wsi/x11: Hook up KHR_incremental_present
authorAdam Jackson <ajax@redhat.com>
Thu, 28 Apr 2022 16:04:42 +0000 (12:04 -0400)
committerMarge Bot <emma+marge@anholt.net>
Wed, 4 May 2022 19:31:53 +0000 (19:31 +0000)
We create one XFIXES region per swapchain image. If the QueuePresent
comes in with a list of rectangles, we push them into the region and
pass it to xcb_present_pixmap.

The extension is technically just a hint. We still fall back to the
unhinted "update the whole image" path if the update region has more
than an arbitrary number of rects, or if we're stuck using plain
PutImage instead of ShmPutImage.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16218>

src/vulkan/meson.build
src/vulkan/wsi/wsi_common_x11.c

index f4e3620..e7fe86e 100644 (file)
@@ -41,6 +41,7 @@ if with_platform_x11
     dep_x11_xcb,
     dep_xcb_dri3,
     dep_xcb_present,
+    dep_xcb_xfixes,
     dep_xcb_sync,
     dep_xcb_xrandr,
     dep_xcb_shm,
index 3bcf152..bdd869c 100644 (file)
@@ -65,6 +65,7 @@ struct wsi_x11_connection {
    bool is_proprietary_x11;
    bool is_xwayland;
    bool has_mit_shm;
+   bool has_xfixes;
 };
 
 struct wsi_x11 {
@@ -188,8 +189,12 @@ static struct wsi_x11_connection *
 wsi_x11_connection_create(struct wsi_device *wsi_dev,
                           xcb_connection_t *conn)
 {
-   xcb_query_extension_cookie_t dri3_cookie, pres_cookie, randr_cookie, amd_cookie, nv_cookie, shm_cookie, sync_cookie;
-   xcb_query_extension_reply_t *dri3_reply, *pres_reply, *randr_reply, *amd_reply, *nv_reply, *shm_reply = NULL;
+   xcb_query_extension_cookie_t dri3_cookie, pres_cookie, randr_cookie,
+                                amd_cookie, nv_cookie, shm_cookie, sync_cookie,
+                                xfixes_cookie;
+   xcb_query_extension_reply_t *dri3_reply, *pres_reply, *randr_reply,
+                               *amd_reply, *nv_reply, *shm_reply = NULL,
+                               *xfixes_reply;
    bool has_dri3_v1_2 = false;
    bool has_present_v1_2 = false;
 
@@ -203,6 +208,7 @@ wsi_x11_connection_create(struct wsi_device *wsi_dev,
    dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
    pres_cookie = xcb_query_extension(conn, 7, "Present");
    randr_cookie = xcb_query_extension(conn, 5, "RANDR");
+   xfixes_cookie = xcb_query_extension(conn, 6, "XFIXES");
 
    if (wsi_dev->sw)
       shm_cookie = xcb_query_extension(conn, 7, "MIT-SHM");
@@ -225,11 +231,13 @@ wsi_x11_connection_create(struct wsi_device *wsi_dev,
    randr_reply = xcb_query_extension_reply(conn, randr_cookie, NULL);
    amd_reply = xcb_query_extension_reply(conn, amd_cookie, NULL);
    nv_reply = xcb_query_extension_reply(conn, nv_cookie, NULL);
+   xfixes_reply = xcb_query_extension_reply(conn, xfixes_cookie, NULL);
    if (wsi_dev->sw)
       shm_reply = xcb_query_extension_reply(conn, shm_cookie, NULL);
-   if (!dri3_reply || !pres_reply) {
+   if (!dri3_reply || !pres_reply || !xfixes_reply) {
       free(dri3_reply);
       free(pres_reply);
+      free(xfixes_reply);
       free(randr_reply);
       free(amd_reply);
       free(nv_reply);
@@ -267,6 +275,17 @@ wsi_x11_connection_create(struct wsi_device *wsi_dev,
    }
 #endif
 
+   wsi_conn->has_xfixes = xfixes_reply->present != 0;
+   if (wsi_conn->has_xfixes) {
+      xcb_xfixes_query_version_cookie_t ver_cookie;
+      xcb_xfixes_query_version_reply_t *ver_reply;
+
+      ver_cookie = xcb_xfixes_query_version(conn, 6, 0);
+      ver_reply = xcb_xfixes_query_version_reply(conn, ver_cookie, NULL);
+      wsi_conn->has_xfixes = (ver_reply->major_version >= 2);
+      free(ver_reply);
+   }
+
    if (randr_reply && randr_reply->present != 0)
       wsi_conn->is_xwayland = wsi_x11_detect_xwayland(conn);
    else
@@ -888,6 +907,8 @@ wsi_CreateXlibSurfaceKHR(VkInstance _instance,
 struct x11_image {
    struct wsi_image                          base;
    xcb_pixmap_t                              pixmap;
+   xcb_xfixes_region_t                       update_region; /* long lived XID */
+   xcb_xfixes_region_t                       update_area;   /* the above or None */
    bool                                      busy;
    bool                                      present_queued;
    struct xshmfence *                        shm_fence;
@@ -1241,7 +1262,7 @@ x11_present_to_x11_dri3(struct x11_swapchain *chain, uint32_t image_index,
                          image->pixmap,
                          image->serial,
                          0,                                    /* valid */
-                         0,                                    /* update */
+                         image->update_area,                   /* update */
                          0,                                    /* x_off */
                          0,                                    /* y_off */
                          XCB_NONE,                             /* target_crtc */
@@ -1331,6 +1352,8 @@ x11_acquire_next_image(struct wsi_swapchain *anv_chain,
    }
 }
 
+#define MAX_DAMAGE_RECTS 64
+
 /**
  * Queue a new presentation of an image that was previously acquired by the
  * consumer.
@@ -1344,11 +1367,29 @@ x11_queue_present(struct wsi_swapchain *anv_chain,
                   const VkPresentRegionKHR *damage)
 {
    struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+   xcb_xfixes_region_t update_area = 0;
 
    /* If the swapchain is in an error state, don't go any further. */
    if (chain->status < 0)
       return chain->status;
 
+   if (damage && damage->pRectangles && damage->rectangleCount > 0 &&
+      damage->rectangleCount <= MAX_DAMAGE_RECTS) {
+      xcb_rectangle_t rects[MAX_DAMAGE_RECTS];
+
+      update_area = chain->images[image_index].update_region;
+      for (unsigned i = 0; i < damage->rectangleCount; i++) {
+         const VkRectLayerKHR *rect = &damage->pRectangles[i];
+         assert(rect->layer == 0);
+         rects[i].x = rect->offset.x;
+         rects[i].y = rect->offset.y;
+         rects[i].width = rect->extent.width;
+         rects[i].height = rect->extent.height;
+      }
+      xcb_xfixes_set_region(chain->conn, update_area, damage->rectangleCount, rects);
+   }
+   chain->images[image_index].update_area = update_area;
+
    chain->images[image_index].busy = true;
    if (chain->has_present_queue) {
       wsi_queue_push(&chain->present_queue, image_index);
@@ -1546,6 +1587,9 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
    if (result != VK_SUCCESS)
       return result;
 
+   image->update_region = xcb_generate_id(chain->conn);
+   xcb_xfixes_create_region(chain->conn, image->update_region, 0, NULL);
+
    if (chain->base.wsi->sw) {
       if (!chain->has_mit_shm) {
          image->busy = false;
@@ -1665,6 +1709,9 @@ x11_image_finish(struct x11_swapchain *chain,
 
       cookie = xcb_free_pixmap(chain->conn, image->pixmap);
       xcb_discard_reply(chain->conn, cookie.sequence);
+
+      cookie = xcb_xfixes_destroy_region(chain->conn, image->update_region);
+      xcb_discard_reply(chain->conn, cookie.sequence);
    }
 
    wsi_destroy_image(&chain->base, &image->base);