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 <rosen.zhelev@arm.com>
This commit is contained in:
Rosen Zhelev 2021-07-21 20:19:52 +01:00
parent feb2445f2a
commit c7be05e3ff
19 changed files with 500 additions and 59 deletions

View file

@ -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

View file

@ -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);

View file

@ -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> &wsi_surface)
{
VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(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<void *>(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<wsi::surface>(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)

View file

@ -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 <vulkan/vulkan.h>
#include <vulkan/vk_layer.h>
#include <vulkan/vk_icd.h>
#include <vulkan/vulkan_wayland.h>
#include <memory>
#include <unordered_set>
@ -39,6 +41,12 @@
using scoped_mutex = std::lock_guard<std::mutex>;
/** 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> &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<VkSurfaceKHR, wsi::surface *> surfaces;
/**
* @brief Lock for thread safe access to @ref surfaces
*/
std::mutex surfaces_lock;
};
/**

View file

@ -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" */

View file

@ -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);
}

View file

@ -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<VkSwapchainKHR>(sc);
result = device_data.add_layer_swapchain(vulkan_swapchain);
result = device_data.add_layer_swapchain(reinterpret_cast<VkSwapchainKHR>(sc.get()));
if (result != VK_SUCCESS)
{
wsi::destroy_surface_swapchain(sc, device_data, pAllocator);
return result;
}
*pSwapchain = vulkan_swapchain;
*pSwapchain = reinterpret_cast<VkSwapchainKHR>(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)

View file

@ -246,20 +246,21 @@ void allocator::destroy(size_t num_objects, T *objects) const noexcept
* destroy method.
*/
template <typename T>
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<T>(1, object);
destroy<T>(1, object);
}
private:
allocator m_allocator;
};
/**

51
wsi/headless/surface.cpp Normal file
View file

@ -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<swapchain_base> 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<swapchain_base>(alloc.make_unique<swapchain>(dev_data, allocator));
}
} /* namespace headless */
} /* namespace wsi */

48
wsi/headless/surface.hpp Normal file
View file

@ -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<swapchain_base> allocate_swapchain(layer::device_private_data &dev_data,
const VkAllocationCallbacks *allocator) override;
};
} /* namespace headless */
} /* namespace wsi */

View file

@ -26,6 +26,7 @@
#include <array>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <map>
#include <mutex>
@ -35,6 +36,7 @@
#include <layer/private_data.hpp>
#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<wsi::surface>(allocator.make_unique<surface>());
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<PFN_vkVoidFunction>(CreateHeadlessSurfaceEXT);
}
return nullptr;
}
} /* namespace headless */
} /* namespace wsi */

View file

@ -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();
};

66
wsi/surface.hpp Normal file
View file

@ -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 <vulkan/vulkan.h>
#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<swapchain_base> allocate_swapchain(layer::device_private_data &dev_data,
const VkAllocationCallbacks *allocator) = 0;
};
} /* namespace wsi */

View file

@ -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 */

51
wsi/wayland/surface.cpp Normal file
View file

@ -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<swapchain_base> 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<swapchain_base>(alloc.make_unique<swapchain>(dev_data, allocator));
}
} // namespace wayland
} // namespace wsi

49
wsi/wayland/surface.hpp Normal file
View file

@ -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<swapchain_base> allocate_swapchain(layer::device_private_data &dev_data,
const VkAllocationCallbacks *allocator) override;
};
} // namespace wayland
} // namespace wsi

View file

@ -33,6 +33,7 @@
#include <array>
#include <cstring>
#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<wsi::surface>(allocator.make_unique<surface>());
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<PFN_vkVoidFunction>(GetPhysicalDeviceWaylandPresentationSupportKHR);
}
else if (strcmp(name, "vkCreateWaylandSurfaceKHR") == 0)
{
return reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR);
}
return nullptr;
}
} // namespace wayland
} // namespace wsi

View file

@ -28,8 +28,8 @@
*/
#include "wsi_factory.hpp"
#include "surface.hpp"
#include "headless/surface_properties.hpp"
#include "headless/swapchain.hpp"
#include <cassert>
#include <cstdlib>
@ -41,7 +41,6 @@
#if BUILD_WSI_WAYLAND
#include <vulkan/vulkan_wayland.h>
#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<VkIcdSurfaceBase *>(surface);
auto *wsi_surface = instance_data.get_surface(surface);
return get_surface_properties(surface_base->platform);
}
template <typename swapchain_type>
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<swapchain_type>(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<VkIcdSurfaceBase *>(surface);
switch (surface_base->platform)
if (wsi_surface)
{
case VK_ICD_WSI_PLATFORM_HEADLESS:
return allocate_swapchain<wsi::headless::swapchain>(dev_data, pAllocator);
#if BUILD_WSI_WAYLAND
case VK_ICD_WSI_PLATFORM_WAYLAND:
return allocate_swapchain<wsi::wayland::swapchain>(dev_data, pAllocator);
#endif
default:
return nullptr;
return &wsi_surface->get_properties();
}
return nullptr;
}
util::unique_ptr<swapchain_base> 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);
}

View file

@ -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<swapchain_base> 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.