[Mesa-dev] [PATCH] [rfc] radv: add initial prime support. (v2)

Dave Airlie airlied at gmail.com
Tue Dec 13 04:23:11 UTC 2016


From: Dave Airlie <airlied at redhat.com>

This is a repost of the prime support with some minor changes,
you no longer need to set DRI_PRIME for this code to figure out
it's on a different GPU and do the linear transfers.

In order to decide the default GPU I'll have to write a layer
so I'll try and get to that soon.

This creates a linear shadow image in GART that gets blitted to at the
image transition. We shouldn't have to add two pointers to every image, but my other
attempts at this were ugly.

v2: move to testing the dri3 fd to decide if we are a different
GPU, dont need to set DRI_PRIME for the driver now.

TODO:
this would use SDMA on a transfer queue, I'll get back to that
when I have transfer queues merged.
Is the image transition the proper place to hack this in? not
really sure anywhere else is appropriate. nha says no, and
he's probably right so once I have transfer working I'll create
some command buffers at swapchain present time.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/amd/vulkan/radv_cmd_buffer.c    |  18 ++++++
 src/amd/vulkan/radv_device.c        |   3 +
 src/amd/vulkan/radv_meta.h          |   2 +
 src/amd/vulkan/radv_meta_copy.c     |  29 +++++++++
 src/amd/vulkan/radv_private.h       |   4 ++
 src/amd/vulkan/radv_wsi.c           | 120 ++++++++++++++++++++++++++++--------
 src/intel/vulkan/Makefile.am        |   2 +-
 src/intel/vulkan/anv_wsi.c          |   2 +
 src/vulkan/wsi/Makefile.am          |   1 +
 src/vulkan/wsi/wsi_common.h         |   3 +
 src/vulkan/wsi/wsi_common_wayland.c |   1 +
 src/vulkan/wsi/wsi_common_x11.c     |  74 +++++++++++++++++++++-
 12 files changed, 232 insertions(+), 27 deletions(-)

diff --git a/src/amd/vulkan/radv_cmd_buffer.c b/src/amd/vulkan/radv_cmd_buffer.c
index 8e99fc0..0fd58bc 100644
--- a/src/amd/vulkan/radv_cmd_buffer.c
+++ b/src/amd/vulkan/radv_cmd_buffer.c
@@ -2381,6 +2381,20 @@ static void radv_handle_dcc_image_transition(struct radv_cmd_buffer *cmd_buffer,
 	}
 }
 
