From c7be05e3ff0d8ef022310d39cc6681acd82eabd4 Mon Sep 17 00:00:00 2001 From: Rosen Zhelev Date: Wed, 21 Jul 2021 20:19:52 +0100 Subject: [PATCH] Implement objects associated with VkSurface Defines an abstract wsi::surface object to be implemented by each WSI backend. This object is then associated with the corresponding VkSurface object in the instance specific data. To keep track of these objects the layer now intercepts vkDestroySurfaceKHR, while specific surface creation entrypoints are intercepted by individual WSI backends. In addition this change should allow for fixing incompatibility issues with layers that wrap VkSurface which breaks casting to the Loader's ICD VkSurface type. Make greater use of util::unique_ptr and allow for such pointers to be constructable when casting derived types. Change-Id: I163e9c47088ad9989583ebce1319b1fc05559d73 Signed-off-by: Rosen Zhelev --- CMakeLists.txt | 2 + layer/layer.cpp | 1 + layer/private_data.cpp | 55 ++++++++++++++++++++++-- layer/private_data.hpp | 57 +++++++++++++++++++++++++ layer/surface_api.cpp | 17 ++++++-- layer/surface_api.hpp | 6 +++ layer/swapchain_api.cpp | 12 ++---- util/custom_allocator.hpp | 15 ++++--- wsi/headless/surface.cpp | 51 ++++++++++++++++++++++ wsi/headless/surface.hpp | 48 +++++++++++++++++++++ wsi/headless/surface_properties.cpp | 35 +++++++++++++++ wsi/headless/surface_properties.hpp | 2 + wsi/surface.hpp | 66 +++++++++++++++++++++++++++++ wsi/surface_properties.hpp | 7 ++- wsi/wayland/surface.cpp | 51 ++++++++++++++++++++++ wsi/wayland/surface.hpp | 49 +++++++++++++++++++++ wsi/wayland/surface_properties.cpp | 28 ++++++++++++ wsi/wsi_factory.cpp | 48 +++++++++------------ wsi/wsi_factory.hpp | 9 ++-- 19 files changed, 500 insertions(+), 59 deletions(-) create mode 100644 wsi/headless/surface.cpp create mode 100644 wsi/headless/surface.hpp create mode 100644 wsi/surface.hpp create mode 100644 wsi/wayland/surface.cpp create mode 100644 wsi/wayland/surface.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 031142d..4a84c88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,7 @@ endif() if(BUILD_WSI_WAYLAND) add_library(wayland_wsi STATIC wsi/wayland/surface_properties.cpp + wsi/wayland/surface.cpp wsi/wayland/wl_helpers.cpp wsi/wayland/swapchain.cpp) @@ -153,6 +154,7 @@ add_library(${PROJECT_NAME} SHARED wsi/swapchain_base.cpp wsi/wsi_factory.cpp wsi/headless/surface_properties.cpp + wsi/headless/surface.cpp wsi/headless/swapchain.cpp) target_compile_definitions(${PROJECT_NAME} PRIVATE ${WSI_DEFINES}) target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/layer/layer.cpp b/layer/layer.cpp index cff12b5..9140131 100644 --- a/layer/layer.cpp +++ b/layer/layer.cpp @@ -461,6 +461,7 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetInstance GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceFormatsKHR); GET_PROC_ADDR(vkGetPhysicalDeviceSurfacePresentModesKHR); + GET_PROC_ADDR(vkDestroySurfaceKHR); GET_PROC_ADDR(vkEnumerateDeviceExtensionProperties); GET_PROC_ADDR(vkEnumerateInstanceLayerProperties); diff --git a/layer/private_data.cpp b/layer/private_data.cpp index c4e9a3d..b47e7a7 100644 --- a/layer/private_data.cpp +++ b/layer/private_data.cpp @@ -24,6 +24,7 @@ #include "private_data.hpp" #include "wsi/wsi_factory.hpp" +#include "wsi/surface.hpp" #include "util/unordered_map.hpp" #include "util/log.hpp" @@ -81,6 +82,7 @@ instance_private_data::instance_private_data(const instance_dispatch_table &tabl , SetInstanceLoaderData(set_loader_data) , enabled_layer_platforms(enabled_layer_platforms) , allocator(alloc) + , surfaces(alloc) { } @@ -172,15 +174,60 @@ instance_private_data &instance_private_data::get(VkPhysicalDevice phys_dev) return get_instance_private_data(phys_dev); } -static VkIcdWsiPlatform get_platform_of_surface(VkSurfaceKHR surface) +VkResult instance_private_data::add_surface(VkSurfaceKHR vk_surface, util::unique_ptr &wsi_surface) { - VkIcdSurfaceBase *surface_base = reinterpret_cast(surface); - return surface_base->platform; + scoped_mutex lock(surfaces_lock); + + auto it = surfaces.find(vk_surface); + if (it != surfaces.end()) + { + WSI_LOG_WARNING("Hash collision when adding new surface (%p). Old surface is replaced.", + reinterpret_cast(vk_surface)); + surfaces.erase(it); + } + + auto result = surfaces.try_insert(std::make_pair(vk_surface, nullptr)); + if (result.has_value()) + { + assert(result->second); + result->first->second = wsi_surface.release(); + return VK_SUCCESS; + } + + return VK_ERROR_OUT_OF_HOST_MEMORY; +} + +wsi::surface *instance_private_data::get_surface(VkSurfaceKHR vk_surface) +{ + scoped_mutex lock(surfaces_lock); + auto it = surfaces.find(vk_surface); + if (it != surfaces.end()) + { + return it->second; + } + + return nullptr; +} + +void instance_private_data::remove_surface(VkSurfaceKHR vk_surface, const util::allocator &alloc) +{ + scoped_mutex lock(surfaces_lock); + auto it = surfaces.find(vk_surface); + if (it != surfaces.end()) + { + alloc.destroy(1, it->second); + surfaces.erase(it); + } + /* Failing to find a surface is not an error. It could have been created by a WSI extension, which is not handled + * by this layer. + */ } bool instance_private_data::does_layer_support_surface(VkSurfaceKHR surface) { - return enabled_layer_platforms.contains(get_platform_of_surface(surface)); + scoped_mutex lock(surfaces_lock); + auto it = surfaces.find(surface); + return it != surfaces.end(); } void instance_private_data::destroy(instance_private_data *instance_data) diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 205112c..eef8e35 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -27,10 +27,12 @@ #include "util/platform_set.hpp" #include "util/custom_allocator.hpp" #include "util/unordered_set.hpp" +#include "util/unordered_map.hpp" #include #include #include +#include #include #include @@ -39,6 +41,12 @@ using scoped_mutex = std::lock_guard; +/** Forward declare stored objects */ +namespace wsi +{ +class surface; +} + namespace layer { @@ -57,6 +65,9 @@ namespace layer OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \ OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \ OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \ + OPTIONAL(CreateHeadlessSurfaceEXT) \ + OPTIONAL(CreateWaylandSurfaceKHR) \ + OPTIONAL(DestroySurfaceKHR) \ OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \ OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \ OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) @@ -190,6 +201,39 @@ public: */ static instance_private_data &get(VkPhysicalDevice phys_dev); + /** + * @brief Associate a VkSurface with a WSI surface object. + * + * @param vk_surface The VkSurface object created by the Vulkan implementation. + * @param wsi_surface The WSI layer object representing the surface. + * + * @return VK_SUCCESS or VK_ERROR_OUT_OF_HOST_MEMORY + * + * @note On success this transfers ownership of the WSI surface. The WSI surface is then explicitly destroyed by the + * user with @ref remove_surface + */ + VkResult add_surface(VkSurfaceKHR vk_surface, util::unique_ptr &wsi_surface); + + /** + * @brief Returns any associated WSI surface to the VkSurface. + * + * @param vk_surface The VkSurface object queried for association. + * + * @return nullptr or a raw pointer to the WSI surface. + * + * @note This returns a raw pointer that does not change any ownership. The user is responsible for ensuring that the + * pointer is valid as it explicitly controls the lifetime of the object. + */ + wsi::surface *get_surface(VkSurfaceKHR vk_surface); + + /** + * @brief Destroys any VkSurface associated WSI surface. + * + * @param vk_surface The VkSurface to check for associations. + * @param alloc The allocator to use if destroying a @ref wsi::surface object. + */ + void remove_surface(VkSurfaceKHR vk_surface, const util::allocator &alloc); + /** * @brief Get the set of enabled platforms that are also supported by the layer. */ @@ -263,6 +307,19 @@ private: const PFN_vkSetInstanceLoaderData SetInstanceLoaderData; const util::wsi_platform_set enabled_layer_platforms; const util::allocator allocator; + + /** + * @brief Container for all VkSurface objects tracked and supported by the Layer's WSI implementation. + * + * Uses plain pointers to store surface data as the lifetime of the object is explicitly controlled by the Vulkan + * application. The application may also use different but compatible host allocators on creation and destruction. + */ + util::unordered_map surfaces; + + /** + * @brief Lock for thread safe access to @ref surfaces + */ + std::mutex surfaces_lock; }; /** diff --git a/layer/surface_api.cpp b/layer/surface_api.cpp index 98c0613..7ee582a 100644 --- a/layer/surface_api.cpp +++ b/layer/surface_api.cpp @@ -39,7 +39,7 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysic auto &instance = layer::instance_private_data::get(physicalDevice); if (instance.should_layer_handle_surface(physicalDevice, surface)) { - wsi::surface_properties *props = wsi::get_surface_properties(surface); + wsi::surface_properties *props = wsi::get_surface_properties(instance, surface); assert(props != nullptr); return props->get_surface_capabilities(physicalDevice, surface, pSurfaceCapabilities); } @@ -61,7 +61,7 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDev auto &instance = layer::instance_private_data::get(physicalDevice); if (instance.should_layer_handle_surface(physicalDevice, surface)) { - wsi::surface_properties *props = wsi::get_surface_properties(surface); + wsi::surface_properties *props = wsi::get_surface_properties(instance, surface); assert(props != nullptr); return props->get_surface_formats(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); } @@ -81,7 +81,7 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysic auto &instance = layer::instance_private_data::get(physicalDevice); if (instance.should_layer_handle_surface(physicalDevice, surface)) { - wsi::surface_properties *props = wsi::get_surface_properties(surface); + wsi::surface_properties *props = wsi::get_surface_properties(instance, surface); assert(props != nullptr); return props->get_surface_present_modes(physicalDevice, surface, pPresentModeCount, pPresentModes); } @@ -107,4 +107,15 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDev return instance.disp.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); } +VKAPI_ATTR void wsi_layer_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, + const VkAllocationCallbacks *pAllocator) +{ + auto &instance_data = layer::instance_private_data::get(instance); + + instance_data.disp.DestroySurfaceKHR(instance, surface, pAllocator); + + instance_data.remove_surface( + surface, util::allocator{ instance_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, pAllocator }); +} + } /* extern "C" */ diff --git a/layer/surface_api.hpp b/layer/surface_api.hpp index 9dc4636..b514260 100644 --- a/layer/surface_api.hpp +++ b/layer/surface_api.hpp @@ -61,4 +61,10 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysic VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported); + +/** + * @brief Implements vkDestroySurfaceKHR Vulkan entrypoint. + */ +VKAPI_ATTR void wsi_layer_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, + const VkAllocationCallbacks *pAllocator); } diff --git a/layer/swapchain_api.cpp b/layer/swapchain_api.cpp index f10c0e3..474b891 100644 --- a/layer/swapchain_api.cpp +++ b/layer/swapchain_api.cpp @@ -56,7 +56,7 @@ VKAPI_ATTR VkResult wsi_layer_vkCreateSwapchainKHR(VkDevice device, return device_data.disp.CreateSwapchainKHR(device_data.device, pSwapchainCreateInfo, pAllocator, pSwapchain); } - wsi::swapchain_base *sc = wsi::allocate_surface_swapchain(surface, device_data, pAllocator); + auto sc = wsi::allocate_surface_swapchain(surface, device_data, pAllocator); if (sc == nullptr) { return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -65,20 +65,16 @@ VKAPI_ATTR VkResult wsi_layer_vkCreateSwapchainKHR(VkDevice device, VkResult result = sc->init(device, pSwapchainCreateInfo); if (result != VK_SUCCESS) { - /* Error occured during initialization, need to free allocated memory. */ - wsi::destroy_surface_swapchain(sc, device_data, pAllocator); return result; } - auto vulkan_swapchain = reinterpret_cast(sc); - result = device_data.add_layer_swapchain(vulkan_swapchain); + result = device_data.add_layer_swapchain(reinterpret_cast(sc.get())); if (result != VK_SUCCESS) { - wsi::destroy_surface_swapchain(sc, device_data, pAllocator); return result; } - *pSwapchain = vulkan_swapchain; + *pSwapchain = reinterpret_cast(sc.release()); return result; } @@ -214,7 +210,7 @@ VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDevicePresentRectanglesKHR(VkPhysical } VkResult result; - wsi::surface_properties *props = wsi::get_surface_properties(surface); + wsi::surface_properties *props = wsi::get_surface_properties(instance, surface); assert(props); if (nullptr == pRects) diff --git a/util/custom_allocator.hpp b/util/custom_allocator.hpp index 78be093..bb6a7a0 100644 --- a/util/custom_allocator.hpp +++ b/util/custom_allocator.hpp @@ -246,20 +246,21 @@ void allocator::destroy(size_t num_objects, T *objects) const noexcept * destroy method. */ template -class deleter +class deleter : public allocator { public: - deleter(allocator allocator) - : m_allocator(std::move(allocator)) + deleter() + : deleter(allocator::get_generic()) + {} + + deleter(allocator alloc) + : allocator(std::move(alloc)) {} void operator()(T *object) { - m_allocator.destroy(1, object); + destroy(1, object); } - -private: - allocator m_allocator; }; /** diff --git a/wsi/headless/surface.cpp b/wsi/headless/surface.cpp new file mode 100644 index 0000000..5a7daf7 --- /dev/null +++ b/wsi/headless/surface.cpp @@ -0,0 +1,51 @@ +/* + * 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 + * @brief Implementation of a headless WSI Surface + */ + +#include "surface.hpp" +#include "swapchain.hpp" +#include "surface_properties.hpp" + +namespace wsi +{ +namespace headless +{ + +wsi::surface_properties &surface::get_properties() +{ + return surface_properties::get_instance(); +} + +util::unique_ptr surface::allocate_swapchain(layer::device_private_data &dev_data, + const VkAllocationCallbacks *allocator) +{ + util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, allocator }; + return util::unique_ptr(alloc.make_unique(dev_data, allocator)); +} + +} /* namespace headless */ +} /* namespace wsi */ \ No newline at end of file diff --git a/wsi/headless/surface.hpp b/wsi/headless/surface.hpp new file mode 100644 index 0000000..049f7ce --- /dev/null +++ b/wsi/headless/surface.hpp @@ -0,0 +1,48 @@ +/* + * 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 + * @brief Definitions for a headless WSI Surface + */ + +#pragma once + +#include "wsi/surface.hpp" + +namespace wsi +{ +namespace headless +{ + +class surface : public wsi::surface +{ +public: + surface() = default; + wsi::surface_properties &get_properties() override; + util::unique_ptr allocate_swapchain(layer::device_private_data &dev_data, + const VkAllocationCallbacks *allocator) override; +}; + +} /* namespace headless */ +} /* namespace wsi */ \ No newline at end of file diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index e030e7b..da63ef0 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,7 @@ #include #include "surface_properties.hpp" +#include "surface.hpp" #define UNUSED(x) ((void)(x)) @@ -168,5 +170,38 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical return res; } +extern "C" VKAPI_ATTR VkResult VKAPI_CALL CreateHeadlessSurfaceEXT(VkInstance instance, + const VkHeadlessSurfaceCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + auto &instance_data = layer::instance_private_data::get(instance); + util::allocator allocator{ instance_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, pAllocator }; + auto wsi_surface = util::unique_ptr(allocator.make_unique()); + if (wsi_surface == nullptr) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + VkResult res = instance_data.disp.CreateHeadlessSurfaceEXT(instance, pCreateInfo, pAllocator, pSurface); + if (res == VK_SUCCESS) + { + res = instance_data.add_surface(*pSurface, wsi_surface); + if (res != VK_SUCCESS) + { + instance_data.disp.DestroySurfaceKHR(instance, *pSurface, pAllocator); + } + } + return res; +} + +PFN_vkVoidFunction surface_properties::get_proc_addr(const char *name) +{ + if (strcmp(name, "vkCreateHeadlessSurfaceEXT") == 0) + { + return reinterpret_cast(CreateHeadlessSurfaceEXT); + } + return nullptr; +} + } /* namespace headless */ } /* namespace wsi */ diff --git a/wsi/headless/surface_properties.hpp b/wsi/headless/surface_properties.hpp index 737f2ca..539b234 100644 --- a/wsi/headless/surface_properties.hpp +++ b/wsi/headless/surface_properties.hpp @@ -45,6 +45,8 @@ public: VkResult get_surface_present_modes(VkPhysicalDevice physical_device, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) override; + PFN_vkVoidFunction get_proc_addr(const char *name) override; + static surface_properties &get_instance(); }; diff --git a/wsi/surface.hpp b/wsi/surface.hpp new file mode 100644 index 0000000..c879cce --- /dev/null +++ b/wsi/surface.hpp @@ -0,0 +1,66 @@ +/* + * 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 + * @brief Vulkan WSI surface interfaces. + */ + +#pragma once + +#include +#include "surface_properties.hpp" +#include "swapchain_base.hpp" + +namespace wsi +{ + +/** + * @brief A generic WSI representation of a VkSurface. + * + * The association between these objects and VkSurfaces is kept in the VkInstance private data. + */ +class surface +{ +public: + virtual ~surface() = default; + + /** + * @brief Returns a @ref surface_properties implementation that can be specific to the VkSurface represented. + */ + virtual surface_properties &get_properties() = 0; + + /** + * @brief Allocates a swapchain for the VkSurface type represented. + * + * @param dev_data The VkDevice associated private date. + * @param allocator Allocation callbacks to use for host memory. + * + * @return nullptr on failure otherwise a constructed swapchain. + */ + virtual util::unique_ptr allocate_swapchain(layer::device_private_data &dev_data, + const VkAllocationCallbacks *allocator) = 0; +}; + +} /* namespace wsi */ \ No newline at end of file diff --git a/wsi/surface_properties.hpp b/wsi/surface_properties.hpp index 477fb18..b9d032f 100644 --- a/wsi/surface_properties.hpp +++ b/wsi/surface_properties.hpp @@ -71,11 +71,10 @@ public: /** * @brief Implements vkGetProcAddr for entrypoints specific to the surface type. + * + * At least the specific VkSurface creation entrypoint must be intercepted. */ - virtual PFN_vkVoidFunction get_proc_addr(const char *name) - { - return nullptr; - } + virtual PFN_vkVoidFunction get_proc_addr(const char *name) = 0; }; } /* namespace wsi */ diff --git a/wsi/wayland/surface.cpp b/wsi/wayland/surface.cpp new file mode 100644 index 0000000..f70d3d5 --- /dev/null +++ b/wsi/wayland/surface.cpp @@ -0,0 +1,51 @@ +/* + * 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 + * @brief Implementation of a Wayland WSI Surface + */ + +#include "surface.hpp" +#include "swapchain.hpp" +#include "surface_properties.hpp" + +namespace wsi +{ +namespace wayland +{ + +wsi::surface_properties &surface::get_properties() +{ + return surface_properties::get_instance(); +} + +util::unique_ptr surface::allocate_swapchain(layer::device_private_data &dev_data, + const VkAllocationCallbacks *allocator) +{ + util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, allocator }; + return util::unique_ptr(alloc.make_unique(dev_data, allocator)); +} + +} // namespace wayland +} // namespace wsi \ No newline at end of file diff --git a/wsi/wayland/surface.hpp b/wsi/wayland/surface.hpp new file mode 100644 index 0000000..12c1462 --- /dev/null +++ b/wsi/wayland/surface.hpp @@ -0,0 +1,49 @@ +/* + * 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 + * @brief Definitions for a Wayland WSI Surface + */ + +#pragma once + +#include "wsi/surface.hpp" + +namespace wsi +{ +namespace wayland +{ + +class surface : public wsi::surface +{ +public: + surface() = default; + + wsi::surface_properties &get_properties() override; + util::unique_ptr allocate_swapchain(layer::device_private_data &dev_data, + const VkAllocationCallbacks *allocator) override; +}; + +} // namespace wayland +} // namespace wsi \ No newline at end of file diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index 45ea124..2da5e1d 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -33,6 +33,7 @@ #include #include #include "surface_properties.hpp" +#include "surface.hpp" #include "layer/private_data.hpp" #include "wl_helpers.hpp" #include "wl_object_owner.hpp" @@ -281,13 +282,40 @@ VkBool32 GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physica return VK_TRUE; } +extern "C" VkResult CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) +{ + auto &instance_data = layer::instance_private_data::get(instance); + util::allocator allocator{ instance_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, pAllocator }; + auto wsi_surface = util::unique_ptr(allocator.make_unique()); + if (wsi_surface == nullptr) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + VkResult res = instance_data.disp.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); + if (res == VK_SUCCESS) + { + res = instance_data.add_surface(*pSurface, wsi_surface); + if (res != VK_SUCCESS) + { + instance_data.disp.DestroySurfaceKHR(instance, *pSurface, pAllocator); + } + } + return res; +} + PFN_vkVoidFunction surface_properties::get_proc_addr(const char *name) { if (strcmp(name, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") == 0) { return reinterpret_cast(GetPhysicalDeviceWaylandPresentationSupportKHR); } + else if (strcmp(name, "vkCreateWaylandSurfaceKHR") == 0) + { + return reinterpret_cast(CreateWaylandSurfaceKHR); + } return nullptr; } + } // namespace wayland } // namespace wsi diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp index a34f1fb..0a85a15 100644 --- a/wsi/wsi_factory.cpp +++ b/wsi/wsi_factory.cpp @@ -28,8 +28,8 @@ */ #include "wsi_factory.hpp" +#include "surface.hpp" #include "headless/surface_properties.hpp" -#include "headless/swapchain.hpp" #include #include @@ -41,7 +41,6 @@ #if BUILD_WSI_WAYLAND #include #include "wayland/surface_properties.hpp" -#include "wayland/swapchain.hpp" #endif namespace wsi @@ -73,36 +72,27 @@ static surface_properties *get_surface_properties(VkIcdWsiPlatform platform) } } -surface_properties *get_surface_properties(VkSurfaceKHR surface) +surface_properties *get_surface_properties(layer::instance_private_data &instance_data, VkSurfaceKHR surface) { - VkIcdSurfaceBase *surface_base = reinterpret_cast(surface); + auto *wsi_surface = instance_data.get_surface(surface); - return get_surface_properties(surface_base->platform); -} - -template -static swapchain_base *allocate_swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator) -{ - util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, pAllocator }; - return alloc.create(1, dev_data, pAllocator); -} - -swapchain_base *allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_private_data &dev_data, - const VkAllocationCallbacks *pAllocator) -{ - VkIcdSurfaceBase *surface_base = reinterpret_cast(surface); - - switch (surface_base->platform) + if (wsi_surface) { - case VK_ICD_WSI_PLATFORM_HEADLESS: - return allocate_swapchain(dev_data, pAllocator); -#if BUILD_WSI_WAYLAND - case VK_ICD_WSI_PLATFORM_WAYLAND: - return allocate_swapchain(dev_data, pAllocator); -#endif - default: - return nullptr; + return &wsi_surface->get_properties(); } + + return nullptr; +} + +util::unique_ptr allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_private_data &dev_data, + const VkAllocationCallbacks *pAllocator) +{ + wsi::surface *wsi_surface = dev_data.instance_data.get_surface(surface); + if (wsi_surface) + { + return wsi_surface->allocate_swapchain(dev_data, pAllocator); + } + return nullptr; } util::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo *pCreateInfo) @@ -195,7 +185,7 @@ void destroy_surface_swapchain(swapchain_base *swapchain, layer::device_private_ { assert(swapchain); - util::allocator alloc{ swapchain->get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, pAllocator }; + util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, pAllocator }; alloc.destroy(1, swapchain); } diff --git a/wsi/wsi_factory.hpp b/wsi/wsi_factory.hpp index 1331d63..b913489 100644 --- a/wsi/wsi_factory.hpp +++ b/wsi/wsi_factory.hpp @@ -41,11 +41,12 @@ namespace wsi /** * @brief Obtains the surface properties for the specific surface type. * - * @param surface The surface for which to get the properties. + * @param instance_data The instance specific data. + * @param surface The surface for which to get the properties. * * @return nullptr if surface type is unsupported. */ -surface_properties *get_surface_properties(VkSurfaceKHR surface); +surface_properties *get_surface_properties(layer::instance_private_data &instance_data, VkSurfaceKHR surface); /** * @brief Allocates a surface specific swapchain. @@ -56,8 +57,8 @@ surface_properties *get_surface_properties(VkSurfaceKHR surface); * * @return nullptr on failure. */ -swapchain_base *allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_private_data &dev_data, - const VkAllocationCallbacks *pAllocator); +util::unique_ptr allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_private_data &dev_data, + const VkAllocationCallbacks *pAllocator); /** * @brief Destroys a swapchain and frees memory. Used with @ref allocate_surface_swapchain.