Add support for some Vulkan 1.1 structs
authorDennis Tsiang <dennis.tsiang@arm.com>
Thu, 23 Sep 2021 14:35:51 +0000 (15:35 +0100)
committerDennis Tsiang <dennis.tsiang@arm.com>
Thu, 23 Sep 2021 14:35:51 +0000 (15:35 +0100)
This commit adds support for VkBindImageMemorySwapchainInfoKHR and
VkImageSwapchainCreateInfoKHR.

Change-Id: I3d87cd7df380e59ceb386f08437c5d6f09dcee1f
Signed-off-by: Dennis Tsiang <dennis.tsiang@arm.com>
layer/layer.cpp
layer/swapchain_api.cpp
layer/swapchain_api.hpp
util/helpers.hpp [new file with mode: 0644]
wsi/headless/swapchain.cpp
wsi/headless/swapchain.hpp
wsi/swapchain_base.cpp
wsi/swapchain_base.hpp
wsi/wayland/swapchain.cpp
wsi/wayland/swapchain.hpp

index 8c444bf..be2f2a1 100644 (file)
@@ -439,6 +439,8 @@ VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetDeviceProcAddr(VkDe
    GET_PROC_ADDR(vkGetDeviceGroupSurfacePresentModesKHR);
    GET_PROC_ADDR(vkGetDeviceGroupPresentCapabilitiesKHR);
    GET_PROC_ADDR(vkAcquireNextImage2KHR);
+   GET_PROC_ADDR(vkCreateImage);
+   GET_PROC_ADDR(vkBindImageMemory2);
 
    return layer::device_private_data::get(device).disp.GetDeviceProcAddr(device, funcName);
 }
index 474b891..8ee59a8 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "private_data.hpp"
 #include "swapchain_api.hpp"
+#include <util/helpers.hpp>
 
 extern "C" {
 
@@ -262,4 +263,54 @@ VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImage2KHR(VkDevice device, const VkAc
    return sc->acquire_next_image(pAcquireInfo->timeout, pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex);
 }
 
+VKAPI_ATTR VkResult wsi_layer_vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage)
+{
+   auto &device_data = layer::device_private_data::get(device);
+
+   const VkImageSwapchainCreateInfoKHR *image_sc_create_info =
+      util::find_extension<VkImageSwapchainCreateInfoKHR>(VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
+         pCreateInfo->pNext);
+
+   if (image_sc_create_info == nullptr || !device_data.layer_owns_swapchain(image_sc_create_info->swapchain))
+   {
+      return device_data.disp.CreateImage(device_data.device, pCreateInfo, pAllocator, pImage);
+   }
+
+   auto sc = reinterpret_cast<wsi::swapchain_base *>(image_sc_create_info->swapchain);
+   return sc->create_aliased_image_handle(pCreateInfo, pImage);
+}
+
+VKAPI_ATTR VkResult wsi_layer_vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount,
+                                                    const VkBindImageMemoryInfo *pBindInfos)
+{
+   auto &device_data = layer::device_private_data::get(device);
+
+   for (uint32_t i = 0; i < bindInfoCount; i++)
+   {
+      const VkBindImageMemorySwapchainInfoKHR *bind_sc_info = util::find_extension<VkBindImageMemorySwapchainInfoKHR>(
+         VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, pBindInfos[i].pNext);
+
+      if (bind_sc_info == nullptr || bind_sc_info->swapchain == VK_NULL_HANDLE ||
+          !device_data.layer_owns_swapchain(bind_sc_info->swapchain))
+      {
+         VkResult result = device_data.disp.BindImageMemory2KHR(device, 1, &pBindInfos[i]);
+         if (result != VK_SUCCESS)
+         {
+            return result;
+         }
+      }
+      else
+      {
+         auto sc = reinterpret_cast<wsi::swapchain_base *>(bind_sc_info->swapchain);
+         VkResult result = sc->bind_swapchain_image(device, &pBindInfos[i], bind_sc_info);
+         if (result != VK_SUCCESS)
+         {
+            return result;
+         }
+      }
+   }
+   return VK_SUCCESS;
+}
+
 } /* extern "C" */