+static void radv_handle_prime_image_transition(struct radv_cmd_buffer *cmd_buffer,
+					       struct radv_image *image,
+					       VkImageLayout src_layout,
+					       VkImageLayout dst_layout,
+					       VkImageSubresourceRange range,
+					       VkImageAspectFlags pending_clears)
+{
+	cmd_buffer->state.flush_bits |= RADV_CMD_FLUSH_AND_INV_FRAMEBUFFER;
+	si_emit_cache_flush(cmd_buffer);
+	radv_blit_to_prime_linear(cmd_buffer, image);
+	cmd_buffer->state.flush_bits |= RADV_CMD_FLUSH_AND_INV_FRAMEBUFFER;
+	si_emit_cache_flush(cmd_buffer);
+}
+
 static void radv_handle_image_transition(struct radv_cmd_buffer *cmd_buffer,
 					 struct radv_image *image,
 					 VkImageLayout src_layout,
@@ -2399,6 +2413,10 @@ static void radv_handle_image_transition(struct radv_cmd_buffer *cmd_buffer,
 	if (image->surface.dcc_size)
 		radv_handle_dcc_image_transition(cmd_buffer, image, src_layout,
 						 dst_layout, range, pending_clears);
+
+	if (image->prime_image && dst_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
+		radv_handle_prime_image_transition(cmd_buffer, image, src_layout,
+						   dst_layout, range, pending_clears);
 }
 
 void radv_CmdPipelineBarrier(
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 75b7af1..4abf053 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -105,6 +105,8 @@ radv_physical_device_init(struct radv_physical_device *device,
 	}
 	drmFreeVersion(version);
 
+	device->rendername = drmGetRenderDeviceNameFromFd(fd);
+
 	device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
 	device->instance = instance;
 	assert(strlen(path) < ARRAY_SIZE(device->path));
@@ -145,6 +147,7 @@ radv_physical_device_finish(struct radv_physical_device *device)
 {
 	radv_finish_wsi(device);
 	device->ws->destroy(device->ws);
+	free(device->rendername);
 }
 
 static const VkExtensionProperties global_extensions[] = {
diff --git a/src/amd/vulkan/radv_meta.h b/src/amd/vulkan/radv_meta.h
index 97d020c..e43a0e7 100644
--- a/src/amd/vulkan/radv_meta.h
+++ b/src/amd/vulkan/radv_meta.h
@@ -186,6 +186,8 @@ void radv_meta_resolve_compute_image(struct radv_cmd_buffer *cmd_buffer,
 				     uint32_t region_count,
 				     const VkImageResolve *regions);
 
+void radv_blit_to_prime_linear(struct radv_cmd_buffer *cmd_buffer,
+			       struct radv_image *image);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/amd/vulkan/radv_meta_copy.c b/src/amd/vulkan/radv_meta_copy.c
index d81fc48..978c853 100644
--- a/src/amd/vulkan/radv_meta_copy.c
+++ b/src/amd/vulkan/radv_meta_copy.c
@@ -403,3 +403,32 @@ void radv_CmdCopyImage(
 	meta_copy_image(cmd_buffer, src_image, dest_image,
 			regionCount, pRegions);
 }
+
+void radv_blit_to_prime_linear(struct radv_cmd_buffer *cmd_buffer,
+			       struct radv_image *image)
+{
+	struct radv_meta_saved_state saved_state;
+	struct radv_meta_saved_pass_state saved_pass_state;
+	VkImageSubresourceLayers src_res = {0}, dst_res = {0};
+	radv_meta_save_pass(&saved_pass_state, cmd_buffer);
+	radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
+
+	src_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	dst_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	struct radv_meta_blit2d_surf b_src =
+		blit_surf_for_image_level_layer(image,
+						&src_res);
+
+	struct radv_meta_blit2d_surf b_dst =
+		blit_surf_for_image_level_layer(image->prime_image,
+						&dst_res);
+	struct radv_meta_blit2d_rect rect = {
+		.width = image->extent.width,
+		.height = image->extent.height,
+	};
+
+	radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect);
+
+	radv_meta_restore(&saved_state, cmd_buffer);
+	radv_meta_restore_pass(&saved_pass_state, cmd_buffer);
+}
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index 2ecc48e..cd3577e 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -267,6 +267,7 @@ struct radv_physical_device {
 	const char *                                name;
 	uint8_t                                     uuid[VK_UUID_SIZE];
 
+	char *rendername;
 	struct wsi_device                       wsi_device;
 };
 
@@ -985,6 +986,9 @@ struct radv_image {
 
 	/* Depth buffer compression and fast clear. */
 	struct r600_htile_info htile;
+
+	struct radv_image *prime_image;
+	struct radv_device_memory *prime_memory;
 };
 
 bool radv_layout_has_htile(const struct radv_image *image,
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index 1f1ab1c..5dcf491 100644
--- a/src/amd/vulkan/radv_wsi.c
+++ b/src/amd/vulkan/radv_wsi.c
@@ -135,23 +135,27 @@ VkResult radv_GetPhysicalDeviceSurfacePresentModesKHR(
 					pPresentModes);
 }
 
+static void
+radv_wsi_image_destroy_single(VkDevice device_h,
+			      const VkAllocationCallbacks* pAllocator,
+			      VkImage image_h,
+			      VkDeviceMemory memory_h)
+{
+	radv_DestroyImage(device_h, image_h, pAllocator);
+	radv_FreeMemory(device_h, memory_h, pAllocator);
+}
+
 static VkResult
-radv_wsi_image_create(VkDevice device_h,
-		      const VkSwapchainCreateInfoKHR *pCreateInfo,
-		      const VkAllocationCallbacks* pAllocator,
-		      VkImage *image_p,
-		      VkDeviceMemory *memory_p,
-		      uint32_t *size,
-		      uint32_t *offset,
-		      uint32_t *row_pitch, int *fd_p)
+radv_wsi_image_create_single(VkDevice device_h,
+			     const VkSwapchainCreateInfoKHR *pCreateInfo,
+			     const VkAllocationCallbacks* pAllocator,
+			     VkImage *image_p,
+			     VkDeviceMemory *memory_p,
+			     bool tiled)
 {
-	struct radv_device *device = radv_device_from_handle(device_h);
-	VkResult result = VK_SUCCESS;
-	struct radeon_surf *surface;
+	VkResult result;
 	VkImage image_h;
 	struct radv_image *image;
-	bool bret;
-	int fd;
 
 	result = radv_image_create(device_h,
 				   &(struct radv_image_create_info) {
@@ -169,7 +173,7 @@ radv_wsi_image_create(VkDevice device_h,
 						   .arrayLayers = 1,
 						   .samples = 1,
 						   /* FIXME: Need a way to use X tiling to allow scanout */
-						   .tiling = VK_IMAGE_TILING_OPTIMAL,
+						   .tiling = tiled ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR,
 						   .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
 						   .flags = 0,
 					   },
@@ -180,24 +184,74 @@ radv_wsi_image_create(VkDevice device_h,
 		return result;
 
 	image = radv_image_from_handle(image_h);
-
 	VkDeviceMemory memory_h;
-	struct radv_device_memory *memory;
+
 	result = radv_AllocateMemory(device_h,
 				     &(VkMemoryAllocateInfo) {
 					     .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
 						     .allocationSize = image->size,
-						     .memoryTypeIndex = 0,
+						     .memoryTypeIndex = tiled ? 0 : 1,
 						     },
 				     NULL /* XXX: pAllocator */,
 				     &memory_h);
 	if (result != VK_SUCCESS)
 		goto fail_create_image;
 
-	memory = radv_device_memory_from_handle(memory_h);
-
 	radv_BindImageMemory(VK_NULL_HANDLE, image_h, memory_h, 0);
 
+	*image_p = image_h;
+	*memory_p = memory_h;
+	return VK_SUCCESS;
+fail_create_image:
+	radv_DestroyImage(device_h, image_h, pAllocator);
+	return result;
+}
+
+static VkResult
+radv_wsi_image_create(VkDevice device_h,
+		      const VkSwapchainCreateInfoKHR *pCreateInfo,
+		      const VkAllocationCallbacks* pAllocator,
+		      bool different_gpu,
+		      VkImage *image_p,
+		      VkDeviceMemory *memory_p,
+		      uint32_t *size,
+		      uint32_t *offset,
+		      uint32_t *row_pitch, int *fd_p)
+{
+	struct radv_device *device = radv_device_from_handle(device_h);
+	VkResult result = VK_SUCCESS;
+	struct radeon_surf *surface;
+	VkImage image_h, image_prime_h;
+	VkDeviceMemory memory_h, memory_prime_h;
+	struct radv_image *image;
+	struct radv_device_memory *memory;
+	bool bret;
+	int fd;
+
+	result = radv_wsi_image_create_single(device_h, pCreateInfo,
+					      pAllocator, &image_h, &memory_h,
+					      true);
+	if (result != VK_SUCCESS)
+		return result;
+
+	image = radv_image_from_handle(image_h);
+	if (different_gpu) {
+		result = radv_wsi_image_create_single(device_h, pCreateInfo,
+						      pAllocator, &image_prime_h,
+						      &memory_prime_h, false);
+
+		if (result != VK_SUCCESS)
+			goto fail_create_image;
+
+		image->prime_image = radv_image_from_handle(image_prime_h);
+		image->prime_memory = radv_device_memory_from_handle(memory_prime_h);
+
+		memory = image->prime_memory;
+		image = image->prime_image;
+	} else {
+		memory = radv_device_memory_from_handle(memory_h);
+	}
+
 	bret = device->ws->buffer_get_fd(device->ws,
 					 memory->bo, &fd);
 	if (bret == false)
@@ -217,29 +271,45 @@ radv_wsi_image_create(VkDevice device_h,
 	*offset = image->offset;
 	*row_pitch = surface->level[0].pitch_bytes;
 	return VK_SUCCESS;
- fail_alloc_memory:
-	radv_FreeMemory(device_h, memory_h, pAllocator);
+
+fail_alloc_memory:
+	if (different_gpu)
+		radv_wsi_image_destroy_single(device_h, pAllocator, image_prime_h, memory_prime_h);
 
 fail_create_image:
-	radv_DestroyImage(device_h, image_h, pAllocator);
+	radv_wsi_image_destroy_single(device_h, pAllocator, image_h, memory_h);
 
 	return result;
 }
 
 static void
-radv_wsi_image_free(VkDevice device,
+radv_wsi_image_free(VkDevice device_h,
 		    const VkAllocationCallbacks* pAllocator,
 		    VkImage image_h,
 		    VkDeviceMemory memory_h)
 {
-	radv_DestroyImage(device, image_h, pAllocator);
+	RADV_FROM_HANDLE(radv_image, image, image_h);
+
+	if (image->prime_image)
+		radv_wsi_image_destroy_single(device_h, pAllocator,
+					      radv_image_to_handle(image->prime_image),
+					      radv_device_memory_to_handle(image->prime_memory));
+
+	radv_wsi_image_destroy_single(device_h, pAllocator, image_h, memory_h);
+}
+
+static const char *
+radv_wsi_get_device_name(VkDevice device_h)
+{
+	RADV_FROM_HANDLE(radv_device, device, device_h);
 
-	radv_FreeMemory(device, memory_h, pAllocator);
+	return device->instance->physicalDevice.rendername;
 }
 
 static const struct wsi_image_fns radv_wsi_image_fns = {
    .create_wsi_image = radv_wsi_image_create,
    .free_wsi_image = radv_wsi_image_free,
+   .get_render_device_name = radv_wsi_get_device_name,
 };
 
 VkResult radv_CreateSwapchainKHR(
diff --git a/src/intel/vulkan/Makefile.am b/src/intel/vulkan/Makefile.am
index df7645f..2d30992 100644
--- a/src/intel/vulkan/Makefile.am
+++ b/src/intel/vulkan/Makefile.am
@@ -91,7 +91,7 @@ VULKAN_SOURCES = \
 	$(VULKAN_GENERATED_FILES) \
 	$(VULKAN_FILES)
 
-VULKAN_LIB_DEPS =
+VULKAN_LIB_DEPS = $(LIBDRM_LIBS)
 
 if HAVE_PLATFORM_X11
 AM_CPPFLAGS += \
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index 669eacc..95a2d18 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -142,6 +142,7 @@ static VkResult
 x11_anv_wsi_image_create(VkDevice device_h,
                          const VkSwapchainCreateInfoKHR *pCreateInfo,
                          const VkAllocationCallbacks* pAllocator,
+                         bool different_gpu,
                          VkImage *image_p,
                          VkDeviceMemory *memory_p,
                          uint32_t *size,
@@ -251,6 +252,7 @@ x11_anv_wsi_image_free(VkDevice device,
 static const struct wsi_image_fns anv_wsi_image_fns = {
    .create_wsi_image = x11_anv_wsi_image_create,
    .free_wsi_image = x11_anv_wsi_image_free,
+   .get_render_device_name = NULL,
 };
 
 VkResult anv_CreateSwapchainKHR(
diff --git a/src/vulkan/wsi/Makefile.am b/src/vulkan/wsi/Makefile.am
index a712799..b5ccf98 100644
--- a/src/vulkan/wsi/Makefile.am
+++ b/src/vulkan/wsi/Makefile.am
@@ -13,6 +13,7 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/gallium/include
 
 AM_CFLAGS = \
+	$(LIBDRM_CFLAGS) \
 	$(VISIBILITY_CFLAGS)
 
 VULKAN_LIB_DEPS =
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index a1f5a40..216dacb 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -35,6 +35,7 @@ struct wsi_image_fns {
    VkResult (*create_wsi_image)(VkDevice device_h,
                                 const VkSwapchainCreateInfoKHR *pCreateInfo,
                                 const VkAllocationCallbacks *pAllocator,
+                                bool different_gpu,
                                 VkImage *image_p,
                                 VkDeviceMemory *memory_p,
                                 uint32_t *size_p,
@@ -45,6 +46,8 @@ struct wsi_image_fns {
                           const VkAllocationCallbacks *pAllocator,
                           VkImage image_h,
                           VkDeviceMemory memory_h);
+
+   const char *(*get_render_device_name)(VkDevice device);
 };
 
 struct wsi_swapchain {
diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c
index 2fe889e..9c007f9 100644
--- a/src/vulkan/wsi/wsi_common_wayland.c
+++ b/src/vulkan/wsi/wsi_common_wayland.c
@@ -632,6 +632,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain,
    result = chain->base.image_fns->create_wsi_image(vk_device,
                                                     pCreateInfo,
                                                     pAllocator,
+                                                    false,
                                                     &image->image,
                                                     &image->memory,
                                                     &size,
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index 25ba0c1..65a5e32 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -33,8 +33,9 @@
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
-
+#include <fcntl.h>
 #include <poll.h>
+#include <xf86drm.h>
 #include "util/hash_table.h"
 
 #include "wsi_common.h"
@@ -485,6 +486,8 @@ struct x11_swapchain {
    xcb_connection_t *                           conn;
    xcb_window_t                                 window;
    xcb_gc_t                                     gc;
+   bool                                         different_gpu;
+
    uint32_t                                     depth;
    VkExtent2D                                   extent;
    uint32_t                                     image_count;
@@ -813,6 +816,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
    result = chain->base.image_fns->create_wsi_image(device_h,
                                                     pCreateInfo,
                                                     pAllocator,
+                                                    chain->different_gpu,
                                                     &image->image,
                                                     &image->memory,
                                                     &size,
@@ -916,6 +920,61 @@ x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
    return VK_SUCCESS;
 }
 
+/** wsi_dri3_open
+ *
+ * Wrapper around xcb_dri3_open
+ */
+static int
+wsi_dri3_open(xcb_connection_t *conn,
+	      xcb_window_t root,
+	      uint32_t provider)
+{
+   xcb_dri3_open_cookie_t       cookie;
+   xcb_dri3_open_reply_t        *reply;
+   int                          fd;
+
+   cookie = xcb_dri3_open(conn,
+                          root,
+                          provider);
+
+   reply = xcb_dri3_open_reply(conn, cookie, NULL);
+   if (!reply)
+      return -1;
+
+   if (reply->nfd != 1) {
+      free(reply);
+      return -1;
+   }
+
+   fd = xcb_dri3_open_reply_fds(conn, reply)[0];
+   free(reply);
+   fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+
+   return fd;
+}
+
+static int
+x11_get_dri3_fd(struct x11_swapchain *chain)
+{
+   xcb_query_tree_cookie_t tree_cookie;
+   xcb_query_tree_reply_t *tree;
+   int dri3_fd;
+   tree_cookie = xcb_query_tree(chain->conn, chain->window);
+   tree = xcb_query_tree_reply(chain->conn, tree_cookie, NULL);
+   if (tree == NULL) {
+      return -1;
+   }
+
+   xcb_window_t root = tree->root;
+   free(tree);
+
+   dri3_fd = wsi_dri3_open(chain->conn, root, None);
+   if (dri3_fd == -1)
+      return -1;
+
+   return dri3_fd;
+}
+
 static VkResult
 x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
                              VkDevice device,
@@ -966,6 +1025,19 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
 
    free(geometry);
 
+   if (chain->base.image_fns->get_render_device_name) {
+      int dri3_fd = x11_get_dri3_fd(chain);
+      if (dri3_fd != -1) {
+	 const char *render_dev = chain->base.image_fns->get_render_device_name(device);
+	 char *dri3_dev = drmGetRenderDeviceNameFromFd(dri3_fd);
+
+	 if (strcmp(render_dev, dri3_dev))
+	    chain->different_gpu = true;
+
+	 close(dri3_fd);
+      }
+   }
+
    chain->event_id = xcb_generate_id(chain->conn);
    xcb_present_select_input(chain->conn, chain->event_id, chain->window,
                             XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
-- 
2.9.3



More information about the mesa-dev mailing list