summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Orzechowski <[email protected]>2022-08-26 19:07:52 -0400
committerAlexander Orzechowski <[email protected]>2022-08-26 19:07:52 -0400
commitd34a07994fac07c6c98c6c6c351743ab2655a90e (patch)
tree80b5a8f0d26ef259f9e61eca81aace8ab5a56adb
parent50cec289e83c36924ecc1f3b10f5af68a5613405 (diff)
wlr_scene: Only consider visible parts of the node when culling background
Originally, I thought that we could safely subtract opaque regions from the background even if the black rect optimization was kicking in. This is wrong because a scene node that isn't fully occluded will still appear in the render list even if its partially under a black rect. We need to make sure that while culling the background, we only consider opaque regions that are also visible. This will fix the black rect optimization with the background.
-rw-r--r--wlr_scene.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/wlr_scene.c b/wlr_scene.c
index 9516971..5e5f800 100644
--- a/wlr_scene.c
+++ b/wlr_scene.c
@@ -221,8 +221,8 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
return _scene_nodes_in_box(node, box, iterator, user_data, x, y);
}
-static void scene_node_cull_hidden(struct wlr_scene_node *node, int x, int y,
- pixman_region32_t *visible) {
+static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
+ pixman_region32_t *opaque) {
if (node->type == WLR_SCENE_NODE_RECT) {
struct wlr_scene_rect *scene_rect = scene_rect_from_node(node);
if (scene_rect->color[3] != 1) {
@@ -236,19 +236,16 @@ static void scene_node_cull_hidden(struct wlr_scene_node *node, int x, int y,
}
if (!buffer_is_opaque(scene_buffer->buffer)) {
- pixman_region32_translate(visible, -x, -y);
- pixman_region32_subtract(visible, visible, &scene_buffer->opaque_region);
- pixman_region32_translate(visible, x, y);
+ pixman_region32_copy(opaque, &scene_buffer->opaque_region);
+ pixman_region32_translate(opaque, x, y);
return;
}
}
int width, height;
scene_node_get_size(node, &width, &height);
- pixman_region32_t opaque;
- pixman_region32_init_rect(&opaque, x, y, width, height);
- pixman_region32_subtract(visible, visible, &opaque);
- pixman_region32_fini(&opaque);
+ pixman_region32_fini(opaque);
+ pixman_region32_init_rect(opaque, x, y, width, height);
}
struct scene_update_data {
@@ -370,7 +367,11 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node,
lx, ly, box.width, box.height);
if (data->calculate_visibility) {
- scene_node_cull_hidden(node, lx, ly, data->visible);
+ pixman_region32_t opaque;
+ pixman_region32_init(&opaque);
+ scene_node_opaque_region(node, lx, ly, &opaque);
+ pixman_region32_subtract(data->visible, data->visible, &opaque);
+ pixman_region32_fini(&opaque);
}
update_node_update_outputs(node, data->outputs, NULL);
@@ -1507,7 +1508,20 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
struct wlr_scene_node *node = list_data[i];
int x, y;
wlr_scene_node_coords(node, &x, &y);
- scene_node_cull_hidden(node, x, y, &background);
+
+ // We must only cull opaque regions that are visible by the node.
+ // The node's visibility will have the knowledge of a black rect
+ // that may have been omitted from the render list via the black
+ // rect optimization. In order to ensure we don't cull background
+ // rendering in that black rect region, consider the node's visibility.
+ pixman_region32_t opaque;
+ pixman_region32_init(&opaque);
+ scene_node_opaque_region(node, x, y, &opaque);
+ pixman_region32_intersect(&opaque, &opaque, &node->visible);
+
+ wlr_region_scale(&opaque, &opaque, scene_output->output->scale);
+ pixman_region32_subtract(&background, &background, &opaque);
+ pixman_region32_fini(&opaque);
}
}