index 0db72c8..155b3fa 100644 (file)
@@ -62,4 +62,10 @@ extern "C"
 
    VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo,
                                                         uint32_t *pImageIndex);
+
+   VKAPI_ATTR VkResult wsi_layer_vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkImage *pImage);
+
+   VKAPI_ATTR VkResult wsi_layer_vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount,
+                                                       const VkBindImageMemoryInfo *pBindInfos);
 }
diff --git a/util/helpers.hpp b/util/helpers.hpp
new file mode 100644 (file)
index 0000000..046a505
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 Arm Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @file helpers.hpp
+ *
+ * @brief Contains common utility functions used across the project.
+ */
+
+#pragma once
+
+#include <vulkan/vulkan.h>
+
+namespace util
+{
+template <typename T>
+const T *find_extension(VkStructureType sType, const void *pNext)
+{
+   auto entry = reinterpret_cast<const VkBaseOutStructure *>(pNext);
+   while (entry && entry->sType != sType)
+   {
+      entry = entry->pNext;
+   }
+   return reinterpret_cast<const T *>(entry);
+}
+} // namespace util
\ No newline at end of file
index ed9a882..b1033e9 100644 (file)
@@ -58,12 +58,17 @@ swapchain::~swapchain()
    teardown();
 }
 
-VkResult swapchain::create_image(VkImageCreateInfo image_create, wsi::swapchain_image &image)
+VkResult swapchain::create_aliased_image_handle(const VkImageCreateInfo *image_create_info, VkImage *image)
+{
+   return m_device_data.disp.CreateImage(m_device, image_create_info, get_allocation_callbacks(), image);
+}
+
+VkResult swapchain::create_and_bind_swapchain_image(VkImageCreateInfo image_create, wsi::swapchain_image &image)
 {
    VkResult res = VK_SUCCESS;
    const std::lock_guard<std::recursive_mutex> lock(m_image_status_mutex);
 
-   res = m_device_data.disp.CreateImage(m_device, &image_create, nullptr, &image.image);
+   res = m_device_data.disp.CreateImage(m_device, &image_create, get_allocation_callbacks(), &image.image);
    if (res != VK_SUCCESS)
    {
       return res;
@@ -100,7 +105,7 @@ VkResult swapchain::create_image(VkImageCreateInfo image_create, wsi::swapchain_
    image.data = reinterpret_cast<void *>(data);
    image.status = wsi::swapchain_image::FREE;
 
-   res = m_device_data.disp.AllocateMemory(m_device, &mem_info, nullptr, &data->memory);
+   res = m_device_data.disp.AllocateMemory(m_device, &mem_info, get_allocation_callbacks(), &data->memory);
    assert(VK_SUCCESS == res);
    if (res != VK_SUCCESS)
    {
@@ -154,7 +159,7 @@ void swapchain::destroy_image(wsi::swapchain_image &image)
       auto *data = reinterpret_cast<image_data *>(image.data);
       if (data->memory != VK_NULL_HANDLE)
       {
-         m_device_data.disp.FreeMemory(m_device, data->memory, nullptr);
+         m_device_data.disp.FreeMemory(m_device, data->memory, get_allocation_callbacks());
          data->memory = VK_NULL_HANDLE;
       }
       m_allocator.destroy(1, data);
@@ -176,5 +181,16 @@ VkResult swapchain::image_wait_present(swapchain_image &image, uint64_t timeout)
    return data->present_fence.wait_payload(timeout);
 }
 
+VkResult swapchain::bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
+                                         const VkBindImageMemorySwapchainInfoKHR *bind_sc_info)
+{
+   auto &device_data = layer::device_private_data::get(device);
+
+   const wsi::swapchain_image &swapchain_image = m_swapchain_images[bind_sc_info->imageIndex];
+   VkDeviceMemory memory = reinterpret_cast<image_data *>(swapchain_image.data)->memory;
+
+   return device_data.disp.BindImageMemory(device, bind_image_mem_info->image, memory, 0);
+}
+
 } /* namespace headless */
 } /* namespace wsi */
index ded7e15..cadfb86 100644 (file)
@@ -62,17 +62,28 @@ protected:
    };
 
    /**
-    * @brief Creates a new swapchain image.
+    * @brief Creates a VkImage handle.
     *
-    * @param image_create_info Data to be used to create the image.
+    * @param      image_create_info Data to be used to create the image.
+    * @param[out] image             Handle to the image.
     *
-    * @param image Handle to the image.
+    * @return If image creation is successful returns VK_SUCCESS, otherwise
+    * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_OUT_OF_HOST_MEMORY
+    * depending on the error that occured.
+    */
+   VkResult create_aliased_image_handle(const VkImageCreateInfo *image_create_info, VkImage *image) override;
+
+   /**
+    * @brief Creates and binds a new swapchain image.
+    *
+    * @param image_create_info Data to be used to create the image.
+    * @param image             Handle to the image.
     *
     * @return If image creation is successful returns VK_SUCCESS, otherwise
     * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED
     * depending on the error that occured.
     */
-   VkResult create_image(VkImageCreateInfo image_create_info, wsi::swapchain_image &image);
+   VkResult create_and_bind_swapchain_image(VkImageCreateInfo image_create_info, wsi::swapchain_image &image) override;
 
    /**
     * @brief Method to perform a present - just calls unpresent_image on headless
@@ -93,6 +104,19 @@ protected:
                                       uint32_t sem_count) override;
 
    VkResult image_wait_present(swapchain_image &image, uint64_t timeout) override;
+
+   /**
+    * @brief Bind image to a swapchain
+    *
+    * @param device              is the logical device that owns the images and memory.
+    * @param bind_image_mem_info details the image we want to bind.
+    * @param bind_sc_info        describes the swapchain memory to bind to.
+    *
+    * @return VK_SUCCESS on success, otherwise on failure VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY
+    * can be returned.
+    */
+   VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
+                                 const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) override;
 };
 
 } /* namespace headless */
index 90369a2..c35c0ff 100644 (file)
@@ -217,7 +217,7 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
 
    for (auto& img : m_swapchain_images)
    {
-      result = create_image(image_create_info, img);
+      result = create_and_bind_swapchain_image(image_create_info, img);
       if (result != VK_SUCCESS)
       {
          return result;
index 028f917..2443b86 100644 (file)
@@ -144,6 +144,31 @@ public:
       return m_allocator;
    }
 
+   /**
+    * @brief Creates a VkImage handle.
+    *
+    * @param      image_create_info Data to be used to create the image.
+    * @param[out] image             Handle to the image.
+    *
+    * @return If image creation is successful returns VK_SUCCESS, otherwise
+    * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_OUT_OF_HOST_MEMORY
+    * depending on the error that occured.
+    */
+   virtual VkResult create_aliased_image_handle(const VkImageCreateInfo *image_create_info, VkImage *image) = 0;
+
+   /**
+    * @brief Bind image to a swapchain
+    *
+    * @param device              is the logical device that owns the images and memory.
+    * @param bind_image_mem_info details the image we want to bind.
+    * @param bind_sc_info        describes the swapchain memory to bind to.
+    *
+    * @return VK_SUCCESS on success, otherwise on failure VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY
+    * can be returned.
+    */
+   virtual VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
+                                         const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) = 0;
+
 protected:
 
    layer::device_private_data &m_device_data;
@@ -306,17 +331,16 @@ protected:
    void teardown();
 
    /**
-    * @brief Creates a new swapchain image.
+    * @brief Creates and binds a new swapchain image.
     *
     * @param image_create_info Data to be used to create the image.
-    *
-    * @param image Handle to the image.
+    * @param image             Handle to the image.
     *
     * @return If image creation is successful returns VK_SUCCESS, otherwise
     * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED
     * depending on the error that occured.
     */
-   virtual VkResult create_image(VkImageCreateInfo image_create_info, swapchain_image &image) = 0;
+   virtual VkResult create_and_bind_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image) = 0;
 
    /**
     * @brief Method to present and image
index e442d9f..59b73e6 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "util/drm/drm_utils.hpp"
 #include "util/log.hpp"
+#include "util/helpers.hpp"
 
 #define MAX_PLANES 4
 
@@ -67,6 +68,7 @@ struct swapchain::wayland_image_data
    uint32_t num_planes;
 
    sync_fd_fence_sync present_fence;
+   bool is_disjoint;
 };
 
 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator,
@@ -78,8 +80,10 @@ swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCal
    , m_swapchain_queue(nullptr)
    , m_buffer_queue(nullptr)
    , m_wsi_allocator(nullptr)
+   , m_image_creation_parameters({}, {}, m_allocator, {}, {})
    , m_present_pending(false)
 {
+   m_image_creation_parameters.m_image_create_info.format = VK_FORMAT_UNDEFINED;
 }
 
 swapchain::~swapchain()
@@ -370,6 +374,35 @@ VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info
    return VK_SUCCESS;
 }
 
+VkResult swapchain::create_aliased_image_handle(const VkImageCreateInfo *image_create_info, VkImage *image)
+{
+   return m_device_data.disp.CreateImage(m_device, &m_image_creation_parameters.m_image_create_info,
+                                         get_allocation_callbacks(), image);
+}
+
+VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
+                                      util::vector<wsialloc_format> importable_formats,
+                                      wsialloc_format *allocated_format)
+{
+   bool is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
+   const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
+   wsialloc_allocate_info alloc_info = { importable_formats.data(), static_cast<unsigned>(importable_formats.size()),
+                                       image_create_info.extent.width, image_create_info.extent.height,
+                                       allocation_flags };
+   const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, allocated_format, image_data->stride,
+                                   image_data->buffer_fd, image_data->offset);
+   if (res != WSIALLOC_ERROR_NONE)
+   {
+      WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
+      if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
+      {
+         return VK_ERROR_FORMAT_NOT_SUPPORTED;
+      }
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+   }
+   return VK_SUCCESS;
+}
+
 VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image)
 {
    image_data->buffer = nullptr;
@@ -380,44 +413,54 @@ VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland
       image_data->memory[plane] = VK_NULL_HANDLE;
    }
 
+   bool is_disjoint = false;
    util::vector<wsialloc_format> importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
-   util::vector<uint64_t> exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
-   VkResult result = get_surface_compatible_formats(image_create_info, importable_formats, exportable_modifiers);
-   if (result != VK_SUCCESS)
+   auto &m_image_create_info = m_image_creation_parameters.m_image_create_info;
+   auto &m_allocated_format = m_image_creation_parameters.m_allocated_format;
+   if (m_image_create_info.format != VK_FORMAT_UNDEFINED)
    {
-      return result;
-   }
-
-   /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
-
-   if (importable_formats.empty())
-   {
-      WSI_LOG_ERROR("Export/Import not supported.");
-      return VK_ERROR_INITIALIZATION_FAILED;
+      is_disjoint = (m_image_create_info.flags & VK_IMAGE_CREATE_DISJOINT_BIT) == VK_IMAGE_CREATE_DISJOINT_BIT;
+      if (!importable_formats.try_push_back(m_allocated_format))
+      {
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
+      VkResult result = allocate_wsialloc(m_image_create_info, image_data, importable_formats, &m_allocated_format);
+      if (result != VK_SUCCESS)
+      {
+         return result;
+      }
+      for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
+      {
+         if (image_data->buffer_fd[plane] == -1)
+         {
+            break;
+         }
+         image_data->num_planes++;
+      }
    }
    else
    {
-      /* TODO: Handle Dedicated allocation bit. */
-      bool is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
-      const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
-      wsialloc_allocate_info alloc_info = { importable_formats.data(), static_cast<unsigned>(importable_formats.size()),
-                                            image_create_info.extent.width, image_create_info.extent.height,
-                                            allocation_flags };
+      util::vector<uint64_t> exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+      VkResult result = get_surface_compatible_formats(image_create_info, importable_formats, exportable_modifiers);
+      if (result != VK_SUCCESS)
+      {
+         return result;
+      }
+
+      /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
+      if (importable_formats.empty())
+      {
+         WSI_LOG_ERROR("Export/Import not supported.");
+         return VK_ERROR_INITIALIZATION_FAILED;
+      }
 
       wsialloc_format allocated_format = { 0 };
