commit 87e5e78

Michael Forney  ·  2013-12-07 04:28:02 +0000 UTC
parent 75b42b7
compositor: Better support for multiple outputs

Now, multiple outputs displaying the same region both get painted
correctly because each output keeps track of it's damage since it's last
refresh.
3 files changed,  +48, -27
+46, -26
  1@@ -85,43 +85,49 @@ static void calculate_damage(struct swc_compositor * compositor)
  2 }
  3 
  4 static void repaint_output(struct swc_compositor * compositor,
  5-                           struct swc_output * output)
  6+                           struct swc_output * output,
  7+                           pixman_region32_t * damage)
  8 {
  9-    pixman_region32_t damage, previous_damage, base_damage;
 10+    pixman_region32_t base_damage;
 11 
 12-    pixman_region32_init(&damage);
 13-    pixman_region32_init(&previous_damage);
 14     pixman_region32_init(&base_damage);
 15-
 16-    pixman_region32_intersect_rect
 17-        (&damage, &compositor->damage, output->geometry.x, output->geometry.y,
 18-         output->geometry.width, output->geometry.height);
 19-
 20-    /* We must save the damage from the previous frame because the back buffer
 21-     * is also damaged in this region. */
 22-    pixman_region32_copy(&previous_damage, &output->previous_damage);
 23-    pixman_region32_copy(&output->previous_damage, &damage);
 24-
 25-    /* The total damage is composed of the damage from the new frame, and the
 26-     * damage from the last frame. */
 27-    pixman_region32_union(&damage, &damage, &previous_damage);
 28-
 29-    pixman_region32_subtract(&base_damage, &damage, &compositor->opaque);
 30+    pixman_region32_subtract(&base_damage, damage, &compositor->opaque);
 31 
 32     swc_renderer_set_target(&compositor->renderer, &output->framebuffer_plane);
 33-    swc_renderer_repaint(&compositor->renderer, &damage, &base_damage,
 34+    swc_renderer_repaint(&compositor->renderer, damage, &base_damage,
 35                          &compositor->surfaces);
 36 
 37-    pixman_region32_subtract(&compositor->damage, &compositor->damage, &damage);
 38-
 39-    pixman_region32_fini(&damage);
 40-    pixman_region32_fini(&previous_damage);
 41     pixman_region32_fini(&base_damage);
 42 
 43     if (!swc_plane_flip(&output->framebuffer_plane))
 44         fprintf(stderr, "Plane flip failed\n");
 45 }
 46 
 47+static void update_output_damage(struct swc_output * output,
 48+                                 pixman_region32_t * damage)
 49+{
 50+    pixman_region32_union
 51+        (&output->current_damage, &output->current_damage, damage);
 52+    pixman_region32_intersect_rect
 53+        (&output->current_damage, &output->current_damage,
 54+         output->geometry.x, output->geometry.y,
 55+         output->geometry.width, output->geometry.height);
 56+}
 57+
 58+static void flush_output_damage(struct swc_output * output,
 59+                                pixman_region32_t * damage)
 60+{
 61+    /* The total damage is composed of the damage from the new frame, and the
 62+     * damage from the last frame. */
 63+    pixman_region32_union(damage,
 64+                          &output->current_damage, &output->previous_damage);
 65+
 66+    /* We must save the damage from the previous frame because the back buffer
 67+     * is also damaged in this region. */
 68+    pixman_region32_copy(&output->previous_damage, &output->current_damage);
 69+    pixman_region32_clear(&output->current_damage);
 70+}
 71+
 72 static void perform_update(void * data)
 73 {
 74     struct swc_compositor * compositor = data;
 75@@ -131,15 +137,29 @@ static void perform_update(void * data)
 76 
 77     if (updates)
 78     {
 79+        pixman_region32_t damage;
 80+
 81         printf("performing update\n");
 82         calculate_damage(compositor);
 83+        pixman_region32_init(&damage);
 84 
 85         wl_list_for_each(output, &compositor->outputs, link)
 86         {
 87-            if (updates & SWC_OUTPUT_MASK(output))
 88-                repaint_output(compositor, output);
 89+            if (compositor->scheduled_updates & SWC_OUTPUT_MASK(output))
 90+            {
 91+                update_output_damage(output, &compositor->damage);
 92+
 93+                if (!(compositor->pending_flips & SWC_OUTPUT_MASK(output)))
 94+                {
 95+                    flush_output_damage(output, &damage);
 96+                    repaint_output(compositor, output, &damage);
 97+                }
 98+            }
 99         }
100 
101+        pixman_region32_fini(&damage);
102+        /* XXX: Should assert that all damage was covered by some output */
103+        pixman_region32_clear(&compositor->damage);
104         compositor->pending_flips |= updates;
105         compositor->scheduled_updates &= ~updates;
106     }
+1, -0
1@@ -64,6 +64,7 @@ bool swc_output_initialize(struct swc_output * output, struct swc_drm * drm,
2 
3     wl_list_init(&output->resources);
4     wl_array_init(&output->modes);
5+    pixman_region32_init(&output->current_damage);
6     pixman_region32_init(&output->previous_damage);
7 
8     output->crtc_id = crtc_id;
+1, -1
1@@ -29,7 +29,7 @@ struct swc_output
2     struct swc_plane framebuffer_plane;
3     struct swc_plane cursor_plane;
4 
5-    pixman_region32_t previous_damage;
6+    pixman_region32_t current_damage, previous_damage;
7 
8     /* The CRTC and connector we are using to drive this output */
9     uint32_t crtc_id;