mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
Merge branch 'sunli1/wlroots-output_layers_v3' into 'master'
wlr_scene: Implement Output Layers See merge request wlroots/wlroots!4348
This commit is contained in:
commit
51e76f9000
6 changed files with 581 additions and 66 deletions
|
|
@ -15,4 +15,15 @@ void array_remove_at(struct wl_array *arr, size_t offset, size_t size);
|
||||||
*/
|
*/
|
||||||
bool array_realloc(struct wl_array *arr, size_t size);
|
bool array_realloc(struct wl_array *arr, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the first valid element in a reversed array.
|
||||||
|
*/
|
||||||
|
void *array_reversed_start(struct wl_array *arr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new element to the array inserting them starting from a higher
|
||||||
|
* memory address effectively inserting them in reverse order.
|
||||||
|
*/
|
||||||
|
void *array_reversed_add(struct wl_array *arr, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,20 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
/* For triple buffering, a history of two frames is required. */
|
|
||||||
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
|
|
||||||
|
|
||||||
struct wlr_box;
|
struct wlr_box;
|
||||||
|
struct wlr_buffer;
|
||||||
|
|
||||||
|
struct wlr_damage_ring_entry {
|
||||||
|
pixman_region32_t damage;
|
||||||
|
struct wlr_buffer *buffer;
|
||||||
|
|
||||||
|
struct wl_listener buffer_destroy;
|
||||||
|
|
||||||
|
struct wlr_damage_ring *ring;
|
||||||
|
struct wl_list link; // struct wlr_damage_ring.previous
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_damage_ring {
|
struct wlr_damage_ring {
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
|
|
@ -27,8 +36,7 @@ struct wlr_damage_ring {
|
||||||
|
|
||||||
// private state
|
// private state
|
||||||
|
|
||||||
pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
|
struct wl_list previous; // struct wlr_damage_ring_entry.link
|
||||||
size_t previous_idx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
|
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
|
||||||
|
|
@ -81,4 +89,14 @@ void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
|
||||||
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
||||||
int buffer_age, pixman_region32_t *damage);
|
int buffer_age, pixman_region32_t *damage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the since accumulated damage for this buffer. These buffers should
|
||||||
|
* typically come from a wlr_swapchain. In the context of rendering, the
|
||||||
|
* damage is the region that needs to be redrawn.
|
||||||
|
*
|
||||||
|
* The damage ring is automatically rotated during invocation.
|
||||||
|
*/
|
||||||
|
void wlr_damage_ring_damage_for_buffer(struct wlr_damage_ring *ring,
|
||||||
|
struct wlr_buffer *buffer, pixman_region32_t *damage);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ struct wlr_scene {
|
||||||
enum wlr_scene_debug_damage_option debug_damage_option;
|
enum wlr_scene_debug_damage_option debug_damage_option;
|
||||||
bool direct_scanout;
|
bool direct_scanout;
|
||||||
bool calculate_visibility;
|
bool calculate_visibility;
|
||||||
|
|
||||||
|
struct wl_array render_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A scene-graph node displaying a single surface. */
|
/** A scene-graph node displaying a single surface. */
|
||||||
|
|
@ -204,6 +206,8 @@ struct wlr_scene_output {
|
||||||
|
|
||||||
// private state
|
// private state
|
||||||
|
|
||||||
|
pixman_region32_t pending_commit_damage;
|
||||||
|
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
bool prev_scanout;
|
bool prev_scanout;
|
||||||
|
|
||||||
|
|
@ -213,7 +217,7 @@ struct wlr_scene_output {
|
||||||
|
|
||||||
struct wl_list damage_highlight_regions;
|
struct wl_list damage_highlight_regions;
|
||||||
|
|
||||||
struct wl_array render_list;
|
struct wl_array output_layers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_scene_timer {
|
struct wlr_scene_timer {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <wlr/types/wlr_damage_ring.h>
|
#include <wlr/types/wlr_damage_ring.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||||
|
#include <wlr/types/wlr_output_layer.h>
|
||||||
#include <wlr/types/wlr_presentation_time.h>
|
#include <wlr/types/wlr_presentation_time.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
@ -125,6 +126,8 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
||||||
|
|
||||||
wl_list_remove(&scene->presentation_destroy.link);
|
wl_list_remove(&scene->presentation_destroy.link);
|
||||||
wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
|
wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
|
||||||
|
|
||||||
|
wl_array_release(&scene->render_list);
|
||||||
} else {
|
} else {
|
||||||
assert(node->parent);
|
assert(node->parent);
|
||||||
}
|
}
|
||||||
|
|
@ -1104,8 +1107,10 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
|
||||||
|
|
||||||
struct render_list_entry {
|
struct render_list_entry {
|
||||||
struct wlr_scene_node *node;
|
struct wlr_scene_node *node;
|
||||||
|
struct wlr_output_layer_state *state;
|
||||||
bool sent_dmabuf_feedback;
|
bool sent_dmabuf_feedback;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
bool visible;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void scene_entry_render(struct render_list_entry *entry, const struct render_data *data) {
|
static void scene_entry_render(struct render_list_entry *entry, const struct render_data *data) {
|
||||||
|
|
@ -1273,6 +1278,14 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data)
|
||||||
WLR_OUTPUT_STATE_ENABLED)) {
|
WLR_OUTPUT_STATE_ENABLED)) {
|
||||||
scene_output_update_geometry(scene_output);
|
scene_output_update_geometry(scene_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the output has been committed with a certain damage, we know that region
|
||||||
|
// will be acknowledged by the backend so we don't need to keep track of it
|
||||||
|
// anymore
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||||
|
pixman_region32_subtract(&scene_output->pending_commit_damage,
|
||||||
|
&scene_output->pending_commit_damage, &state->damage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scene_output_handle_damage(struct wl_listener *listener, void *data) {
|
static void scene_output_handle_damage(struct wl_listener *listener, void *data) {
|
||||||
|
|
@ -1302,6 +1315,7 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
|
||||||
wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl);
|
wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl);
|
||||||
|
|
||||||
wlr_damage_ring_init(&scene_output->damage_ring);
|
wlr_damage_ring_init(&scene_output->damage_ring);
|
||||||
|
pixman_region32_init(&scene_output->pending_commit_damage);
|
||||||
wl_list_init(&scene_output->damage_highlight_regions);
|
wl_list_init(&scene_output->damage_highlight_regions);
|
||||||
|
|
||||||
int prev_output_index = -1;
|
int prev_output_index = -1;
|
||||||
|
|
@ -1360,12 +1374,14 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
||||||
|
|
||||||
wlr_addon_finish(&scene_output->addon);
|
wlr_addon_finish(&scene_output->addon);
|
||||||
wlr_damage_ring_finish(&scene_output->damage_ring);
|
wlr_damage_ring_finish(&scene_output->damage_ring);
|
||||||
|
pixman_region32_fini(&scene_output->pending_commit_damage);
|
||||||
wl_list_remove(&scene_output->link);
|
wl_list_remove(&scene_output->link);
|
||||||
wl_list_remove(&scene_output->output_commit.link);
|
wl_list_remove(&scene_output->output_commit.link);
|
||||||
wl_list_remove(&scene_output->output_damage.link);
|
wl_list_remove(&scene_output->output_damage.link);
|
||||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||||
|
|
||||||
wl_array_release(&scene_output->render_list);
|
wl_array_release(&scene_output->output_layers);
|
||||||
|
|
||||||
free(scene_output);
|
free(scene_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1415,57 +1431,84 @@ struct render_list_constructor_data {
|
||||||
bool calculate_visibility;
|
bool calculate_visibility;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool construct_render_list_iterator(struct wlr_scene_node *node,
|
static bool scene_construct_render_list(struct wlr_scene_node *node,
|
||||||
int lx, int ly, void *_data) {
|
struct wl_array *render_list, struct wlr_box *box, bool calculate_visibility,
|
||||||
struct render_list_constructor_data *data = _data;
|
bool enabled, int lx, int ly) {
|
||||||
|
|
||||||
if (scene_node_invisible(node)) {
|
enabled = enabled && node->enabled;
|
||||||
|
|
||||||
|
if (node->type == WLR_SCENE_NODE_TREE) {
|
||||||
|
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||||
|
struct wlr_scene_node *child;
|
||||||
|
wl_list_for_each_reverse(child, &scene_tree->children, link) {
|
||||||
|
if (!scene_construct_render_list(child, render_list, box, calculate_visibility, enabled,
|
||||||
|
lx + child->x, ly + child->y)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct render_list_entry *entry = wl_array_add(render_list, sizeof(*entry));
|
||||||
|
if (!entry) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(entry, 0, sizeof(*entry));
|
||||||
|
entry->node = node;
|
||||||
|
entry->x = lx;
|
||||||
|
entry->y = ly;
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||||
|
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||||
|
|
||||||
|
if (!wlr_box_intersection(&node_box, &node_box, box) || scene_node_invisible(node)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// while rendering, the background should always be black.
|
// while rendering, the background should always be black.
|
||||||
// If we see a black rect, we can ignore rendering everything under the rect
|
// If we see a black rect, we can ignore rendering everything under the rect
|
||||||
// and even the rect itself.
|
// and even the rect itself.
|
||||||
if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) {
|
if (node->type == WLR_SCENE_NODE_RECT && calculate_visibility) {
|
||||||
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
||||||
float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f };
|
float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f };
|
||||||
|
|
||||||
if (memcmp(rect->color, black, sizeof(float) * 4) == 0) {
|
if (memcmp(rect->color, black, sizeof(float) * 4) == 0) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_t intersection;
|
pixman_region32_t intersection;
|
||||||
pixman_region32_init(&intersection);
|
pixman_region32_init(&intersection);
|
||||||
pixman_region32_intersect_rect(&intersection, &node->visible,
|
pixman_region32_intersect_rect(&intersection, &node->visible,
|
||||||
data->box.x, data->box.y,
|
box->x, box->y, box->width, box->height);
|
||||||
data->box.width, data->box.height);
|
|
||||||
if (!pixman_region32_not_empty(&intersection)) {
|
if (!pixman_region32_not_empty(&intersection)) {
|
||||||
pixman_region32_fini(&intersection);
|
pixman_region32_fini(&intersection);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini(&intersection);
|
pixman_region32_fini(&intersection);
|
||||||
|
|
||||||
struct render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry));
|
entry->visible = true;
|
||||||
if (!entry) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*entry = (struct render_list_entry){
|
|
||||||
.node = node,
|
|
||||||
.x = lx,
|
|
||||||
.y = ly,
|
|
||||||
};
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_state_apply_damage(const struct render_data *data,
|
static void output_state_apply_damage(const struct render_data *data,
|
||||||
struct wlr_output_state *state) {
|
struct wlr_output_state *state) {
|
||||||
|
struct wlr_scene_output *output = data->output;
|
||||||
|
pixman_region32_union(&output->pending_commit_damage,
|
||||||
|
&output->pending_commit_damage, &output->damage_ring.current);
|
||||||
|
pixman_region32_intersect_rect(&output->pending_commit_damage,
|
||||||
|
&output->pending_commit_damage, 0, 0, data->trans_width, data->trans_height);
|
||||||
|
|
||||||
pixman_region32_t frame_damage;
|
pixman_region32_t frame_damage;
|
||||||
pixman_region32_init(&frame_damage);
|
pixman_region32_init(&frame_damage);
|
||||||
pixman_region32_copy(&frame_damage, &data->output->damage_ring.current);
|
pixman_region32_copy(&frame_damage, &output->pending_commit_damage);
|
||||||
transform_output_damage(&frame_damage, data);
|
transform_output_damage(&frame_damage, data);
|
||||||
wlr_output_state_set_damage(state, &frame_damage);
|
wlr_output_state_set_damage(state, &frame_damage);
|
||||||
pixman_region32_fini(&frame_damage);
|
pixman_region32_fini(&frame_damage);
|
||||||
|
|
@ -1595,10 +1638,263 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool scene_buffer_can_be_output_layer(struct wlr_scene_buffer *buffer,
|
||||||
|
struct wlr_scene_output *scene_output) {
|
||||||
|
struct wlr_fbox default_box = {0};
|
||||||
|
if (buffer->transform & WL_OUTPUT_TRANSFORM_90) {
|
||||||
|
default_box.width = buffer->buffer->height;
|
||||||
|
default_box.height = buffer->buffer->width;
|
||||||
|
} else {
|
||||||
|
default_box.width = buffer->buffer->width;
|
||||||
|
default_box.height = buffer->buffer->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_fbox_empty(&buffer->src_box) &&
|
||||||
|
!wlr_fbox_equal(&buffer->src_box, &default_box)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->transform != scene_output->output->transform) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_scene_node_output_layer {
|
||||||
|
struct wlr_addon addon;
|
||||||
|
struct wlr_output_layer *layer;
|
||||||
|
struct wlr_scene_buffer *buffer;
|
||||||
|
struct wlr_scene_output *output;
|
||||||
|
struct render_list_entry *current_render_entry;
|
||||||
|
|
||||||
|
struct wl_listener layer_feedback;
|
||||||
|
struct wl_listener output_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void node_output_layer_destroy(struct wlr_scene_node_output_layer *layer) {
|
||||||
|
wlr_output_layer_destroy(layer->layer);
|
||||||
|
wlr_addon_finish(&layer->addon);
|
||||||
|
wl_list_remove(&layer->output_destroy.link);
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_layer_addon_finish(struct wlr_addon *addon) {
|
||||||
|
struct wlr_scene_node_output_layer *layer = wl_container_of(addon, layer, addon);
|
||||||
|
node_output_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_layer_output_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_scene_node_output_layer *layer = wl_container_of(listener, layer, output_destroy);
|
||||||
|
wl_list_remove(&layer->layer_feedback.link);
|
||||||
|
node_output_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_addon_interface node_addon_output_layer = {
|
||||||
|
.name = "wlr_scene_output_layer",
|
||||||
|
.destroy = handle_output_layer_addon_finish,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct wlr_scene_node_output_layer *scene_node_get_output_layer(
|
||||||
|
struct wlr_scene_node *node, struct wlr_scene_output *output) {
|
||||||
|
struct wlr_addon *addon = wlr_addon_find(
|
||||||
|
&node->addons, output, &node_addon_output_layer);
|
||||||
|
if (!addon) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_scene_node_output_layer *layer = wl_container_of(addon, layer, addon);
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void output_handle_layer_feedback(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_scene_node_output_layer *layer =
|
||||||
|
wl_container_of(listener, layer, layer_feedback);
|
||||||
|
struct wlr_output_layer_feedback_event *event = data;
|
||||||
|
struct wlr_linux_dmabuf_feedback_v1_init_options options = {
|
||||||
|
.main_renderer = layer->buffer->primary_output->output->renderer,
|
||||||
|
.output_layer_feedback_event = event,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layer->buffer->primary_output == layer->output) {
|
||||||
|
scene_buffer_send_dmabuf_feedback(scene_node_get_root(&layer->buffer->node),
|
||||||
|
layer->buffer, &options);
|
||||||
|
layer->current_render_entry->sent_dmabuf_feedback = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_scene_node_output_layer *scene_buffer_create_output_layer(
|
||||||
|
struct wlr_scene_buffer *buffer, struct wlr_scene_output *output) {
|
||||||
|
struct wlr_scene_node_output_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (!layer) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->layer = wlr_output_layer_create(output->output);
|
||||||
|
if (!layer->layer) {
|
||||||
|
free(layer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->layer_feedback.notify = output_handle_layer_feedback;
|
||||||
|
wl_signal_add(&layer->layer->events.feedback, &layer->layer_feedback);
|
||||||
|
|
||||||
|
layer->output_destroy.notify = handle_output_layer_output_destroy;
|
||||||
|
wl_signal_add(&output->output->events.destroy, &layer->output_destroy);
|
||||||
|
|
||||||
|
layer->buffer = buffer;
|
||||||
|
layer->output = output;
|
||||||
|
|
||||||
|
wlr_addon_init(&layer->addon, &buffer->node.addons, output, &node_addon_output_layer);
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool scene_submit_output_layers(struct wlr_scene_output *scene_output,
|
||||||
|
struct wlr_output_state *state, struct wl_array *render_list) {
|
||||||
|
// if we render software cursors, that means they will be a part of the
|
||||||
|
// primary plane. If we render output layers, it means we could render
|
||||||
|
// over the cursor. A lock will also be registered if there is screen share.
|
||||||
|
// Screen share cannot use output layers.
|
||||||
|
if (scene_output->output->software_cursor_locks) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scene_output->scene->debug_damage_option ==
|
||||||
|
WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct render_list_entry *list_data = render_list->data;
|
||||||
|
int list_len = render_list->size / sizeof(*list_data);
|
||||||
|
|
||||||
|
scene_output->output_layers.size = 0;
|
||||||
|
if (!array_realloc(&scene_output->output_layers,
|
||||||
|
list_len * sizeof(struct wlr_output_layer_state))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// area of that the base layer must render (such as rects)
|
||||||
|
pixman_region32_t base_layer_area;
|
||||||
|
pixman_region32_init(&base_layer_area);
|
||||||
|
|
||||||
|
for (int i = 0; i < list_len; i++) {
|
||||||
|
struct render_list_entry *entry = &list_data[i];
|
||||||
|
struct wlr_scene_node *node = entry->node;
|
||||||
|
|
||||||
|
if (node->type != WLR_SCENE_NODE_BUFFER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box box = { .x = entry->x, .y = entry->y };
|
||||||
|
scene_node_get_size(node, &box.width, &box.height);
|
||||||
|
|
||||||
|
box.x = floor(box.x * scene_output->output->scale) - scene_output->x;
|
||||||
|
box.y = floor(box.y * scene_output->output->scale) - scene_output->y;
|
||||||
|
box.width = ceil(box.width * scene_output->output->scale);
|
||||||
|
box.height = ceil(box.height * scene_output->output->scale);
|
||||||
|
|
||||||
|
struct wlr_scene_node_output_layer *layer =
|
||||||
|
scene_node_get_output_layer(node, scene_output);
|
||||||
|
|
||||||
|
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
|
||||||
|
|
||||||
|
if (entry->visible && !scene_buffer_can_be_output_layer(buffer, scene_output)) {
|
||||||
|
pixman_region32_union_rect(&base_layer_area, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
|
||||||
|
if (layer) {
|
||||||
|
node_output_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->visible && !layer) {
|
||||||
|
layer = scene_buffer_create_output_layer(buffer, scene_output);
|
||||||
|
if (!layer) {
|
||||||
|
pixman_region32_union_rect(&base_layer_area, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer) {
|
||||||
|
// we preallocted the array length, this should never return NULL.
|
||||||
|
entry->state = array_reversed_add(&scene_output->output_layers, sizeof(*entry->state));
|
||||||
|
|
||||||
|
layer->current_render_entry = entry;
|
||||||
|
*entry->state = (struct wlr_output_layer_state){
|
||||||
|
.layer = layer->layer,
|
||||||
|
.buffer = NULL,
|
||||||
|
.dst_box = box,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_t intersection;
|
||||||
|
pixman_region32_init(&intersection);
|
||||||
|
pixman_region32_intersect_rect(&intersection, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
if (pixman_region32_not_empty(&intersection)) {
|
||||||
|
pixman_region32_union_rect(&base_layer_area, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
|
||||||
|
// only consider nodes that are in the damage
|
||||||
|
pixman_region32_init(&intersection);
|
||||||
|
pixman_region32_intersect_rect(&intersection, &scene_output->damage_ring.current,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
if (!pixman_region32_not_empty(&intersection)) {
|
||||||
|
pixman_region32_union_rect(&base_layer_area, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buffer_is_opaque(buffer->buffer)) {
|
||||||
|
// With transparent nodes, we can't get away with just having the
|
||||||
|
// node partially in the damage or else the user can see through
|
||||||
|
// the node to find an older version of the node software composited
|
||||||
|
// in the base layer.
|
||||||
|
pixman_region32_t node_box;
|
||||||
|
pixman_region32_init_rect(&node_box, box.x, box.y, box.width, box.height);
|
||||||
|
pixman_region32_subtract(&intersection, &node_box, &intersection);
|
||||||
|
pixman_region32_fini(&node_box);
|
||||||
|
if (pixman_region32_not_empty(&intersection)) {
|
||||||
|
pixman_region32_union_rect(&base_layer_area, &base_layer_area,
|
||||||
|
box.x, box.y, box.width, box.height);
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
|
||||||
|
entry->state->buffer = buffer->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini(&base_layer_area);
|
||||||
|
|
||||||
|
wlr_output_state_set_layers(state, array_reversed_start(&scene_output->output_layers),
|
||||||
|
scene_output->output_layers.size / sizeof(struct wlr_output_layer_state));
|
||||||
|
|
||||||
|
if (!wlr_output_test_state(scene_output->output, state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
|
bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
|
||||||
const struct wlr_scene_output_state_options *options) {
|
const struct wlr_scene_output_state_options *options) {
|
||||||
if (!scene_output->output->needs_frame && !pixman_region32_not_empty(
|
if (!scene_output->output->needs_frame && !pixman_region32_not_empty(
|
||||||
&scene_output->damage_ring.current)) {
|
&scene_output->pending_commit_damage)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1614,8 +1910,6 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_damage_ring_rotate(&scene_output->damage_ring);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
wlr_output_state_finish(&state);
|
wlr_output_state_finish(&state);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
@ -1679,22 +1973,64 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
render_data.logical.width = render_data.trans_width / render_data.scale;
|
render_data.logical.width = render_data.trans_width / render_data.scale;
|
||||||
render_data.logical.height = render_data.trans_height / render_data.scale;
|
render_data.logical.height = render_data.trans_height / render_data.scale;
|
||||||
|
|
||||||
struct render_list_constructor_data list_con = {
|
bool calculate_visibility = scene_output->scene->calculate_visibility;
|
||||||
.box = render_data.logical,
|
struct wlr_scene_node *tree_node = &scene_output->scene->tree.node;
|
||||||
.render_list = &scene_output->render_list,
|
struct wl_array *render_list = &scene_output->scene->render_list;
|
||||||
.calculate_visibility = scene_output->scene->calculate_visibility,
|
int x, y;
|
||||||
|
|
||||||
|
render_list->size = 0;
|
||||||
|
wlr_scene_node_coords(tree_node, &x, &y);
|
||||||
|
|
||||||
|
// There is at least one render list entry for the scene tree itself, therefore
|
||||||
|
// construct_render_list should always return true.
|
||||||
|
if (!scene_construct_render_list(tree_node, render_list, &render_data.logical,
|
||||||
|
calculate_visibility, true, x, y)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
array_realloc(render_list, render_list->size);
|
||||||
|
|
||||||
|
scene_submit_output_layers(scene_output, state, render_list);
|
||||||
|
|
||||||
|
// Find number of visible render entries. If only one, try direct scanout.
|
||||||
|
struct render_list_entry *list_data = render_list->data;
|
||||||
|
struct render_list_entry *scanout_entry = NULL;
|
||||||
|
int list_len = render_list->size / sizeof(*list_data);
|
||||||
|
int render_count = 0;
|
||||||
|
pixman_region32_t forward_damage;
|
||||||
|
pixman_region32_init(&forward_damage);
|
||||||
|
|
||||||
|
for (int i = list_len - 1; i >= 0; i--) {
|
||||||
|
struct render_list_entry *entry = &list_data[i];
|
||||||
|
if (!entry->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->state && entry->state->accepted && entry->state->buffer) {
|
||||||
|
// we need to damage the output here for the next frame because since
|
||||||
|
// the we're using output layers here. The contents won't be part
|
||||||
|
// of the primary plane and will therefore have stale contents.
|
||||||
|
pixman_region32_union(&forward_damage, &forward_damage, &entry->node->visible);
|
||||||
|
|
||||||
|
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node);
|
||||||
|
struct wlr_scene_output_sample_event sample_event = {
|
||||||
|
.output = scene_output,
|
||||||
|
.direct_scanout = true,
|
||||||
};
|
};
|
||||||
|
wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
|
||||||
|
|
||||||
list_con.render_list->size = 0;
|
continue;
|
||||||
scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box,
|
}
|
||||||
construct_render_list_iterator, &list_con);
|
|
||||||
array_realloc(list_con.render_list, list_con.render_list->size);
|
|
||||||
|
|
||||||
struct render_list_entry *list_data = list_con.render_list->data;
|
scanout_entry = entry;
|
||||||
int list_len = list_con.render_list->size / sizeof(*list_data);
|
render_count++;
|
||||||
|
}
|
||||||
|
|
||||||
bool scanout = list_len == 1 &&
|
pixman_region32_translate(&forward_damage, -scene_output->x, -scene_output->y);
|
||||||
scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
scale_output_damage(&forward_damage, scene_output->output->scale);
|
||||||
|
pixman_region32_intersect(&forward_damage, &forward_damage, &scene_output->damage_ring.current);
|
||||||
|
|
||||||
|
bool scanout = render_count == 1 &&
|
||||||
|
scene_entry_try_direct_scanout(scanout_entry, state, &render_data);
|
||||||
|
|
||||||
if (scene_output->prev_scanout != scanout) {
|
if (scene_output->prev_scanout != scanout) {
|
||||||
scene_output->prev_scanout = scanout;
|
scene_output->prev_scanout = scanout;
|
||||||
|
|
@ -1713,6 +2049,10 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
timespec_sub(&duration, &end_time, &start_time);
|
timespec_sub(&duration, &end_time, &start_time);
|
||||||
timer->pre_render_duration = timespec_to_nsec(&duration);
|
timer->pre_render_duration = timespec_to_nsec(&duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_damage_ring_add(&scene_output->damage_ring, &forward_damage);
|
||||||
|
pixman_region32_fini(&forward_damage);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1765,9 +2105,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buffer_age;
|
struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain, NULL);
|
||||||
struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain, &buffer_age);
|
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
|
pixman_region32_fini(&forward_damage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1786,13 +2126,16 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
});
|
});
|
||||||
if (render_pass == NULL) {
|
if (render_pass == NULL) {
|
||||||
wlr_buffer_unlock(buffer);
|
wlr_buffer_unlock(buffer);
|
||||||
|
pixman_region32_fini(&forward_damage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_data.render_pass = render_pass;
|
render_data.render_pass = render_pass;
|
||||||
|
|
||||||
|
output_state_apply_damage(&render_data, state);
|
||||||
pixman_region32_init(&render_data.damage);
|
pixman_region32_init(&render_data.damage);
|
||||||
wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring,
|
wlr_damage_ring_damage_for_buffer(&scene_output->damage_ring, buffer,
|
||||||
buffer_age, &render_data.damage);
|
&render_data.damage);
|
||||||
|
|
||||||
pixman_region32_t background;
|
pixman_region32_t background;
|
||||||
pixman_region32_init(&background);
|
pixman_region32_init(&background);
|
||||||
|
|
@ -1805,6 +2148,10 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
for (int i = list_len - 1; i >= 0; i--) {
|
for (int i = list_len - 1; i >= 0; i--) {
|
||||||
struct render_list_entry *entry = &list_data[i];
|
struct render_list_entry *entry = &list_data[i];
|
||||||
|
|
||||||
|
if (!entry->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// We must only cull opaque regions that are visible by the node.
|
// We must only cull opaque regions that are visible by the node.
|
||||||
// The node's visibility will have the knowledge of a black rect
|
// The node's visibility will have the knowledge of a black rect
|
||||||
// that may have been omitted from the render list via the black
|
// that may have been omitted from the render list via the black
|
||||||
|
|
@ -1840,6 +2187,15 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
|
|
||||||
for (int i = list_len - 1; i >= 0; i--) {
|
for (int i = list_len - 1; i >= 0; i--) {
|
||||||
struct render_list_entry *entry = &list_data[i];
|
struct render_list_entry *entry = &list_data[i];
|
||||||
|
|
||||||
|
if (!entry->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->state && entry->state->accepted && entry->state->buffer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
scene_entry_render(entry, &render_data);
|
scene_entry_render(entry, &render_data);
|
||||||
|
|
||||||
if (entry->node->type == WLR_SCENE_NODE_BUFFER) {
|
if (entry->node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
|
|
@ -1877,19 +2233,26 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
pixman_region32_fini(&render_data.damage);
|
pixman_region32_fini(&render_data.damage);
|
||||||
|
|
||||||
if (!wlr_render_pass_submit(render_pass)) {
|
if (!wlr_render_pass_submit(render_pass)) {
|
||||||
|
pixman_region32_fini(&forward_damage);
|
||||||
wlr_buffer_unlock(buffer);
|
wlr_buffer_unlock(buffer);
|
||||||
|
|
||||||
|
// if we failed to render the buffer, it will have undefined contents
|
||||||
|
// Trash the damage ring
|
||||||
|
wlr_damage_ring_add_whole(&scene_output->damage_ring);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_state_set_buffer(state, buffer);
|
wlr_output_state_set_buffer(state, buffer);
|
||||||
wlr_buffer_unlock(buffer);
|
wlr_buffer_unlock(buffer);
|
||||||
output_state_apply_damage(&render_data, state);
|
|
||||||
|
|
||||||
if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
|
if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
|
||||||
!wl_list_empty(&scene_output->damage_highlight_regions)) {
|
!wl_list_empty(&scene_output->damage_highlight_regions)) {
|
||||||
wlr_output_schedule_frame(scene_output->output);
|
wlr_output_schedule_frame(scene_output->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_damage_ring_add(&scene_output->damage_ring, &forward_damage);
|
||||||
|
pixman_region32_fini(&forward_damage);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_damage_ring.h>
|
#include <wlr/types/wlr_damage_ring.h>
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
|
|
@ -14,15 +15,25 @@ void wlr_damage_ring_init(struct wlr_damage_ring *ring) {
|
||||||
};
|
};
|
||||||
|
|
||||||
pixman_region32_init(&ring->current);
|
pixman_region32_init(&ring->current);
|
||||||
for (size_t i = 0; i < WLR_DAMAGE_RING_PREVIOUS_LEN; ++i) {
|
wl_list_init(&ring->previous);
|
||||||
pixman_region32_init(&ring->previous[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void entry_destroy(struct wlr_damage_ring_entry *entry) {
|
||||||
|
if (entry->buffer) {
|
||||||
|
wl_list_remove(&entry->buffer_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&entry->link);
|
||||||
|
pixman_region32_fini(&entry->damage);
|
||||||
|
free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_damage_ring_finish(struct wlr_damage_ring *ring) {
|
void wlr_damage_ring_finish(struct wlr_damage_ring *ring) {
|
||||||
pixman_region32_fini(&ring->current);
|
pixman_region32_fini(&ring->current);
|
||||||
for (size_t i = 0; i < WLR_DAMAGE_RING_PREVIOUS_LEN; ++i) {
|
|
||||||
pixman_region32_fini(&ring->previous[i]);
|
struct wlr_damage_ring_entry *entry, *tmp_entry;
|
||||||
|
wl_list_for_each_safe(entry, tmp_entry, &ring->previous, link) {
|
||||||
|
entry_destroy(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,28 +90,41 @@ void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring) {
|
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring) {
|
||||||
// modular decrement
|
struct wlr_damage_ring_entry *last =
|
||||||
ring->previous_idx = ring->previous_idx +
|
wl_container_of(ring->previous.prev, last, link);
|
||||||
WLR_DAMAGE_RING_PREVIOUS_LEN - 1;
|
wl_list_remove(&last->link);
|
||||||
ring->previous_idx %= WLR_DAMAGE_RING_PREVIOUS_LEN;
|
wl_list_insert(&ring->previous, &last->link);
|
||||||
|
|
||||||
pixman_region32_copy(&ring->previous[ring->previous_idx], &ring->current);
|
pixman_region32_copy(&last->damage, &ring->current);
|
||||||
pixman_region32_clear(&ring->current);
|
pixman_region32_clear(&ring->current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
||||||
int buffer_age, pixman_region32_t *damage) {
|
int buffer_age, pixman_region32_t *damage) {
|
||||||
if (buffer_age <= 0 || buffer_age - 1 > WLR_DAMAGE_RING_PREVIOUS_LEN) {
|
|
||||||
pixman_region32_clear(damage);
|
|
||||||
pixman_region32_union_rect(damage, damage,
|
|
||||||
0, 0, ring->width, ring->height);
|
|
||||||
} else {
|
|
||||||
pixman_region32_copy(damage, &ring->current);
|
pixman_region32_copy(damage, &ring->current);
|
||||||
|
|
||||||
// Accumulate damage from old buffers
|
// Accumulate damage from old buffers
|
||||||
for (int i = 0; i < buffer_age - 1; ++i) {
|
struct wlr_damage_ring_entry *entry;
|
||||||
int j = (ring->previous_idx + i) % WLR_DAMAGE_RING_PREVIOUS_LEN;
|
wl_list_for_each(entry, &ring->previous, link) {
|
||||||
pixman_region32_union(damage, damage, &ring->previous[j]);
|
if (--buffer_age <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_union(damage, damage, &entry->damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if our buffer age is older than anything we are keeping track of, increase
|
||||||
|
// the size
|
||||||
|
if (buffer_age > 0) {
|
||||||
|
pixman_region32_clear(damage);
|
||||||
|
pixman_region32_union_rect(damage, damage,
|
||||||
|
0, 0, ring->width, ring->height);
|
||||||
|
|
||||||
|
struct wlr_damage_ring_entry *entry = calloc(1, sizeof(*entry));
|
||||||
|
if (entry) {
|
||||||
|
pixman_region32_init(&entry->damage);
|
||||||
|
wl_list_insert(ring->previous.prev, &entry->link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the number of rectangles
|
// Check the number of rectangles
|
||||||
|
|
@ -113,4 +137,76 @@ void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
||||||
extents->y2 - extents->y1);
|
extents->y2 - extents->y1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void entry_squash_damage(struct wlr_damage_ring_entry *entry) {
|
||||||
|
pixman_region32_t *prev;
|
||||||
|
if (entry->link.prev == &entry->ring->previous) {
|
||||||
|
// this entry is the first in the list
|
||||||
|
prev = &entry->ring->current;
|
||||||
|
} else {
|
||||||
|
struct wlr_damage_ring_entry *last =
|
||||||
|
wl_container_of(entry->link.prev, last, link);
|
||||||
|
prev = &last->damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_union(prev, prev, &entry->damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_buffer_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_damage_ring_entry *entry =
|
||||||
|
wl_container_of(listener, entry, buffer_destroy);
|
||||||
|
entry_squash_damage(entry);
|
||||||
|
entry_destroy(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_damage_ring_damage_for_buffer(struct wlr_damage_ring *ring,
|
||||||
|
struct wlr_buffer *buffer, pixman_region32_t *damage) {
|
||||||
|
pixman_region32_copy(damage, &ring->current);
|
||||||
|
|
||||||
|
struct wlr_damage_ring_entry *entry;
|
||||||
|
wl_list_for_each(entry, &ring->previous, link) {
|
||||||
|
if (entry->buffer != buffer) {
|
||||||
|
pixman_region32_union(damage, damage, &entry->damage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the number of rectangles
|
||||||
|
int n_rects = pixman_region32_n_rects(damage);
|
||||||
|
if (n_rects > WLR_DAMAGE_RING_MAX_RECTS) {
|
||||||
|
pixman_box32_t *extents = pixman_region32_extents(damage);
|
||||||
|
pixman_region32_union_rect(damage, damage,
|
||||||
|
extents->x1, extents->y1,
|
||||||
|
extents->x2 - extents->x1,
|
||||||
|
extents->y2 - extents->y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate
|
||||||
|
entry_squash_damage(entry);
|
||||||
|
pixman_region32_copy(&entry->damage, &ring->current);
|
||||||
|
pixman_region32_clear(&ring->current);
|
||||||
|
|
||||||
|
wl_list_remove(&entry->link);
|
||||||
|
wl_list_insert(&ring->previous, &entry->link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_clear(damage);
|
||||||
|
pixman_region32_union_rect(damage, damage,
|
||||||
|
0, 0, ring->width, ring->height);
|
||||||
|
|
||||||
|
entry = calloc(1, sizeof(*entry));
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_init(&entry->damage);
|
||||||
|
pixman_region32_copy(&entry->damage, &ring->current);
|
||||||
|
pixman_region32_clear(&ring->current);
|
||||||
|
|
||||||
|
wl_list_insert(&ring->previous, &entry->link);
|
||||||
|
entry->buffer = buffer;
|
||||||
|
entry->ring = ring;
|
||||||
|
|
||||||
|
entry->buffer_destroy.notify = handle_buffer_destroy;
|
||||||
|
wl_signal_add(&buffer->events.destroy, &entry->buffer_destroy);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
util/array.c
23
util/array.c
|
|
@ -38,3 +38,26 @@ bool array_realloc(struct wl_array *arr, size_t size) {
|
||||||
arr->alloc = alloc;
|
arr->alloc = alloc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *array_reversed_start(struct wl_array *arr) {
|
||||||
|
char *data = arr->data;
|
||||||
|
return data + arr->alloc - arr->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *array_reversed_add(struct wl_array *arr, size_t size) {
|
||||||
|
if (arr->size + size > arr->alloc) {
|
||||||
|
size_t new_alloc = arr->alloc * 2;
|
||||||
|
char *new = malloc(new_alloc);
|
||||||
|
if (!new) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(new + (new_alloc - arr->size), array_reversed_start(arr), arr->size);
|
||||||
|
free(arr->data);
|
||||||
|
arr->data = new;
|
||||||
|
arr->alloc = new_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr->size += size;
|
||||||
|
return array_reversed_start(arr);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue