diff --git a/layer/layer.cpp b/layer/layer.cpp index 8c444bf..be2f2a1 100644 --- a/layer/layer.cpp +++ b/layer/layer.cpp @@ -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); } diff --git a/layer/swapchain_api.cpp b/layer/swapchain_api.cpp index 474b891..8ee59a8 100644 --- a/layer/swapchain_api.cpp +++ b/layer/swapchain_api.cpp @@ -36,6 +36,7 @@ #include "private_data.hpp" #include "swapchain_api.hpp" +#include 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(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(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( + 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(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" */ diff --git a/layer/swapchain_api.hpp b/layer/swapchain_api.hpp index 0db72c8..155b3fa 100644 --- a/layer/swapchain_api.hpp +++ b/layer/swapchain_api.hpp @@ -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 index 0000000..046a505 --- /dev/null +++ b/util/helpers.hpp @@ -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 + +namespace util +{ +template +const T *find_extension(VkStructureType sType, const void *pNext) +{ + auto entry = reinterpret_cast(pNext); + while (entry && entry->sType != sType) + { + entry = entry->pNext; + } + return reinterpret_cast(entry); +} +} // namespace util \ No newline at end of file diff --git a/wsi/headless/swapchain.cpp b/wsi/headless/swapchain.cpp index ed9a882..b1033e9 100644 --- a/wsi/headless/swapchain.cpp +++ b/wsi/headless/swapchain.cpp @@ -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 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(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); 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(swapchain_image.data)->memory; + + return device_data.disp.BindImageMemory(device, bind_image_mem_info->image, memory, 0); +} + } /* namespace headless */ } /* namespace wsi */ diff --git a/wsi/headless/swapchain.hpp b/wsi/headless/swapchain.hpp index ded7e15..cadfb86 100644 --- a/wsi/headless/swapchain.hpp +++ b/wsi/headless/swapchain.hpp @@ -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[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. + * @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 */ diff --git a/wsi/swapchain_base.cpp b/wsi/swapchain_base.cpp index 90369a2..c35c0ff 100644 --- a/wsi/swapchain_base.cpp +++ b/wsi/swapchain_base.cpp @@ -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; diff --git a/wsi/swapchain_base.hpp b/wsi/swapchain_base.hpp index 028f917..2443b86 100644 --- a/wsi/swapchain_base.hpp +++ b/wsi/swapchain_base.hpp @@ -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 diff --git a/wsi/wayland/swapchain.cpp b/wsi/wayland/swapchain.cpp index e442d9f..59b73e6 100644 --- a/wsi/wayland/swapchain.cpp +++ b/wsi/wayland/swapchain.cpp @@ -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 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(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(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 importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); - util::vector 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(importable_formats.size()), - image_create_info.extent.width, image_create_info.extent.height, - allocation_flags }; - - 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) + util::vector 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) { - WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast(res)); - if (res == WSIALLOC_ERROR_NOT_SUPPORTED) - { - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - return VK_ERROR_OUT_OF_HOST_MEMORY; + 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 }; + result = allocate_wsialloc(image_create_info, image_data, importable_formats, &allocated_format); + if (result != VK_SUCCESS) + { + 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 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; - } - - 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(image_data->stride[plane]); - } - - 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(); - - 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; - - 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); + return VK_ERROR_OUT_OF_HOST_MEMORY; } - if (result != VK_SUCCESS) + + for (uint32_t plane = 0; plane < image_data->num_planes; plane++) { - WSI_LOG_ERROR("Image creation failed."); - return result; + assert(image_data->stride[plane] >= 0); + image_layout[plane].offset = image_data->offset[plane]; + image_layout[plane].rowPitch = static_cast(image_data->stride[plane]); } + + if (is_disjoint) { - if (is_disjoint) + image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT; + } + + auto &drm_mod_info = m_image_creation_parameters.m_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 &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; + + 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; + + 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; + } + + 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) { - util::vector 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; - } - - util::vector 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; - } - - 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]; - } - - result = - m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(), bind_img_mem_infos.data()); - } - else - { - 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(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 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 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(swapchain_image.data); + return internal_bind_swapchain_image(device, image_data, bind_image_mem_info->image); +} + } // namespace wayland } // namespace wsi diff --git a/wsi/wayland/swapchain.hpp b/wsi/wayland/swapchain.hpp index 4f77176..4260866 100644 --- a/wsi/wayland/swapchain.hpp +++ b/wsi/wayland/swapchain.hpp @@ -34,6 +34,7 @@ extern "C" { #include #include #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 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. + * + * 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_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. + * @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 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; @@ -130,6 +183,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 *