From e12688f365258f6f719983528a2af9b6ca4e25c5 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 15 Nov 2017 22:30:20 -0800 Subject: [PATCH] vulkan/wsi: Do image creation in common code This uses the mock extension created in a previous commit to tell the driver that the image it's just been asked to create is, in fact, a window system image with whatever assumptions that implies. There was a lot of redundant code between the two drivers to do basically exactly the same thing. Reviewed-by: Dave Airlie Reviewed-by: Chad Versace --- src/amd/vulkan/radv_wsi.c | 124 +--------------------------- src/intel/vulkan/anv_wsi.c | 122 +-------------------------- src/vulkan/wsi/wsi_common.c | 117 +++++++++++++++++++++++++- src/vulkan/wsi/wsi_common.h | 28 +------ src/vulkan/wsi/wsi_common_private.h | 25 +++++- src/vulkan/wsi/wsi_common_wayland.c | 13 +-- src/vulkan/wsi/wsi_common_x11.c | 20 +---- 7 files changed, 146 insertions(+), 303 deletions(-) diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c index 930e9e36461..5e9c239e637 100644 --- a/src/amd/vulkan/radv_wsi.c +++ b/src/amd/vulkan/radv_wsi.c @@ -157,128 +157,6 @@ VkResult radv_GetPhysicalDeviceSurfacePresentModesKHR( pPresentModes); } -static VkResult -radv_wsi_image_create(VkDevice device_h, - const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks* pAllocator, - struct wsi_image *wsi_image) -{ - VkResult result = VK_SUCCESS; - struct radeon_surf *surface; - VkImage image_h; - struct radv_image *image; - int fd; - RADV_FROM_HANDLE(radv_device, device, device_h); - - result = radv_image_create(device_h, - &(struct radv_image_create_info) { - .vk_info = - &(VkImageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1 - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = 1, - /* FIXME: Need a way to use X tiling to allow scanout */ - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .flags = 0, - }, - .scanout = true}, - NULL, - &image_h); - if (result != VK_SUCCESS) - return result; - - image = radv_image_from_handle(image_h); - - VkDeviceMemory memory_h; - - const VkMemoryDedicatedAllocateInfoKHR ded_alloc = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, - .pNext = NULL, - .buffer = VK_NULL_HANDLE, - .image = image_h - }; - - /* Find the first VRAM memory type, or GART for PRIME images. */ - int memory_type_index = -1; - for (int i = 0; i < device->physical_device->memory_properties.memoryTypeCount; ++i) { - bool is_local = !!(device->physical_device->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - if (is_local) { - memory_type_index = i; - break; - } - } - - /* fallback */ - if (memory_type_index == -1) - memory_type_index = 0; - - result = radv_alloc_memory(device_h, - &(VkMemoryAllocateInfo) { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &ded_alloc, - .allocationSize = image->size, - .memoryTypeIndex = memory_type_index, - }, - NULL /* XXX: pAllocator */, - RADV_MEM_IMPLICIT_SYNC, - &memory_h); - if (result != VK_SUCCESS) - goto fail_create_image; - - radv_BindImageMemory(device_h, image_h, memory_h, 0); - - RADV_FROM_HANDLE(radv_device_memory, memory, memory_h); - if (!radv_get_memory_fd(device, memory, &fd)) - goto fail_alloc_memory; - wsi_image->fd = fd; - - surface = &image->surface; - - wsi_image->image = image_h; - wsi_image->memory = memory_h; - wsi_image->size = image->size; - wsi_image->offset = image->offset; - if (device->physical_device->rad_info.chip_class >= GFX9) - wsi_image->row_pitch = - surface->u.gfx9.surf_pitch * surface->bpe; - else - wsi_image->row_pitch = - surface->u.legacy.level[0].nblk_x * surface->bpe; - - return VK_SUCCESS; - fail_alloc_memory: - radv_FreeMemory(device_h, memory_h, pAllocator); - -fail_create_image: - radv_DestroyImage(device_h, image_h, pAllocator); - - return result; -} - -static void -radv_wsi_image_free(VkDevice device, - const VkAllocationCallbacks* pAllocator, - struct wsi_image *wsi_image) -{ - radv_DestroyImage(device, wsi_image->image, pAllocator); - - radv_FreeMemory(device, wsi_image->memory, pAllocator); -} - -static const struct wsi_image_fns radv_wsi_image_fns = { - .create_wsi_image = radv_wsi_image_create, - .free_wsi_image = radv_wsi_image_free, -}; - VkResult radv_CreateSwapchainKHR( VkDevice _device, const VkSwapchainCreateInfoKHR* pCreateInfo, @@ -299,7 +177,7 @@ VkResult radv_CreateSwapchainKHR( &device->physical_device->wsi_device, device->physical_device->local_fd, pCreateInfo, - alloc, &radv_wsi_image_fns, + alloc, &swapchain); if (result != VK_SUCCESS) return result; diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c index 18ef61ade61..b654db97bc1 100644 --- a/src/intel/vulkan/anv_wsi.c +++ b/src/intel/vulkan/anv_wsi.c @@ -186,126 +186,6 @@ VkResult anv_GetPhysicalDeviceSurfacePresentModesKHR( pPresentModes); } - -static VkResult -anv_wsi_image_create(VkDevice device_h, - const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks* pAllocator, - struct wsi_image *wsi_image) -{ - struct anv_device *device = anv_device_from_handle(device_h); - VkImage image_h; - struct anv_image *image; - - VkResult result; - result = anv_image_create(anv_device_to_handle(device), - &(struct anv_image_create_info) { - .isl_tiling_flags = ISL_TILING_X_BIT, - .stride = 0, - .vk_info = - &(VkImageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1 - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = 1, - /* FIXME: Need a way to use X tiling to allow scanout */ - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = (pCreateInfo->imageUsage | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), - .flags = 0, - }}, - NULL, - &image_h); - if (result != VK_SUCCESS) - return result; - - image = anv_image_from_handle(image_h); - assert(vk_format_is_color(image->vk_format)); - - VkDeviceMemory memory_h; - struct anv_device_memory *memory; - result = anv_AllocateMemory(anv_device_to_handle(device), - &(VkMemoryAllocateInfo) { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .allocationSize = image->size, - .memoryTypeIndex = 0, - }, - NULL /* XXX: pAllocator */, - &memory_h); - if (result != VK_SUCCESS) - goto fail_create_image; - - memory = anv_device_memory_from_handle(memory_h); - - /* We need to set the WRITE flag on window system buffers so that GEM will - * know we're writing to them and synchronize uses on other rings (eg if - * the display server uses the blitter ring). - */ - memory->bo->flags &= ~EXEC_OBJECT_ASYNC; - memory->bo->flags |= EXEC_OBJECT_WRITE; - - anv_BindImageMemory(device_h, image_h, memory_h, 0); - assert(image->planes[0].offset == 0); - - struct anv_surface *surface = &image->planes[0].surface; - assert(surface->isl.tiling == ISL_TILING_X); - - int ret = anv_gem_set_tiling(device, memory->bo->gem_handle, - surface->isl.row_pitch, I915_TILING_X); - if (ret) { - /* FINISHME: Choose a better error. */ - result = vk_errorf(device->instance, device, - VK_ERROR_OUT_OF_DEVICE_MEMORY, - "set_tiling failed: %m"); - goto fail_alloc_memory; - } - - int fd = anv_gem_handle_to_fd(device, memory->bo->gem_handle); - if (fd == -1) { - /* FINISHME: Choose a better error. */ - result = vk_errorf(device->instance, device, - VK_ERROR_OUT_OF_DEVICE_MEMORY, - "handle_to_fd failed: %m"); - goto fail_alloc_memory; - } - - wsi_image->image = image_h; - wsi_image->memory = memory_h; - wsi_image->fd = fd; - wsi_image->size = image->size; - wsi_image->offset = 0; - wsi_image->row_pitch = surface->isl.row_pitch; - return VK_SUCCESS; -fail_alloc_memory: - anv_FreeMemory(device_h, memory_h, pAllocator); - -fail_create_image: - anv_DestroyImage(device_h, image_h, pAllocator); - return result; -} - -static void -anv_wsi_image_free(VkDevice device, - const VkAllocationCallbacks* pAllocator, - struct wsi_image *wsi_image) -{ - anv_DestroyImage(device, wsi_image->image, pAllocator); - - anv_FreeMemory(device, wsi_image->memory, pAllocator); -} - -static const struct wsi_image_fns anv_wsi_image_fns = { - .create_wsi_image = anv_wsi_image_create, - .free_wsi_image = anv_wsi_image_free, -}; - VkResult anv_CreateSwapchainKHR( VkDevice _device, const VkSwapchainCreateInfoKHR* pCreateInfo, @@ -327,7 +207,7 @@ VkResult anv_CreateSwapchainKHR( &device->instance->physicalDevice.wsi_device, device->instance->physicalDevice.local_fd, pCreateInfo, - alloc, &anv_wsi_image_fns, + alloc, &swapchain); if (result != VK_SUCCESS) return result; diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index 7cb5d894e77..b86bb90cec6 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -59,6 +59,7 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(FreeCommandBuffers); WSI_GET_CB(GetBufferMemoryRequirements); WSI_GET_CB(GetImageMemoryRequirements); + WSI_GET_CB(GetImageSubresourceLayout); WSI_GET_CB(GetMemoryFdKHR); WSI_GET_CB(QueueSubmit); #undef WSI_GET_CB @@ -147,6 +148,116 @@ align_u32(uint32_t v, uint32_t a) return (v + a - 1) & ~(a - 1); } +VkResult +wsi_create_native_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + + const struct wsi_image_create_info image_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, + .pNext = NULL, + .scanout = true, + }; + const VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = &image_wsi_info, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + VkSubresourceLayout image_layout; + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfoKHR memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext = &memory_export_info, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkMemoryGetFdInfoKHR memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = image->memory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + int fd; + result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd); + if (result != VK_SUCCESS) + goto fail; + + image->size = reqs.size; + image->row_pitch = image_layout.rowPitch; + image->offset = 0; + image->fd = fd; + + return VK_SUCCESS; + +fail: + wsi_destroy_image(chain, image); + + return result; +} + #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256 VkResult @@ -342,14 +453,14 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, return VK_SUCCESS; fail: - wsi_destroy_prime_image(chain, image); + wsi_destroy_image(chain, image); return result; } void -wsi_destroy_prime_image(const struct wsi_swapchain *chain, - struct wsi_image *image) +wsi_destroy_image(const struct wsi_swapchain *chain, + struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index d77ae446b08..a5e7e655fc8 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -48,39 +48,13 @@ struct wsi_memory_allocate_info { bool implicit_sync; }; -struct wsi_image { - VkImage image; - VkDeviceMemory memory; - - struct { - VkBuffer buffer; - VkDeviceMemory memory; - VkCommandBuffer *blit_cmd_buffers; - } prime; - - uint32_t size; - uint32_t offset; - uint32_t row_pitch; - int fd; -}; - struct wsi_device; -struct wsi_image_fns { - VkResult (*create_wsi_image)(VkDevice device_h, - const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - struct wsi_image *image_p); - void (*free_wsi_image)(VkDevice device, - const VkAllocationCallbacks *pAllocator, - struct wsi_image *image); -}; struct wsi_swapchain { const struct wsi_device *wsi; VkDevice device; VkAllocationCallbacks alloc; - const struct wsi_image_fns *image_fns; VkFence fences[3]; VkPresentModeKHR present_mode; uint32_t image_count; @@ -134,7 +108,6 @@ struct wsi_interface { int local_fd, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, - const struct wsi_image_fns *image_fns, struct wsi_swapchain **swapchain); }; @@ -164,6 +137,7 @@ struct wsi_device { WSI_CB(FreeCommandBuffers); WSI_CB(GetBufferMemoryRequirements); WSI_CB(GetImageMemoryRequirements); + WSI_CB(GetImageSubresourceLayout); WSI_CB(GetMemoryFdKHR); WSI_CB(QueueSubmit); #undef WSI_CB diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index 3cef6dd4394..ff8ca2a4b20 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -25,6 +25,22 @@ #include "wsi_common.h" +struct wsi_image { + VkImage image; + VkDeviceMemory memory; + + struct { + VkBuffer buffer; + VkDeviceMemory memory; + VkCommandBuffer *blit_cmd_buffers; + } prime; + + uint32_t size; + uint32_t offset; + uint32_t row_pitch; + int fd; +}; + VkResult wsi_swapchain_init(const struct wsi_device *wsi, struct wsi_swapchain *chain, @@ -34,14 +50,19 @@ wsi_swapchain_init(const struct wsi_device *wsi, void wsi_swapchain_finish(struct wsi_swapchain *chain); +VkResult +wsi_create_native_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + struct wsi_image *image); + VkResult wsi_create_prime_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, struct wsi_image *image); void -wsi_destroy_prime_image(const struct wsi_swapchain *chain, - struct wsi_image *image); +wsi_destroy_image(const struct wsi_swapchain *chain, + struct wsi_image *image); VkResult wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain, diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c index c24afcd184a..22c01b2963a 100644 --- a/src/vulkan/wsi/wsi_common_wayland.c +++ b/src/vulkan/wsi/wsi_common_wayland.c @@ -728,13 +728,9 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator) { - VkDevice vk_device = chain->base.device; VkResult result; - result = chain->base.image_fns->create_wsi_image(vk_device, - pCreateInfo, - pAllocator, - &image->base); + result = wsi_create_native_image(&chain->base, pCreateInfo, &image->base); if (result != VK_SUCCESS) return result; @@ -756,7 +752,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, return VK_SUCCESS; fail_image: - chain->base.image_fns->free_wsi_image(vk_device, pAllocator, &image->base); + wsi_destroy_image(&chain->base, &image->base); return result; } @@ -770,8 +766,7 @@ wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain, for (uint32_t i = 0; i < chain->base.image_count; i++) { if (chain->images[i].buffer) { wl_buffer_destroy(chain->images[i].buffer); - chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator, - &chain->images[i].base); + wsi_destroy_image(&chain->base, &chain->images[i].base); } } @@ -799,7 +794,6 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, int local_fd, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, - const struct wsi_image_fns *image_fns, struct wsi_swapchain **swapchain_out) { VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; @@ -841,7 +835,6 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->base.get_images = wsi_wl_swapchain_get_images; chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; chain->base.queue_present = wsi_wl_swapchain_queue_present; - chain->base.image_fns = image_fns; chain->base.present_mode = pCreateInfo->presentMode; chain->base.image_count = num_images; chain->extent = pCreateInfo->imageExtent; diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index fd60cfa95b0..68cb0355612 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -969,10 +969,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, if (chain->use_prime_blit) { result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base); } else { - result = chain->base.image_fns->create_wsi_image(device_h, - pCreateInfo, - pAllocator, - &image->base); + result = wsi_create_native_image(&chain->base, pCreateInfo, &image->base); } if (result != VK_SUCCESS) return result; @@ -1019,11 +1016,7 @@ fail_pixmap: cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); - if (chain->use_prime_blit) { - wsi_destroy_prime_image(&chain->base, &image->base); - } else { - chain->base.image_fns->free_wsi_image(device_h, pAllocator, &image->base); - } + wsi_destroy_image(&chain->base, &image->base); return result; } @@ -1042,12 +1035,7 @@ x11_image_finish(struct x11_swapchain *chain, cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); - if (chain->use_prime_blit) { - wsi_destroy_prime_image(&chain->base, &image->base); - } else { - chain->base.image_fns->free_wsi_image(chain->base.device, - pAllocator, &image->base); - } + wsi_destroy_image(&chain->base, &image->base); } static VkResult @@ -1089,7 +1077,6 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, int local_fd, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, - const struct wsi_image_fns *image_fns, struct wsi_swapchain **swapchain_out) { struct x11_swapchain *chain; @@ -1125,7 +1112,6 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->base.get_images = x11_get_images; chain->base.acquire_next_image = x11_acquire_next_image; chain->base.queue_present = x11_queue_present; - chain->base.image_fns = image_fns; chain->base.present_mode = pCreateInfo->presentMode; chain->base.image_count = num_images; chain->conn = conn; -- 2.30.2