vmwgfx: Make present readbacks not cross scanout bounding box boundaries
authorThomas Hellstrom <thellstrom@vmware.com>
Mon, 20 Jun 2011 12:13:46 +0000 (14:13 +0200)
committerThomas Hellstrom <thellstrom@vmware.com>
Wed, 22 Jun 2011 20:34:50 +0000 (22:34 +0200)
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
vmwgfx/vmwgfx_saa.c

index 55b5fea..f095b9f 100644 (file)
@@ -245,11 +245,24 @@ vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
     RegionRec intersection;
+    RegionRec screen_intersection;
+    struct _WsbmListHead *list;
 
     if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) ||
        !vpix->dirty_present)
        return TRUE;
 
+    /*
+     * Flush dirty stuff to screen.
+     */
+
+
+    vsaa->present_flush(vsaa->pScreen);
+
+    /*
+     * Intersect dirty region with region to be read back, if any.
+     */
+
     REGION_NULL(vsaa->pScreen, &intersection);
     REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw);
     REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection,
@@ -261,24 +274,44 @@ vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
     if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection))
        goto out;
 
-    vsaa->present_flush(vsaa->pScreen);
+    /*
+     * Make really sure there is a GMR to read back to.
+     */
+
     if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
        goto out_err;
 
-
     /*
-     * FIXME: Cliprects may not overlap screen boundaries.
+     * Readback regions are not allowed to cross screen boundaries, so
+     * loop over all scanouts and make sure all readback calls are completely
+     * contained within a scanout bounding box.
      */
 
-    if (vmwgfx_present_readback(vsaa->drm_fd, &intersection) != 0)
-       goto out_err;
+    REGION_NULL(vsaa->pScreen, &screen_intersection);
+    WSBMLISTFOREACH(list, &vpix->scanout_list) {
+       struct vmwgfx_screen_box *box =
+           WSBMLISTENTRY(list, struct vmwgfx_screen_box, scanout_head);
+
+       REGION_RESET(vsaa->pScreen, &screen_intersection, &box->box);
+       REGION_INTERSECT(vsaa->pScreen, &screen_intersection,
+                        &screen_intersection, &intersection);
+
+       if (vmwgfx_present_readback(vsaa->drm_fd, &intersection) != 0)
+           goto out_readback_err;
+
+       REGION_SUBTRACT(vsaa->pScreen, &intersection, &intersection,
+                       &screen_intersection);
+       REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw,
+                       &spix->dirty_hw, &screen_intersection);
+    }
 
-    REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw,
-                   &spix->dirty_hw, &intersection);
+    REGION_UNINIT(vsaa->pScreen, &screen_intersection);
   out:
     REGION_UNINIT(vsaa->pScreen, &intersection);
     return TRUE;
 
+  out_readback_err:
+    REGION_UNINIT(vsaa->pScreen, &screen_intersection);
   out_err:
     REGION_UNINIT(vsaa->pScreen, &intersection);
     return FALSE;