-      const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &allocated_format, image_data->stride,
-                                      image_data->buffer_fd, image_data->offset);
-      if (res != WSIALLOC_ERROR_NONE)
+      result = allocate_wsialloc(image_create_info, image_data, importable_formats, &allocated_format);
+      if (result != VK_SUCCESS)
       {
-         WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
-         if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
-         {
-            return VK_ERROR_FORMAT_NOT_SUPPORTED;
-         }
-         return VK_ERROR_OUT_OF_HOST_MEMORY;
+         return result;
       }
 
-      bool is_disjoint = false;
       for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
       {
          if (image_data->buffer_fd[plane] == -1)
@@ -431,107 +474,79 @@ VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland
          image_data->num_planes++;
       }
 
+      auto &image_layout = m_image_creation_parameters.m_image_layout;
+      if (!image_layout.try_resize(image_data->num_planes))
       {
-         util::vector<VkSubresourceLayout> image_layout(
-            util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
-         if (!image_layout.try_resize(image_data->num_planes))
-         {
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
-         }
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
 
-         for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
-         {
-            assert(image_data->stride[plane] >= 0);
-            image_layout[plane].offset = image_data->offset[plane];
-            image_layout[plane].rowPitch = static_cast<uint32_t>(image_data->stride[plane]);
-         }
+      for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
+      {
+         assert(image_data->stride[plane] >= 0);
+         image_layout[plane].offset = image_data->offset[plane];
+         image_layout[plane].rowPitch = static_cast<uint32_t>(image_data->stride[plane]);
+      }
 
-         if (is_disjoint)
-         {
-            image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
-         }
+      if (is_disjoint)
+      {
+         image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
+      }
 
-         VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {};
-         drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
-         drm_mod_info.pNext = image_create_info.pNext;
-         drm_mod_info.drmFormatModifier = allocated_format.modifier;
-         drm_mod_info.drmFormatModifierPlaneCount = image_data->num_planes;
-         drm_mod_info.pPlaneLayouts = image_layout.data();
+      auto &drm_mod_info = m_image_creation_parameters.m_drm_mod_info;
 
-         VkExternalMemoryImageCreateInfoKHR external_info = {};
-         external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
-         external_info.pNext = &drm_mod_info;
-         external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+      drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
+      drm_mod_info.pNext = image_create_info.pNext;
+      drm_mod_info.drmFormatModifier = allocated_format.modifier;
+      drm_mod_info.drmFormatModifierPlaneCount = image_data->num_planes;
+      drm_mod_info.pPlaneLayouts = image_layout.data();
 
-         VkImageCreateInfo image_info = image_create_info;
-         image_info.pNext = &external_info;
-         image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
-         result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image);
-      }
-      if (result != VK_SUCCESS)
-      {
-         WSI_LOG_ERROR("Image creation failed.");
-         return result;
-      }
-      {
-         if (is_disjoint)
-         {
-            util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(
-               util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
-            if (!bind_img_mem_infos.try_resize(image_data->num_planes))
-            {
-               return VK_ERROR_OUT_OF_HOST_MEMORY;
-            }
+      auto &external_info = m_image_creation_parameters.m_external_info;
+      external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
+      external_info.pNext = &drm_mod_info;
+      external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
 
-            util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(
-               util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
-            if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
-            {
-               return VK_ERROR_OUT_OF_HOST_MEMORY;
-            }
+      m_image_create_info = image_create_info;
+      m_image_create_info.pNext = &external_info;
+      m_image_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
 
-            for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
-            {
-               const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
-               if (fd_index == plane)
-               {
-                  result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
-                  if (result != VK_SUCCESS)
-                  {
-                     return result;
-                  }
-               }
-
-               bind_plane_mem_infos[plane].planeAspect = plane_flag_bits[plane];
-               bind_plane_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
-               bind_plane_mem_infos[plane].pNext = NULL;
-
-               bind_img_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
-               bind_img_mem_infos[plane].pNext = &bind_plane_mem_infos[plane];
-               bind_img_mem_infos[plane].image = *image;
-               bind_img_mem_infos[plane].memory = image_data->memory[fd_index];
-            }
+      m_allocated_format = allocated_format;
+   }
+   image_data->is_disjoint = is_disjoint;
+   VkResult result = m_device_data.disp.CreateImage(m_device, &m_image_create_info, get_allocation_callbacks(), image);
+   if (result != VK_SUCCESS)
+   {
+      WSI_LOG_ERROR("Image creation failed.");
+      return result;
+   }
 
-            result =
-               m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(), bind_img_mem_infos.data());
-         }
-         else
+   if (is_disjoint)
+   {
+      for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
+      {
+         const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
+         if (fd_index == plane)
          {
-            result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
+            VkResult result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
             if (result != VK_SUCCESS)
             {
                return result;
             }
-
-            result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0);
          }
       }
    }
