vulkan/wsi: Implement GetPhysicalDevicePresentRectanglesKHR
authorJason Ekstrand <jason.ekstrand@intel.com>
Mon, 15 Oct 2018 02:56:34 +0000 (21:56 -0500)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 18 Oct 2018 14:17:39 +0000 (09:17 -0500)
This got missed during 1.1 enabling because it was defined as an
interaction between device groups and WSI and it wasn't obvious it was
in the delta.

The idea behind it is that it's supposed to provide a hint to the
application in a multi-GPU setup to indicate which regions of the screen
are being scanned out by which GPU so a multi-device split-screen
rendering application can render each part of the screen on the GPU that
will be presenting it and avoid extra bus traffic between GPUs.  On a
single-GPU setup or one which doesn't support this present mode, we need
to do something.  We choose to return the window size (or a max-size
rect) if the compositor, X server, or crtc is associated with the given
physical device and zero rectangles otherwise.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
src/amd/vulkan/radv_wsi.c
src/intel/vulkan/anv_wsi.c
src/vulkan/wsi/wsi_common.c
src/vulkan/wsi/wsi_common.h
src/vulkan/wsi/wsi_common_display.c
src/vulkan/wsi/wsi_common_private.h
src/vulkan/wsi/wsi_common_wayland.c
src/vulkan/wsi/wsi_common_x11.c

index 8b165ea3916bc79b0b4c18df788f4942b6771049..43103a4ef85a1335c604382ed29cf8d7793844e5 100644 (file)
@@ -284,3 +284,17 @@ VkResult radv_GetDeviceGroupSurfacePresentModesKHR(
 
    return VK_SUCCESS;
 }
+
+VkResult radv_GetPhysicalDevicePresentRectanglesKHR(
+       VkPhysicalDevice                            physicalDevice,
+       VkSurfaceKHR                                surface,
+       uint32_t*                                   pRectCount,
+       VkRect2D*                                   pRects)
+{
+       RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
+
+       return wsi_common_get_present_rectangles(&device->wsi_device,
+                                                device->local_fd,
+                                                surface,
+                                                pRectCount, pRects);
+}
index 1c9a54804e8ac675ca0c6398a9a4734f27921061..5d672c211c471179646bce1d9439d243fe30ecd3 100644 (file)
@@ -293,3 +293,17 @@ VkResult anv_GetDeviceGroupSurfacePresentModesKHR(
 
    return VK_SUCCESS;
 }
+
+VkResult anv_GetPhysicalDevicePresentRectanglesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    uint32_t*                                   pRectCount,
+    VkRect2D*                                   pRects)
+{
+   ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
+
+   return wsi_common_get_present_rectangles(&device->wsi_device,
+                                            device->local_fd,
+                                            surface,
+                                            pRectCount, pRects);
+}
index 1e3c4e0028b2f3b640f3489a4f01efc4b8262c18..ad4b8c9075eae1f5cc0f7ecbfbcb76897ae67631 100644 (file)
@@ -803,6 +803,20 @@ wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
                                    pPresentModes);
 }
 
+VkResult
+wsi_common_get_present_rectangles(struct wsi_device *wsi_device,
+                                  int local_fd,
+                                  VkSurfaceKHR _surface,
+                                  uint32_t* pRectCount,
+                                  VkRect2D* pRects)
+{
+   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
+   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
+
+   return iface->get_present_rectangles(surface, wsi_device, local_fd,
+                                        pRectCount, pRects);
+}
+
 VkResult
 wsi_common_create_swapchain(struct wsi_device *wsi,
                             VkDevice device,
index 424330de5663c5b049909f3aa3015acc56bb5661..5b69c573d9e5e2476db5e260df70cf953d0e5a5d 100644 (file)
@@ -199,6 +199,13 @@ wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
                                      uint32_t *pPresentModeCount,
                                      VkPresentModeKHR *pPresentModes);
 
+VkResult
+wsi_common_get_present_rectangles(struct wsi_device *wsi,
+                                  int local_fd,
+                                  VkSurfaceKHR surface,
+                                  uint32_t* pRectCount,
+                                  VkRect2D* pRects);
+
 VkResult
 wsi_common_get_surface_capabilities2ext(
    struct wsi_device *wsi_device,
index c004060a20533423f39aa9d4147f2f8831c78062..2315717ef8e00155a3c8b6a2b597b8cdbec28246 100644 (file)
@@ -934,6 +934,46 @@ wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
    return vk_outarray_status(&conn);
 }
 
+static bool
+fds_are_same_gpu(int fd1, int fd2)
+{
+   if (fd1 == -1 || fd2 == -1)
+      return false;
+
+   char *fd1_dev = drmGetRenderDeviceNameFromFd(fd1);
+   char *fd2_dev = drmGetRenderDeviceNameFromFd(fd2);
+
+   int ret = strcmp(fd1_dev, fd2_dev);
+
+   free(fd1_dev);
+   free(fd2_dev);
+
+   return ret == 0;
+}
+
+static VkResult
+wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
+                                           struct wsi_device *wsi_device,
+                                           int local_fd,
+                                           uint32_t* pRectCount,
+                                           VkRect2D* pRects)
+{
+   VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
+   wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
+   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
+
+   if (fds_are_same_gpu(local_fd, mode->connector->wsi->fd)) {
+      vk_outarray_append(&out, rect) {
+         *rect = (VkRect2D) {
+            .offset = { 0, 0 },
+            .extent = { mode->hdisplay, mode->vdisplay },
+         };
+      }
+   }
+
+   return vk_outarray_status(&out);
+}
+
 static void
 wsi_display_destroy_buffer(struct wsi_display *wsi,
                            uint32_t buffer)
