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.