+   else
+   {
+      VkResult result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
+      if (result != VK_SUCCESS)
+      {
+         return result;
+      }
+   }
 
-   return result;
+   return internal_bind_swapchain_image(m_device, image_data, *image);
 }
 
-VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image)
+VkResult swapchain::create_and_bind_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image)
 {
    /* Create image_data */
    auto image_data = m_allocator.create<wayland_image_data>(1);
@@ -565,7 +580,6 @@ VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_
    }
 
    zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get());
-
    for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
    {
       zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd[plane], plane,
@@ -815,5 +829,51 @@ VkResult swapchain::image_wait_present(swapchain_image &, uint64_t)
    return VK_SUCCESS;
 }
 
+VkResult swapchain::internal_bind_swapchain_image(VkDevice &device, wayland_image_data *image_data,
+                                                  const VkImage &image)
+{
+   auto &device_data = layer::device_private_data::get(device);
+   if (image_data->is_disjoint)
+   {
+      util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(m_allocator);
+      if (!bind_img_mem_infos.try_resize(image_data->num_planes))
+      {
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
+
+      util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(m_allocator);
+      if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
+      {
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
+
+      for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
+      {
+
+         bind_plane_mem_infos[plane].planeAspect = plane_flag_bits[plane];
+         bind_plane_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
+         bind_plane_mem_infos[plane].pNext = NULL;
+
+         bind_img_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
+         bind_img_mem_infos[plane].pNext = &bind_plane_mem_infos[plane];
+         bind_img_mem_infos[plane].image = image;
+         bind_img_mem_infos[plane].memory = image_data->memory[plane];
+         bind_img_mem_infos[plane].memoryOffset = image_data->offset[plane];
+      }
+
+      return device_data.disp.BindImageMemory2KHR(device, bind_img_mem_infos.size(), bind_img_mem_infos.data());
+   }
+
+   return device_data.disp.BindImageMemory(device, image, image_data->memory[0], image_data->offset[0]);
+}
+
+VkResult swapchain::bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
+                                         const VkBindImageMemorySwapchainInfoKHR *bind_sc_info)
+{
+   const wsi::swapchain_image &swapchain_image = m_swapchain_images[bind_sc_info->imageIndex];
+   auto image_data = reinterpret_cast<wayland_image_data *>(swapchain_image.data);
+   return internal_bind_swapchain_image(device, image_data, bind_image_mem_info->image);
+}
+
 } // namespace wayland
 } // namespace wsi