@@ -1810,6 +1850,7 @@ wsi_display_init_wsi(struct wsi_device *wsi_device,
    wsi->base.get_formats = wsi_display_surface_get_formats;
    wsi->base.get_formats2 = wsi_display_surface_get_formats2;
    wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
+   wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
    wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
 
    wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
index accc11701633334efe7c6c6c20dab888e8aac6e1..d8290b69331bf4d24731b56dddb56e89d290d7ac 100644 (file)
@@ -118,6 +118,11 @@ struct wsi_interface {
    VkResult (*get_present_modes)(VkIcdSurfaceBase *surface,
                                  uint32_t* pPresentModeCount,
                                  VkPresentModeKHR* pPresentModes);
+   VkResult (*get_present_rectangles)(VkIcdSurfaceBase *surface,
+                                      struct wsi_device *wsi_device,
+                                      int local_fd,
+                                      uint32_t* pRectCount,
+                                      VkRect2D* pRects);
    VkResult (*create_swapchain)(VkIcdSurfaceBase *surface,
                                 VkDevice device,
                                 struct wsi_device *wsi_device,
index 67d5f8d4c806ad90a8c9f87bb192da94e1bfb0cb..dccb530dae39dd9fca316cf200ce475032c47393 100644 (file)
@@ -601,6 +601,26 @@ wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
       return VK_SUCCESS;
 }
 
+static VkResult
+wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
+                                      struct wsi_device *wsi_device,
+                                      int local_fd,
+                                      uint32_t* pRectCount,
+                                      VkRect2D* pRects)
+{
+   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
+
+   vk_outarray_append(&out, rect) {
+      /* We don't know a size so just return the usual "I don't know." */
+      *rect = (VkRect2D) {
+         .offset = { 0, 0 },
+         .extent = { -1, -1 },
+      };
+   }
+
+   return vk_outarray_status(&out);
+}
+
 VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator,
                               const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
                               VkSurfaceKHR *pSurface)
@@ -1012,6 +1032,7 @@ wsi_wl_init_wsi(struct wsi_device *wsi_device,
    wsi->base.get_formats = wsi_wl_surface_get_formats;
    wsi->base.get_formats2 = wsi_wl_surface_get_formats2;
    wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
+   wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles;
    wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
 
    wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
index 75aa83bb7b4415c6a9a948a17ef993fbcfd8ccf8..8c621ddf568ad7b22f19744973358ee48a8e6c74 100644 (file)
@@ -599,6 +599,66 @@ x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
       VK_INCOMPLETE : VK_SUCCESS;
 }
 
+static bool
+x11_surface_is_local_to_gpu(struct wsi_device *wsi_dev,
+                            int local_fd,
+                            xcb_connection_t *conn)
+{
+   struct wsi_x11_connection *wsi_conn =
+      wsi_x11_get_connection(wsi_dev, conn);
+
+   if (!wsi_conn)
+      return false;
+
+   if (!wsi_x11_check_for_dri3(wsi_conn))
+      return false;
+
+   if (!wsi_x11_check_dri3_compatible(conn, local_fd))
+      return false;
+
+   return true;
+}
+
+static VkResult
+x11_surface_get_present_rectangles(VkIcdSurfaceBase *icd_surface,
+                                   struct wsi_device *wsi_device,
+                                   int local_fd,
+                                   uint32_t* pRectCount,
+                                   VkRect2D* pRects)
+{
+   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
+   xcb_window_t window = x11_surface_get_window(icd_surface);
+   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
+
+   if (x11_surface_is_local_to_gpu(wsi_device, local_fd, conn)) {
+      vk_outarray_append(&out, rect) {
+         xcb_generic_error_t *err = NULL;
+         xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, window);
+         xcb_get_geometry_reply_t *geom =
+            xcb_get_geometry_reply(conn, geom_cookie, &err);
+         free(err);
+         if (geom) {
+            *rect = (VkRect2D) {
+               .offset = { 0, 0 },
+               .extent = { geom->width, geom->height },
+            };
+         } else {
+            /* This can happen if the client didn't wait for the configure event
+             * to come back from the compositor.  In that case, we don't know the
+             * size of the window so we just return valid "I don't know" stuff.
+             */
+            *rect = (VkRect2D) {
+               .offset = { 0, 0 },
+               .extent = { -1, -1 },
+            };
+         }
+         free(geom);
+      }
+   }
+
+   return vk_outarray_status(&out);
+}
+
 VkResult wsi_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
                                const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
                                VkSurfaceKHR *pSurface)
@@ -1470,6 +1530,7 @@ wsi_x11_init_wsi(struct wsi_device *wsi_device,
    wsi->base.get_formats = x11_surface_get_formats;
    wsi->base.get_formats2 = x11_surface_get_formats2;
    wsi->base.get_present_modes = x11_surface_get_present_modes;
+   wsi->base.get_present_rectangles = x11_surface_get_present_rectangles;
    wsi->base.create_swapchain = x11_surface_create_swapchain;
 
    wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;