aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Orzechowski <orzechowski.alexander@gmail.com>2022-06-25 18:33:40 -0400
committerAlexander Orzechowski <orzechowski.alexander@gmail.com>2022-08-14 02:38:51 -0400
commitce57485e6a37e8b7d1b1cccc02d8d66ad60fe2d9 (patch)
tree440b8aa0b3d0847c4b04507ae3ff1afe111871e9
parent342830e99c3e88c6189a8533051485d9b682a814 (diff)
wlr_scene: Calculate output intersections based on node visibility
This has a few benefits one of them crucial for proper operation: - The primary output will be based on the largest area that is actually visible to the user. Presentation and frame done events are based on this state. This is important to do since we cull frame done events. If we happen to be in a situation where a surface sits mostly on output A and some on output B but is completely obstructed by for instance a fullscreen surface on output A we will erroneously send frame_done events based on output A. If we base things as they are in reality (visibility) the primary output will instead be output B and things will work properly. - The primary output will be NULL if the surface is completely hidden. Due to quirks with wayland, on a surface commit, frame done events are required to be sent. Therefore, a new frame will be submitted for rendering on the primary output. We can improve adaptive sync on completely hidden but enabled surfaces if we null out the primary output in this state. - The client will be more likely to choose better metadata to use for rendering to an output's optimal rendering characteristics.
-rw-r--r--types/scene/wlr_scene.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 36a12a0b..627d7e72 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -247,6 +247,18 @@ struct scene_update_data {
struct wl_list *outputs;
};
+static uint32_t region_area(pixman_region32_t *region) {
+ uint32_t area = 0;
+
+ int nrects;
+ pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects);
+ for (int i = 0; i < nrects; ++i) {
+ area += (rects[i].x2 - rects[i].x1) * (rects[i].y2 - rects[i].y1);
+ }
+
+ return area;
+}
+
static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) {
if (!pixman_region32_not_empty(damage)) {
return;
@@ -276,10 +288,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
- struct wlr_box buffer_box;
- wlr_scene_node_coords(node, &buffer_box.x, &buffer_box.y);
- scene_node_get_size(node, &buffer_box.width, &buffer_box.height);
-
int largest_overlap = 0;
scene_buffer->primary_output = NULL;
@@ -304,11 +312,13 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
wlr_output_effective_resolution(scene_output->output,
&output_box.width, &output_box.height);
- struct wlr_box intersection;
- bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box);
+ pixman_region32_t intersection;
+ pixman_region32_init(&intersection);
+ pixman_region32_intersect_rect(&intersection, &node->visible,
+ output_box.x, output_box.y, output_box.width, output_box.height);
- if (intersects) {
- int overlap = intersection.width * intersection.height;
+ if (pixman_region32_not_empty(&intersection)) {
+ int overlap = region_area(&intersection);
if (overlap > largest_overlap) {
largest_overlap = overlap;
scene_buffer->primary_output = scene_output;
@@ -316,6 +326,8 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
active_outputs |= 1ull << scene_output->index;
}
+
+ pixman_region32_fini(&intersection);
}
uint64_t old_active = scene_buffer->active_outputs;