index 4f77176..4260866 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <wayland-client.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include "util/wsialloc/wsialloc.h"
+#include "util/custom_allocator.hpp"
 #include "wl_object_owner.hpp"
 #include "surface.hpp"
 
@@ -42,6 +43,26 @@ namespace wsi
 namespace wayland
 {
 
+struct image_creation_parameters
+{
+   VkImageCreateInfo m_image_create_info;
+   wsialloc_format m_allocated_format;
+   util::vector<VkSubresourceLayout> m_image_layout;
+   VkExternalMemoryImageCreateInfoKHR m_external_info;
+   VkImageDrmFormatModifierExplicitCreateInfoEXT m_drm_mod_info;
+
+   image_creation_parameters(VkImageCreateInfo image_create_info, wsialloc_format allocated_format,
+                             util::allocator allocator, VkExternalMemoryImageCreateInfoKHR external_info,
+                             VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info)
+      : m_image_create_info(image_create_info)
+      , m_allocated_format(allocated_format)
+      , m_image_layout(allocator)
+      , m_external_info(external_info)
+      , m_drm_mod_info(drm_mod_info)
+   {
+   }
+};
+
 class swapchain : public wsi::swapchain_base
 {
 public:
@@ -60,17 +81,32 @@ protected:
    VkResult init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo) override;
 
    /**
-    * @brief Creates a new swapchain image.
+    * @brief Creates a VkImage handle.
     *
-    * @param image_create_info Data to be used to create the image.
+    * The image_create_info argument is ignored in favour of m_image_create_info. This is because in
+    * order to guarantee a VkImage can be bound to any swapchain index, all swapchain images must
+    * be created with the same creation parameters.
     *
-    * @param image Handle to the image.
+    * @param      image_create_info Data to be used to create the image.
+    * @param[out] image             Handle to the image.
+    *
+    * @return If image creation is successful returns VK_SUCCESS, otherwise
+    * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_OUT_OF_HOST_MEMORY
+    * depending on the error that occured.
+    */
+   VkResult create_aliased_image_handle(const VkImageCreateInfo *image_create_info, VkImage *image) override;
+
+   /**
+    * @brief Creates and binds a new swapchain image.
+    *
+    * @param image_create_info Data to be used to create the image.
+    * @param image             Handle to the image.
     *
     * @return If image creation is successful returns VK_SUCCESS, otherwise
     * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED
     * depending on the error that occurred.
     */
-   VkResult create_image(VkImageCreateInfo image_create_info, swapchain_image &image) override;
+   VkResult create_and_bind_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image) override;
 
    /**
     * @brief Method to present an image
@@ -109,10 +145,27 @@ protected:
 
    VkResult image_wait_present(swapchain_image &image, uint64_t timeout) override;
 
+   /**
+    * @brief Bind image to a swapchain
+    *
+    * @param device              is the logical device that owns the images and memory.
+    * @param bind_image_mem_info details the image we want to bind.
+    * @param bind_sc_info        describes the swapchain memory to bind to.
+    *
+    * @return VK_SUCCESS on success, otherwise on failure VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY
+    * can be returned.
+    */
+   VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
+                                 const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) override;
+
 private:
    struct wayland_image_data;
 
    VkResult allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image);
+   VkResult allocate_wsialloc(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
+                              util::vector<wsialloc_format> importable_formats, wsialloc_format *allocated_format);
+   VkResult internal_bind_swapchain_image(VkDevice &device, wayland_image_data *swapchain_image,
+                                          const VkImage &image);
 
    struct wl_display *m_display;
    struct wl_surface *m_surface;
@@ -131,6 +184,11 @@ private:
    wsialloc_allocator *m_wsi_allocator;
 
    /**
+    * @brief Image creation parameters used for all swapchain images.
+    */
+   struct image_creation_parameters m_image_creation_parameters;
+
+   /**
     * @brief true when waiting for the server hint to present a buffer
     *
     * true if a buffer has been presented and we've not had a wl_surface::frame