"instance_extensions": [
{
"name" : "VK_EXT_headless_surface",
- "spec_version" : 1
+ "spec_version" : "1"
},
{
"name" : "VK_KHR_surface",
- "spec_version" : 1
+ "spec_version" : "1"
}
],
"device_extensions": [
{
"name" : "VK_KHR_swapchain",
- "spec_version" : 1
+ "spec_version" : "1"
}
],
"enable_environment": {
/*
- * Copyright (c) 2016-2020 Arm Limited.
+ * Copyright (c) 2016-2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
#include <cassert>
#include <cstdio>
#include <cstring>
+
#include <vulkan/vk_layer.h>
#include "private_data.hpp"
#include "surface_api.hpp"
#include "swapchain_api.hpp"
+#include "util/extension_list.hpp"
+#include "util/custom_allocator.hpp"
+#include "wsi/wsi_factory.hpp"
#define VK_LAYER_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
{
static const VkLayerProperties global_layer = {
- "VK_LAYER_window_system_integration",
- VK_LAYER_API_VERSION,
- 1,
- "Window system integration layer",
+ "VK_LAYER_window_system_integration", VK_LAYER_API_VERSION, 1, "Window system integration layer",
};
static const VkExtensionProperties device_extension[] = { { VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_SWAPCHAIN_SPEC_VERSION } };
return chain_info;
}
-/*
- * This is where we get our initialisation and construct our dispatch table. All layers must implement the function.
- * If you wish to intercept any device functions at all you need to implement vkCreateDevice.
- */
+/* This is where the layer is initialised and the instance dispatch table is constructed. */
VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
- /* Retrieve the vkGetInstanceProcAddr and the vkCreateInstance function pointers for the next layer in the chain. */
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+
PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(nullptr, "vkCreateInstance");
if (nullptr == fpCreateInstance)
{
/* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
- /* Now call create instance on the chain further down the list. */
- VkResult ret = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
+ /* The layer needs some Vulkan 1.1 functionality in order to operate correctly.
+ * We thus change the application info to require this API version, if necessary.
+ * This may have consequences for ICDs whose behaviour depends on apiVersion.
+ */
+ const uint32_t minimum_required_vulkan_version = VK_API_VERSION_1_1;
+ VkApplicationInfo modified_app_info{};
+ if (nullptr != pCreateInfo->pApplicationInfo)
+ {
+ modified_app_info = *pCreateInfo->pApplicationInfo;
+ if (modified_app_info.apiVersion < minimum_required_vulkan_version)
+ {
+ modified_app_info.apiVersion = minimum_required_vulkan_version;
+ }
+ }
+ else
+ {
+ modified_app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ modified_app_info.apiVersion = minimum_required_vulkan_version;
+ }
- instance_private_data::create(*pInstance, fpGetInstanceProcAddr, loader_callback);
- return ret;
+ VkInstanceCreateInfo modified_info = *pCreateInfo;
+ modified_info.pApplicationInfo = &modified_app_info;
+
+ /* Now call create instance on the chain further down the list.
+ * Note that we do not remove the extensions that the layer supports from modified_info.ppEnabledExtensionNames.
+ * Layers have to abide the rule that vkCreateInstance must not generate an error for unrecognized extension names.
+ * Also, the loader filters the extension list to ensure that ICDs do not see extensions that they do not support.
+ */
+ VkResult result;
+ result = fpCreateInstance(&modified_info, pAllocator, pInstance);
+ if (result != VK_SUCCESS)
+ {
+ return result;
+ }
+
+ instance_dispatch_table table;
+ result = table.populate(*pInstance, fpGetInstanceProcAddr);
+ if (result != VK_SUCCESS)
+ {
+ return result;
+ }
+
+ /* Find all the platforms that the layer can handle based on pCreateInfo->ppEnabledExtensionNames. */
+ auto layer_platforms_to_enable = wsi::find_enabled_layer_platforms(pCreateInfo);
+
+ std::unique_ptr<instance_private_data> inst_data{
+ new instance_private_data{table, loader_callback, layer_platforms_to_enable}};
+ instance_private_data::set(*pInstance, std::move(inst_data));
+ return VK_SUCCESS;
}
VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
/* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
- /* Now call create device on the chain further down the list. */
- VkResult ret = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
-
- device_private_data::create(*pDevice, fpGetDeviceProcAddr, physicalDevice, loader_callback);
-
- return ret;
-}
-
-} /* namespace layer */
-
-extern "C"
-{
- VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL
- wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName);
-
- VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
- wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName);
-
- /* Clean up the dispatch table for this instance. */
- VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
- wsi_layer_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator)
+ /* Copy the extension to a util::extension_list. */
+ util::allocator allocator{pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND};
+ util::extension_list enabled_extensions{allocator};
+ VkResult result;
+ result = enabled_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount);
+ if (result != VK_SUCCESS)
{
- assert(instance);
- layer::instance_private_data::get(layer::get_key(instance))
- .disp.DestroyInstance(instance, pAllocator);
-
- layer::instance_private_data::destroy(instance);
+ return result;
}
- VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
- wsi_layer_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator)
+ /* Add the extensions required by the platforms that are being enabled in the layer. */
+ auto &inst_data = instance_private_data::get(physicalDevice);
+ const util::wsi_platform_set& enabled_platforms = inst_data.get_enabled_platforms();
+ result = wsi::add_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions);
+ if (result != VK_SUCCESS)
{
- layer::device_private_data::destroy(device);
+ return result;
}
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- wsi_layer_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance)
+ util::vector<const char *> modified_enabled_extensions{allocator};
+ if (!enabled_extensions.get_extension_strings(modified_enabled_extensions))
{
- return layer::create_instance(pCreateInfo, pAllocator, pInstance);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
}
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- wsi_layer_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
- const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
+ /* Now call create device on the chain further down the list. */
+ VkDeviceCreateInfo modified_info = *pCreateInfo;
+ modified_info.ppEnabledExtensionNames = modified_enabled_extensions.data();
+ modified_info.enabledExtensionCount = modified_enabled_extensions.size();
+ result = fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice);
+ if (result != VK_SUCCESS)
{
- return layer::create_device(physicalDevice, pCreateInfo, pAllocator, pDevice);
+ return result;
}
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct)
+ device_dispatch_table table;
+ result = table.populate(*pDevice, fpGetDeviceProcAddr);
+ if (result != VK_SUCCESS)
{
- assert(pVersionStruct);
- assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+ return result;
+ }
- /* 2 is the minimum interface version which would utilize this function. */
- assert(pVersionStruct->loaderLayerInterfaceVersion >= 2);
+ std::unique_ptr<device_private_data> device{new device_private_data{inst_data, physicalDevice, *pDevice,
+ table, loader_callback}};
+ device_private_data::set(*pDevice, std::move(device));
+ return VK_SUCCESS;
+}
- /* Set our requested interface version. Set to 2 for now to separate us from newer versions. */
- pVersionStruct->loaderLayerInterfaceVersion = 2;
+} /* namespace layer */
- /* Fill in struct values. */
- pVersionStruct->pfnGetInstanceProcAddr = &wsi_layer_vkGetInstanceProcAddr;
- pVersionStruct->pfnGetDeviceProcAddr = &wsi_layer_vkGetDeviceProcAddr;
- pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
+extern "C" {
+VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName);
- return VK_SUCCESS;
- }
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetInstanceProcAddr(VkInstance instance,
+ const char *funcName);
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- wsi_layer_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
- uint32_t *pCount, VkExtensionProperties *pProperties)
- {
- if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
- return layer::extension_properties(1, layer::device_extension, pCount, pProperties);
+/* Clean up the dispatch table for this instance. */
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL wsi_layer_vkDestroyInstance(VkInstance instance,
+ const VkAllocationCallbacks *pAllocator)
+{
+ assert(instance);
+ layer::instance_private_data::get(instance).disp.DestroyInstance(instance, pAllocator);
+ layer::instance_private_data::destroy(instance);
+}
- assert(physicalDevice);
- return layer::instance_private_data::get(layer::get_key(physicalDevice))
- .disp.EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
- }
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL wsi_layer_vkDestroyDevice(VkDevice device,
+ const VkAllocationCallbacks *pAllocator)
+{
+ layer::device_private_data::destroy(device);
+}
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- wsi_layer_vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
- {
- if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
- return layer::extension_properties(1, layer::instance_extension, pCount, pProperties);
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL wsi_layer_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkInstance *pInstance)
+{
+ return layer::create_instance(pCreateInfo, pAllocator, pInstance);
+}
- return VK_ERROR_LAYER_NOT_PRESENT;
- }
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL wsi_layer_vkCreateDevice(VkPhysicalDevice physicalDevice,
+ const VkDeviceCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDevice *pDevice)
+{
+ return layer::create_device(physicalDevice, pCreateInfo, pAllocator, pDevice);
+}
- VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
- wsi_layer_vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
- {
- return layer::layer_properties(1, &layer::global_layer, pCount, pProperties);
- }
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
+vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct)
+{
+ assert(pVersionStruct);
+ assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+ /* 2 is the minimum interface version which would utilize this function. */
+ assert(pVersionStruct->loaderLayerInterfaceVersion >= 2);
+
+ /* Set our requested interface version. Set to 2 for now to separate us from newer versions. */
+ pVersionStruct->loaderLayerInterfaceVersion = 2;
+
+ /* Fill in struct values. */
+ pVersionStruct->pfnGetInstanceProcAddr = &wsi_layer_vkGetInstanceProcAddr;
+ pVersionStruct->pfnGetDeviceProcAddr = &wsi_layer_vkGetDeviceProcAddr;
+ pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
- #define GET_PROC_ADDR(func) \
+ return VK_SUCCESS;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL wsi_layer_vkEnumerateDeviceExtensionProperties(
+ VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
+{
+ if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
+ return layer::extension_properties(1, layer::device_extension, pCount, pProperties);
+
+ assert(physicalDevice);
+ return layer::instance_private_data::get(physicalDevice)
+ .disp.EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL wsi_layer_vkEnumerateInstanceExtensionProperties(
+ const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
+{
+ if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
+ return layer::extension_properties(1, layer::instance_extension, pCount, pProperties);
+
+ return VK_ERROR_LAYER_NOT_PRESENT;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
+wsi_layer_vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
+{
+ return layer::layer_properties(1, &layer::global_layer, pCount, pProperties);
+}
+
+#define GET_PROC_ADDR(func) \
if (!strcmp(funcName, #func)) \
return (PFN_vkVoidFunction)&wsi_layer_##func;
- VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL
- wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName)
- {
- GET_PROC_ADDR(vkCreateSwapchainKHR);
- GET_PROC_ADDR(vkDestroySwapchainKHR);
- GET_PROC_ADDR(vkGetSwapchainImagesKHR);
- GET_PROC_ADDR(vkAcquireNextImageKHR);
- GET_PROC_ADDR(vkQueuePresentKHR);
+VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName)
+{
+ GET_PROC_ADDR(vkCreateSwapchainKHR);
+ GET_PROC_ADDR(vkDestroySwapchainKHR);
+ GET_PROC_ADDR(vkGetSwapchainImagesKHR);
+ GET_PROC_ADDR(vkAcquireNextImageKHR);
+ GET_PROC_ADDR(vkQueuePresentKHR);
- return layer::device_private_data::get(layer::get_key(device)).disp.GetDeviceProcAddr(device, funcName);
- }
+ return layer::device_private_data::get(device).disp.GetDeviceProcAddr(device, funcName);
+}
- VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
- wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName)
- {
- GET_PROC_ADDR(vkGetDeviceProcAddr);
- GET_PROC_ADDR(vkGetInstanceProcAddr);
- GET_PROC_ADDR(vkCreateInstance);
- GET_PROC_ADDR(vkDestroyInstance);
- GET_PROC_ADDR(vkCreateDevice);
- GET_PROC_ADDR(vkDestroyDevice);
- GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceSupportKHR);
- GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
- GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceFormatsKHR);
- GET_PROC_ADDR(vkGetPhysicalDeviceSurfacePresentModesKHR);
- GET_PROC_ADDR(vkEnumerateDeviceExtensionProperties);
- GET_PROC_ADDR(vkEnumerateInstanceExtensionProperties);
- GET_PROC_ADDR(vkEnumerateInstanceLayerProperties);
-
- return layer::instance_private_data::get(layer::get_key(instance)).disp.GetInstanceProcAddr(instance, funcName);
- }
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wsi_layer_vkGetInstanceProcAddr(VkInstance instance,
+ const char *funcName)
+{
+ GET_PROC_ADDR(vkGetDeviceProcAddr);
+ GET_PROC_ADDR(vkGetInstanceProcAddr);
+ GET_PROC_ADDR(vkCreateInstance);
+ GET_PROC_ADDR(vkDestroyInstance);
+ GET_PROC_ADDR(vkCreateDevice);
+ GET_PROC_ADDR(vkDestroyDevice);
+ GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceSupportKHR);
+ GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+ GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceFormatsKHR);
+ GET_PROC_ADDR(vkGetPhysicalDeviceSurfacePresentModesKHR);
+ GET_PROC_ADDR(vkEnumerateDeviceExtensionProperties);
+ GET_PROC_ADDR(vkEnumerateInstanceExtensionProperties);
+ GET_PROC_ADDR(vkEnumerateInstanceLayerProperties);
+
+ return layer::instance_private_data::get(instance).disp.GetInstanceProcAddr(instance, funcName);
+}
} /* extern "C" */
/*
- * Copyright (c) 2018-2019 Arm Limited.
+ * Copyright (c) 2018-2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* SOFTWARE.
*/
-#include <cassert>
-#include <map>
-#include <mutex>
-
#include "private_data.hpp"
-using scoped_mutex = std::lock_guard<std::mutex>;
+#include "wsi/wsi_factory.hpp"
+
+#include <unordered_map>
namespace layer
{
static std::mutex g_data_lock;
-static std::map<void *, instance_private_data *> g_instance_data;
-static std::map<void *, device_private_data *> g_device_data;
+static std::unordered_map<void *, std::unique_ptr<instance_private_data>> g_instance_data;
+static std::unordered_map<void *, std::unique_ptr<device_private_data>> g_device_data;
+
+template <typename object_type, typename get_proc_type>
+static PFN_vkVoidFunction get_proc_helper(object_type obj, get_proc_type get_proc,
+ const char* proc_name, bool required, bool &ok)
+{
+ PFN_vkVoidFunction ret = get_proc(obj, proc_name);
+ if (nullptr == ret && required)
+ {
+ ok = false;
+ }
+ return ret;
+}
-instance_private_data::instance_private_data(VkInstance inst, PFN_vkGetInstanceProcAddr get_proc,
- PFN_vkSetInstanceLoaderData set_loader_data)
- : disp(inst, get_proc)
+VkResult instance_dispatch_table::populate(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc)
+{
+ bool ok = true;
+#define REQUIRED(x) x = reinterpret_cast<PFN_vk##x>(get_proc_helper(instance, get_proc, "vk" #x, true, ok));
+#define OPTIONAL(x) x = reinterpret_cast<PFN_vk##x>(get_proc_helper(instance, get_proc, "vk" #x, false, ok));
+ INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL);
+#undef REQUIRED
+#undef OPTIONAL
+ return ok ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
+}
+
+VkResult device_dispatch_table::populate(VkDevice device, PFN_vkGetDeviceProcAddr get_proc)
+{
+ bool ok = true;
+#define REQUIRED(x) x = reinterpret_cast<PFN_vk##x>(get_proc_helper(device, get_proc, "vk" #x, true, ok));
+#define OPTIONAL(x) x = reinterpret_cast<PFN_vk##x>(get_proc_helper(device, get_proc, "vk" #x, false, ok));
+ DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL);
+#undef REQUIRED
+#undef OPTIONAL
+ return ok ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
+}
+
+instance_private_data::instance_private_data(const instance_dispatch_table& table,
+ PFN_vkSetInstanceLoaderData set_loader_data,
+ util::wsi_platform_set enabled_layer_platforms)
+ : disp(table)
, SetInstanceLoaderData(set_loader_data)
+ , enabled_layer_platforms(enabled_layer_platforms)
{
}
-instance_private_data &instance_private_data::create(VkInstance inst, PFN_vkGetInstanceProcAddr get_proc,
- PFN_vkSetInstanceLoaderData set_loader_data)
+template <typename dispatchable_type>
+static inline void *get_key(dispatchable_type dispatchable_object)
+{
+ return *reinterpret_cast<void **>(dispatchable_object);
+}
+
+void instance_private_data::set(VkInstance inst, std::unique_ptr<instance_private_data> inst_data)
{
- instance_private_data *inst_data = new instance_private_data(inst, get_proc, set_loader_data);
scoped_mutex lock(g_data_lock);
- g_instance_data[get_key(inst)] = inst_data;
- return *inst_data;
+ g_instance_data[get_key(inst)] = std::move(inst_data);
}
-instance_private_data &instance_private_data::get(void *key)
+template <typename dispatchable_type>
+static instance_private_data &get_instance_private_data(dispatchable_type dispatchable_object)
{
scoped_mutex lock(g_data_lock);
- instance_private_data *data = g_instance_data[key];
- assert(data);
- return *data;
+ return *g_instance_data[get_key(dispatchable_object)];
+}
+
+instance_private_data &instance_private_data::get(VkInstance instance)
+{
+ return get_instance_private_data(instance);
+}
+
+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)
+{
+ VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(surface);
+ return surface_base->platform;
+}
+
+bool instance_private_data::does_layer_support_surface(VkSurfaceKHR surface)
+{
+ return enabled_layer_platforms.contains(get_platform_of_surface(surface));
+}
+
+bool instance_private_data::do_icds_support_surface(VkPhysicalDevice, VkSurfaceKHR)
+{
+ /* For now assume ICDs do not support VK_KHR_surface. This means that the layer will handle all the surfaces it can
+ * handle (even if the ICDs can handle the surface) and only call down for surfaces it cannot handle. In the future
+ * we may allow system integrators to configure which ICDs have precedence handling which platforms.
+ */
+ return false;
+}
+
+bool instance_private_data::should_layer_handle_surface(VkPhysicalDevice phys_dev, VkSurfaceKHR surface)
+{
+ /* If the layer cannot handle the surface, then necessarily the ICDs or layers below us must be able to do it:
+ * the fact that the surface exists means that the Vulkan loader created it. In turn, this means that someone
+ * among the ICDs and layers advertised support for it. If it's not us, then it must be one of the layers/ICDs
+ * below us. It is therefore safe to always return false (and therefore call-down) when layer_can_handle_surface
+ * is false.
+ */
+ bool icd_can_handle_surface = do_icds_support_surface(phys_dev, surface);
+ bool layer_can_handle_surface = does_layer_support_surface(surface);
+ bool ret = layer_can_handle_surface && !icd_can_handle_surface;
+ return ret;
}
void instance_private_data::destroy(VkInstance inst)
{
- instance_private_data *data;
- {
- scoped_mutex lock(g_data_lock);
- data = g_instance_data[get_key(inst)];
- assert(data);
- g_instance_data.erase(get_key(inst));
- }
- delete data;
+ scoped_mutex lock(g_data_lock);
+ g_instance_data.erase(get_key(inst));
}
-device_private_data::device_private_data(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc,
- instance_private_data &inst_data, PFN_vkSetDeviceLoaderData set_loader_data)
- : disp(dev, get_proc)
- , instance_data(inst_data)
- , SetDeviceLoaderData(set_loader_data)
+device_private_data::device_private_data(instance_private_data &inst_data, VkPhysicalDevice phys_dev, VkDevice dev,
+ const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data)
+ : disp{table}
+ , instance_data{inst_data}
+ , SetDeviceLoaderData{set_loader_data}
+ , physical_device{phys_dev}
+ , device{dev}
{
}
-device_private_data &device_private_data::create(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc,
- VkPhysicalDevice phys_dev, PFN_vkSetDeviceLoaderData set_loader_data)
+void device_private_data::set(VkDevice dev, std::unique_ptr<device_private_data> dev_data)
{
- device_private_data *dev_data =
- new device_private_data(dev, get_proc, instance_private_data::get(get_key(phys_dev)), set_loader_data);
scoped_mutex lock(g_data_lock);
- g_device_data[get_key(dev)] = dev_data;
- return *dev_data;
+ g_device_data[get_key(dev)] = std::move(dev_data);
}
-device_private_data &device_private_data::get(void *key)
+template <typename dispatchable_type>
+static device_private_data &get_device_private_data(dispatchable_type dispatchable_object)
{
scoped_mutex lock(g_data_lock);
- device_private_data *data = g_device_data[key];
- assert(data);
- return *data;
+ return *g_device_data[get_key(dispatchable_object)];
}
-void device_private_data::destroy(VkDevice dev)
+device_private_data &device_private_data::get(VkDevice device)
+{
+ return get_device_private_data(device);
+}
+
+device_private_data &device_private_data::get(VkQueue queue)
+{
+ return get_device_private_data(queue);
+}
+
+void device_private_data::add_layer_swapchain(VkSwapchainKHR swapchain)
+{
+ scoped_mutex lock(swapchains_lock);
+ swapchains.insert(swapchain);
+}
+
+bool device_private_data::layer_owns_all_swapchains(const VkSwapchainKHR *swapchain, uint32_t swapchain_count) const
{
- device_private_data *data;
+ scoped_mutex lock(swapchains_lock);
+ for (uint32_t i = 0; i < swapchain_count; i++)
{
- scoped_mutex lock(g_data_lock);
- data = g_device_data[get_key(dev)];
- g_device_data.erase(get_key(dev));
+ if (swapchains.find(swapchain[i]) == swapchains.end())
+ {
+ return false;
+ }
}
- delete data;
+ return true;
+}
+
+bool device_private_data::should_layer_create_swapchain(VkSurfaceKHR vk_surface)
+{
+ return instance_data.should_layer_handle_surface(physical_device, vk_surface);
}
-} /* namespace layer */
+bool device_private_data::can_icds_create_swapchain(VkSurfaceKHR vk_surface)
+{
+ return disp.CreateSwapchainKHR != nullptr;
+}
+
+void device_private_data::destroy(VkDevice dev)
+{
+ scoped_mutex lock(g_data_lock);
+ g_device_data.erase(get_key(dev));
+}
+} /* namespace layer */
\ No newline at end of file
/*
- * Copyright (c) 2018-2020 Arm Limited.
+ * Copyright (c) 2018-2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
#pragma once
-#include "vulkan/vulkan.h"
-#include "vulkan/vk_layer.h"
+#include "util/platform_set.hpp"
-#define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x;
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_layer.h>
+#include <vulkan/vk_icd.h>
-#define INSTANCE_ENTRYPOINTS_LIST(V) \
- V(GetInstanceProcAddr) \
- V(GetPhysicalDeviceProperties) \
- V(GetPhysicalDeviceImageFormatProperties) \
- V(EnumerateDeviceExtensionProperties) \
- V(GetPhysicalDeviceSurfaceCapabilitiesKHR) \
- V(GetPhysicalDeviceSurfaceFormatsKHR) \
- V(GetPhysicalDeviceSurfacePresentModesKHR) \
- V(DestroyInstance) \
- V(GetPhysicalDeviceSurfaceSupportKHR)
+#include <memory>
+#include <unordered_set>
+#include <cassert>
+#include <mutex>
+
+using scoped_mutex = std::lock_guard<std::mutex>;
namespace layer
{
-template <typename DispatchableType>
-inline void *get_key(DispatchableType dispatchable_object)
-{
- return *(void **)dispatchable_object;
-}
+/* List of device entrypoints in the layer's instance dispatch table.
+ * Note that the Vulkan loader implements some of these entrypoints so the fact that these are non-null doesn't
+ * guarantee than we can safely call them. We still mark the entrypoints with REQUIRED() and OPTIONAL(). The layer
+ * fails if vkGetInstanceProcAddr returns null for entrypoints that are REQUIRED().
+ */
+#define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
+ REQUIRED(GetInstanceProcAddr) \
+ REQUIRED(DestroyInstance) \
+ REQUIRED(GetPhysicalDeviceProperties) \
+ REQUIRED(GetPhysicalDeviceImageFormatProperties) \
+ REQUIRED(EnumerateDeviceExtensionProperties) \
+ OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \
+ OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \
+ OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \
+ OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR)
struct instance_dispatch_table
{
- instance_dispatch_table(VkInstance inst, PFN_vkGetInstanceProcAddr get_proc)
- {
-#define DISPATCH_INIT(x) x = (PFN_vk##x)get_proc(inst, "vk" #x);
- INSTANCE_ENTRYPOINTS_LIST(DISPATCH_INIT);
-#undef DISPATCH_INIT
- }
+ VkResult populate(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
- INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY)
+#define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
+ INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
+#undef DISPATCH_TABLE_ENTRY
};
-#define DEVICE_ENTRYPOINTS_LIST(V) \
- V(GetDeviceProcAddr) \
- V(GetDeviceQueue) \
- V(QueueSubmit) \
- V(QueueWaitIdle) \
- V(CreateCommandPool) \
- V(DestroyCommandPool) \
- V(AllocateCommandBuffers) \
- V(FreeCommandBuffers) \
- V(ResetCommandBuffer) \
- V(BeginCommandBuffer) \
- V(EndCommandBuffer) \
- V(CreateImage) \
- V(DestroyImage) \
- V(GetImageMemoryRequirements) \
- V(BindImageMemory) \
- V(AllocateMemory) \
- V(FreeMemory) \
- V(CreateFence) \
- V(DestroyFence) \
- V(ResetFences) \
- V(WaitForFences)
+/* List of device entrypoints in the layer's device dispatch table.
+ * The layer fails initializing a device instance when entrypoints marked with REQUIRED() are retrieved as null.
+ * The layer will instead tolerate retrieving a null for entrypoints marked as OPTIONAL(). Code in the layer needs to
+ * check these entrypoints are non-null before calling them.
+ *
+ * Note that we cannot rely on checking whether the physical device supports a particular extension as the Vulkan
+ * loader currently aggregates all extensions advertised by all implicit layers (in their JSON manifests) and adds
+ * them automatically to the output of vkEnumeratePhysicalDeviceProperties.
+ */
+#define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
+ REQUIRED(GetDeviceProcAddr) \
+ REQUIRED(GetDeviceQueue) \
+ REQUIRED(QueueSubmit) \
+ REQUIRED(QueueWaitIdle) \
+ REQUIRED(CreateCommandPool) \
+ REQUIRED(DestroyCommandPool) \
+ REQUIRED(AllocateCommandBuffers) \
+ REQUIRED(FreeCommandBuffers) \
+ REQUIRED(ResetCommandBuffer) \
+ REQUIRED(BeginCommandBuffer) \
+ REQUIRED(EndCommandBuffer) \
+ REQUIRED(CreateImage) \
+ REQUIRED(DestroyImage) \
+ REQUIRED(GetImageMemoryRequirements) \
+ REQUIRED(BindImageMemory) \
+ REQUIRED(AllocateMemory) \
+ REQUIRED(FreeMemory) \
+ REQUIRED(CreateFence) \
+ REQUIRED(DestroyFence) \
+ REQUIRED(ResetFences) \
+ REQUIRED(WaitForFences) \
+ OPTIONAL(CreateSwapchainKHR) \
+ OPTIONAL(DestroySwapchainKHR) \
+ OPTIONAL(GetSwapchainImagesKHR) \
+ OPTIONAL(AcquireNextImageKHR) \
+ OPTIONAL(QueuePresentKHR)
struct device_dispatch_table
{
- device_dispatch_table(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc)
- {
-#define DISPATCH_INIT(x) x = (PFN_vk##x)get_proc(dev, "vk" #x);
- DEVICE_ENTRYPOINTS_LIST(DISPATCH_INIT);
-#undef DISPATCH_INIT
- }
+ VkResult populate(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
- DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY)
+#define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
+ DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
+#undef DISPATCH_TABLE_ENTRY
};
+/**
+ * @brief Layer "mirror object" for VkInstance.
+ */
class instance_private_data
{
public:
instance_private_data() = delete;
- static instance_private_data &create(VkInstance inst, PFN_vkGetInstanceProcAddr get_proc,
- PFN_vkSetInstanceLoaderData set_loader_data);
- static instance_private_data &get(void *key);
+ instance_private_data(const instance_private_data &) = delete;
+ instance_private_data &operator=(const instance_private_data &) = delete;
+
+ instance_private_data(const instance_dispatch_table& table,
+ PFN_vkSetInstanceLoaderData set_loader_data,
+ util::wsi_platform_set enabled_layer_platforms);
+ static void set(VkInstance inst, std::unique_ptr<instance_private_data> inst_data);
+
+ /**
+ * @brief Get the mirror object that the layer associates to a given Vulkan instance.
+ */
+ static instance_private_data &get(VkInstance instance);
+
+ /**
+ * @brief Get the layer instance object associated to the VkInstance owning the specified VkPhysicalDevice.
+ */
+ static instance_private_data &get(VkPhysicalDevice phys_dev);
+
+ /**
+ * @brief Get the set of enabled platforms that are also supported by the layer.
+ */
+ const util::wsi_platform_set &get_enabled_platforms()
+ {
+ return enabled_layer_platforms;
+ }
+
+ /**
+ * @brief Check whether a surface command should be handled by the WSI layer.
+ *
+ * @param phys_dev Physical device involved in the Vulkan command.
+ * @param surface The surface involved in the Vulkan command.
+ *
+ * @retval @c true if the layer should handle commands for the specified surface, which may mean returning an error
+ * if the layer does not support @p surface 's platform.
+ *
+ * @retval @c false if the layer should call down to the layers and ICDs below to handle the surface commands.
+ */
+ bool should_layer_handle_surface(VkPhysicalDevice phys_dev, VkSurfaceKHR surface);
+
+ /**
+ * @brief Check whether the given surface is supported for presentation via the layer.
+ *
+ * @param surface A VK_KHR_surface surface.
+ *
+ * @return Whether the WSI layer supports this surface.
+ */
+ bool does_layer_support_surface(VkSurfaceKHR surface);
+
static void destroy(VkInstance inst);
- instance_dispatch_table disp;
- PFN_vkSetInstanceLoaderData SetInstanceLoaderData;
+ const instance_dispatch_table disp;
private:
- instance_private_data(VkInstance inst, PFN_vkGetInstanceProcAddr get_proc,
- PFN_vkSetInstanceLoaderData set_loader_data);
+ /**
+ * @brief Check whether the given surface is already supported for presentation without the layer.
+ */
+ bool do_icds_support_surface(VkPhysicalDevice phys_dev, VkSurfaceKHR surface);
+
+ const PFN_vkSetInstanceLoaderData SetInstanceLoaderData;
+ const util::wsi_platform_set enabled_layer_platforms;
};
class device_private_data
{
public:
device_private_data() = delete;
- static device_private_data &create(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, VkPhysicalDevice phys_dev,
- PFN_vkSetDeviceLoaderData set_loader_data);
- static device_private_data &get(void *key);
+ device_private_data(const device_private_data &) = delete;
+ device_private_data &operator=(const device_private_data &) = delete;
+
+ device_private_data(instance_private_data &inst_data, VkPhysicalDevice phys_dev, VkDevice dev,
+ const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data);
+ static void set(VkDevice dev, std::unique_ptr<device_private_data> dev_data);
+
+ /**
+ * @brief Get the mirror object that the layer associates to a given Vulkan device.
+ */
+ static device_private_data &get(VkDevice device);
+
+ /**
+ * @brief Get the layer device object associated to the VkDevice owning the specified VkQueue.
+ */
+ static device_private_data &get(VkQueue queue);
+
+ void add_layer_swapchain(VkSwapchainKHR swapchain);
+
+ /**
+ * @brief Return whether all the provided swapchains are owned by us (the WSI Layer).
+ */
+ bool layer_owns_all_swapchains(const VkSwapchainKHR *swapchain, uint32_t swapchain_count) const;
+
+ /**
+ * @brief Check whether the given swapchain is owned by us (the WSI Layer).
+ */
+ bool layer_owns_swapchain(VkSwapchainKHR swapchain) const {
+ return layer_owns_all_swapchains(&swapchain, 1);
+ }
+
+ /**
+ * @brief Check whether the layer can create a swapchain for the given surface.
+ */
+ bool should_layer_create_swapchain(VkSurfaceKHR vk_surface);
+
+ /**
+ * @brief Check whether the ICDs or layers below support VK_KHR_swapchain.
+ */
+ bool can_icds_create_swapchain(VkSurfaceKHR vk_surface);
+
static void destroy(VkDevice dev);
- device_dispatch_table disp;
+ const device_dispatch_table disp;
instance_private_data &instance_data;
- PFN_vkSetDeviceLoaderData SetDeviceLoaderData;
+ const PFN_vkSetDeviceLoaderData SetDeviceLoaderData;
+ const VkPhysicalDevice physical_device;
+ const VkDevice device;
private:
- device_private_data(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, instance_private_data &inst_data,
- PFN_vkSetDeviceLoaderData set_loader_data);
+ std::unordered_set<VkSwapchainKHR> swapchains;
+ mutable std::mutex swapchains_lock;
};
} /* namespace layer */
/*
- * Copyright (c) 2016-2017, 2019 Arm Limited.
+ * Copyright (c) 2016-2017, 2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
*/
#include <cassert>
-
#include <wsi/wsi_factory.hpp>
-
#include "private_data.hpp"
#include "surface_api.hpp"
-extern "C"
-{
+extern "C" {
- /**
- * @brief Implements vkGetPhysicalDeviceSurfaceCapabilitiesKHR Vulkan entrypoint.
- */
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
- VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
+/**
+ * @brief Implements vkGetPhysicalDeviceSurfaceCapabilitiesKHR Vulkan entrypoint.
+ */
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
+{
+ 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);
- if (props)
- {
- return props->get_surface_capabilities(physicalDevice, surface, pSurfaceCapabilities);
- }
-
- return layer::instance_private_data::get(layer::get_key(physicalDevice))
- .disp.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
+ assert(props != nullptr);
+ return props->get_surface_capabilities(physicalDevice, surface, pSurfaceCapabilities);
}
- /**
- * @brief Implements vkGetPhysicalDeviceSurfaceFormatsKHR Vulkan entrypoint.
+ /* If the layer cannot handle this surface, then necessarily the surface must have been created by the ICDs (or a
+ * layer below us.) So it is safe to assume that the ICDs (or layers below us) support VK_KHR_surface and therefore
+ * it is safe to can call down. This holds for other entrypoints below.
*/
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- uint32_t *pSurfaceFormatCount,
- VkSurfaceFormatKHR *pSurfaceFormats)
+ return instance.disp.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
+}
+
+/**
+ * @brief Implements vkGetPhysicalDeviceSurfaceFormatsKHR Vulkan entrypoint.
+ */
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount,
+ VkSurfaceFormatKHR *pSurfaceFormats)
+{
+ 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);
- if (props)
- {
- return props->get_surface_formats(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats);
- }
-
- return layer::instance_private_data::get(layer::get_key(physicalDevice))
- .disp.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats);
+ assert(props != nullptr);
+ return props->get_surface_formats(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats);
}
- /**
- * @brief Implements vkGetPhysicalDeviceSurfacePresentModesKHR Vulkan entrypoint.
- */
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- uint32_t *pPresentModeCount,
- VkPresentModeKHR *pPresentModes)
+ return instance.disp.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
+ pSurfaceFormats);
+}
+
+/**
+ * @brief Implements vkGetPhysicalDeviceSurfacePresentModesKHR Vulkan entrypoint.
+ */
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t *pPresentModeCount,
+ VkPresentModeKHR *pPresentModes)
+{
+ 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);
- if (props)
- {
- return props->get_surface_present_modes(physicalDevice, surface, pPresentModeCount, pPresentModes);
- }
-
- return layer::instance_private_data::get(layer::get_key(physicalDevice))
- .disp.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes);
+ assert(props != nullptr);
+ return props->get_surface_present_modes(physicalDevice, surface, pPresentModeCount, pPresentModes);
}
- /**
- * @brief Implements vkGetPhysicalDeviceSurfaceSupportKHR Vulkan entrypoint.
- */
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,
- uint32_t queueFamilyIndex, VkSurfaceKHR surface,
- VkBool32 *pSupported)
- {
- wsi::surface_properties *props = wsi::get_surface_properties(surface);
- /* We assume that presentation to surface is supported by default */
- if (props)
- {
- *pSupported = VK_TRUE;
- return VK_SUCCESS;
- }
+ return instance.disp.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
+ pPresentModes);
+}
- return layer::instance_private_data::get(layer::get_key(physicalDevice))
- .disp.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
+/**
+ * @brief Implements vkGetPhysicalDeviceSurfaceSupportKHR Vulkan entrypoint.
+ */
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,
+ uint32_t queueFamilyIndex, VkSurfaceKHR surface,
+ VkBool32 *pSupported)
+{
+ auto &instance = layer::instance_private_data::get(physicalDevice);
+ if (instance.should_layer_handle_surface(physicalDevice, surface))
+ {
+ *pSupported = VK_TRUE;
+ return VK_SUCCESS;
}
+ return instance.disp.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
+}
+
} /* extern "C" */
/*
- * Copyright (c) 2018-2019 Arm Limited.
+ * Copyright (c) 2018-2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
extern "C" {
- /**
+/**
* @brief Implements vkGetPhysicalDeviceSurfaceCapabilitiesKHR Vulkan entrypoint.
*/
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- VkSurfaceCapabilitiesKHR *pSurfaceCapabilities);
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilitiesKHR *pSurfaceCapabilities);
- /**
+/**
* @brief Implements vkGetPhysicalDeviceSurfaceFormatsKHR Vulkan entrypoint.
*/
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
- uint32_t *pSurfaceFormatCount,
- VkSurfaceFormatKHR *pSurfaceFormats);
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount,
+ VkSurfaceFormatKHR *pSurfaceFormats);
- /**
+/**
* @brief Implements vkGetPhysicalDeviceSurfacePresentModesKHR Vulkan entrypoint.
*/
- VKAPI_ATTR VkResult
- wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
- uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes);
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t *pPresentModeCount,
+ VkPresentModeKHR *pPresentModes);
- /**
+/**
* @brief Implements vkGetPhysicalDeviceSurfaceSupportKHR Vulkan entrypoint.
*/
- VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,
- uint32_t queueFamilyIndex, VkSurfaceKHR surface,
- VkBool32 *pSupported);
-
+VKAPI_ATTR VkResult wsi_layer_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,
+ uint32_t queueFamilyIndex, VkSurfaceKHR surface,
+ VkBool32 *pSupported);
}
/*
- * Copyright (c) 2017, 2019 Arm Limited.
+ * Copyright (c) 2017, 2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
#include "private_data.hpp"
#include "swapchain_api.hpp"
-extern "C"
+extern "C" {
+
+VKAPI_ATTR VkResult wsi_layer_vkCreateSwapchainKHR(VkDevice device,
+ const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo,
+ const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain)
{
+ assert(pSwapchain != nullptr);
+ layer::device_private_data &device_data = layer::device_private_data::get(device);
+ VkSurfaceKHR surface = pSwapchainCreateInfo->surface;
- VKAPI_ATTR VkResult wsi_layer_vkCreateSwapchainKHR(VkDevice device,
- const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo,
- const VkAllocationCallbacks *pAllocator,
- VkSwapchainKHR *pSwapchain)
+ if (!device_data.should_layer_create_swapchain(surface))
{
- assert(pSwapchain != nullptr);
-
- wsi::swapchain_base *sc = wsi::allocate_surface_swapchain(
- pSwapchainCreateInfo->surface, layer::device_private_data::get(layer::get_key(device)), pAllocator);
-
- if (sc == nullptr)
+ if (!device_data.can_icds_create_swapchain(surface))
{
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
-
- VkResult result = sc->init(device, pSwapchainCreateInfo);
- if (result != VK_SUCCESS)
- {
- /* Error occured during initialization, need to free allocated memory. */
- wsi::destroy_surface_swapchain(sc, pAllocator);
- return result;
+ return VK_ERROR_INITIALIZATION_FAILED;
}
+ return device_data.disp.CreateSwapchainKHR(device_data.device, pSwapchainCreateInfo, pAllocator, pSwapchain);
+ }
- *pSwapchain = reinterpret_cast<VkSwapchainKHR>(sc);
+ wsi::swapchain_base *sc = wsi::allocate_surface_swapchain(surface, device_data, pAllocator);
+ if (sc == nullptr)
+ {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ VkResult result = sc->init(device, pSwapchainCreateInfo);
+ if (result != VK_SUCCESS)
+ {
+ /* Error occured during initialization, need to free allocated memory. */
+ wsi::destroy_surface_swapchain(sc, pAllocator);
return result;
}
- VKAPI_ATTR void wsi_layer_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapc,
- const VkAllocationCallbacks *pAllocator)
- {
- assert(swapc != VK_NULL_HANDLE);
+ *pSwapchain = reinterpret_cast<VkSwapchainKHR>(sc);
+ device_data.add_layer_swapchain(*pSwapchain);
+ return result;
+}
- wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+VKAPI_ATTR void wsi_layer_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapc,
+ const VkAllocationCallbacks *pAllocator)
+{
+ layer::device_private_data &device_data = layer::device_private_data::get(device);
- wsi::destroy_surface_swapchain(sc, pAllocator);
+ if (!device_data.layer_owns_swapchain(swapc))
+ {
+ return device_data.disp.DestroySwapchainKHR(device_data.device, swapc, pAllocator);
}
- VKAPI_ATTR VkResult wsi_layer_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapc,
- uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages)
- {
- assert(pSwapchainImageCount != nullptr);
- assert(swapc != VK_NULL_HANDLE);
+ assert(swapc != VK_NULL_HANDLE);
+ wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+ wsi::destroy_surface_swapchain(sc, pAllocator);
+}
- wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+VKAPI_ATTR VkResult wsi_layer_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapc,
+ uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages)
+{
+ layer::device_private_data &device_data = layer::device_private_data::get(device);
- return sc->get_swapchain_images(pSwapchainImageCount, pSwapchainImages);
+ if (!device_data.layer_owns_swapchain(swapc))
+ {
+ return device_data.disp.GetSwapchainImagesKHR(device_data.device, swapc, pSwapchainImageCount, pSwapchainImages);
}
- VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapc, uint64_t timeout,
- VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex)
+ assert(pSwapchainImageCount != nullptr);
+ assert(swapc != VK_NULL_HANDLE);
+ wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+ return sc->get_swapchain_images(pSwapchainImageCount, pSwapchainImages);
+}
+
+VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapc, uint64_t timeout,
+ VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex)
+{
+ layer::device_private_data &device_data = layer::device_private_data::get(device);
+
+ if (!device_data.layer_owns_swapchain(swapc))
{
- assert(swapc != VK_NULL_HANDLE);
- assert(semaphore != VK_NULL_HANDLE || fence != VK_NULL_HANDLE);
- assert(pImageIndex != nullptr);
+ return device_data.disp.AcquireNextImageKHR(device_data.device, swapc, timeout, semaphore, fence, pImageIndex);
+ }
- wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+ assert(swapc != VK_NULL_HANDLE);
+ assert(semaphore != VK_NULL_HANDLE || fence != VK_NULL_HANDLE);
+ assert(pImageIndex != nullptr);
+ wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+ return sc->acquire_next_image(timeout, semaphore, fence, pImageIndex);
+}
+
+VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
+{
+ assert(queue != VK_NULL_HANDLE);
+ assert(pPresentInfo != nullptr);
- return sc->acquire_next_image(timeout, semaphore, fence, pImageIndex);
+ layer::device_private_data &device_data = layer::device_private_data::get(queue);
+
+ if (!device_data.layer_owns_all_swapchains(pPresentInfo->pSwapchains, pPresentInfo->swapchainCount))
+ {
+ return device_data.disp.QueuePresentKHR(queue, pPresentInfo);
}
- VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
+ VkResult ret = VK_SUCCESS;
+ for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i)
{
- assert(queue != VK_NULL_HANDLE);
- assert(pPresentInfo != nullptr);
+ VkSwapchainKHR swapc = pPresentInfo->pSwapchains[i];
+
+ wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
+ assert(sc != nullptr);
- uint32_t resultMask = 0;
+ VkResult res = sc->queue_present(queue, pPresentInfo, pPresentInfo->pImageIndices[i]);
- for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i)
+ if (pPresentInfo->pResults != nullptr)
{
- wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(pPresentInfo->pSwapchains[i]);
- assert(sc != nullptr);
-
- VkResult res = sc->queue_present(queue, pPresentInfo, pPresentInfo->pImageIndices[i]);
-
- if (pPresentInfo->pResults != nullptr)
- {
- pPresentInfo->pResults[i] = res;
- }
-
- if (res == VK_ERROR_DEVICE_LOST)
- resultMask |= (1u << 1);
- else if (res == VK_ERROR_SURFACE_LOST_KHR)
- resultMask |= (1u << 2);
- else if (res == VK_ERROR_OUT_OF_DATE_KHR)
- resultMask |= (1u << 3);
+ pPresentInfo->pResults[i] = res;
}
- if (resultMask & (1u << 1))
- return VK_ERROR_DEVICE_LOST;
- else if (resultMask & (1u << 2))
- return VK_ERROR_SURFACE_LOST_KHR;
- else if (resultMask & (1u << 3))
- return VK_ERROR_OUT_OF_DATE_KHR;
-
- return VK_SUCCESS;
+ if (res != VK_SUCCESS && ret == VK_SUCCESS)
+ {
+ ret = res;
+ }
}
+ return ret;
+}
+
} /* extern "C" */
VkResult extension_list::add(VkPhysicalDevice dev)
{
- layer::instance_private_data &inst_data = layer::instance_private_data::get(layer::get_key(dev));
+ layer::instance_private_data &inst_data = layer::instance_private_data::get(dev);
uint32_t count;
VkResult m_error = inst_data.disp.EnumerateDeviceExtensionProperties(dev, nullptr, &count, nullptr);
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <stdint.h>
+
+#include <vulkan/vk_icd.h>
+
+namespace util
+{
+
+/**
+ * @brief Set of WSI platforms.
+ * @note This could be implemented via std::unordered_set, but would require handling allocation callbacks and would
+ * therefore be less convenient to use. Instead, we can store all info in the bits of uint64_t.
+ */
+class wsi_platform_set
+{
+public:
+ void add(VkIcdWsiPlatform p)
+ {
+ m_platforms |= (static_cast<uint64_t>(1) << to_int(p));
+ }
+
+ bool contains(VkIcdWsiPlatform p) const
+ {
+ return (m_platforms & (static_cast<uint64_t>(1) << to_int(p))) != 0;
+ }
+
+private:
+ /**
+ * @brief Convert a VkIcdWsiPlatform to an integer between 0-63.
+ */
+ static int to_int(VkIcdWsiPlatform p)
+ {
+ assert(static_cast<int>(p) >= 0 && static_cast<int>(p) < 64);
+ return static_cast<int>(p);
+ }
+
+ uint64_t m_platforms = 0;
+};
+
+} /* namespace util */
/*
- * Copyright (c) 2017-2019 Arm Limited.
+ * Copyright (c) 2017-2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
surface_capabilities->minImageExtent = { 1, 1 };
/* Ask the device for max */
VkPhysicalDeviceProperties dev_props;
- layer::instance_private_data::get(layer::get_key(physical_device)).disp.GetPhysicalDeviceProperties(physical_device, &dev_props);
+ layer::instance_private_data::get(physical_device).disp.GetPhysicalDeviceProperties(physical_device, &dev_props);
surface_capabilities->maxImageExtent = { dev_props.limits.maxImageDimension2D,
dev_props.limits.maxImageDimension2D };
{
VkImageFormatProperties image_format_props;
- res = layer::instance_private_data::get(layer::get_key(physical_device))
+ res = layer::instance_private_data::get(physical_device)
.disp.GetPhysicalDeviceImageFormatProperties(
physical_device, static_cast<VkFormat>(id), VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, &image_format_props);
/*
- * Copyright (c) 2017-2019 Arm Limited.
+ * Copyright (c) 2017-2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
#pragma once
#include <vulkan/vulkan.h>
+#include <util/extension_list.hpp>
namespace wsi
{
{
public:
/**
- * Implementation of vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the specific VkSurface type.
+ * @brief Implementation of vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the specific VkSurface type.
*/
virtual VkResult get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR *surface_capabilities) = 0;
/**
- * Implementation of vkGetPhysicalDeviceSurfaceFormatsKHR for the specific VkSurface type.
+ * @brief Implementation of vkGetPhysicalDeviceSurfaceFormatsKHR for the specific VkSurface type.
*/
virtual VkResult get_surface_formats(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
uint32_t *surface_format_count, VkSurfaceFormatKHR *surface_formats) = 0;
/**
- * Implementation of vkGetPhysicalDeviceSurfacePresentModesKHR for the specific VkSurface type.
+ * @brief Implementation of vkGetPhysicalDeviceSurfacePresentModesKHR for the specific VkSurface type.
*/
virtual VkResult get_surface_present_modes(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
uint32_t *present_mode_count, VkPresentModeKHR *present_modes) = 0;
+
+ /**
+ * @brief Return the device extensions that this surface_properties implementation needs.
+ */
+ virtual const util::extension_list &get_required_device_extensions()
+ {
+ static const util::extension_list empty{util::allocator::get_generic()};
+ return empty;
+ }
};
} /* namespace wsi */
-
/*
- * Copyright (c) 2019 Arm Limited.
+ * Copyright (c) 2019-2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
*/
#include "wsi_factory.hpp"
+#include "headless/surface_properties.hpp"
+#include "headless/swapchain.hpp"
+
#include <cassert>
#include <cstdlib>
-#include <cstdio>
+#include <cstring>
#include <new>
#include <vulkan/vk_icd.h>
-#include "headless/surface_properties.hpp"
-#include "headless/swapchain.hpp"
-
namespace wsi
{
-surface_properties *get_surface_properties(VkSurfaceKHR surface)
+static struct wsi_extension
{
- VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(surface);
+ VkExtensionProperties extension;
+ VkIcdWsiPlatform platform;
+} const supported_wsi_extensions[] = {
+ { { VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_HEADLESS }
+};
- switch (surface_base->platform)
+static surface_properties *get_surface_properties(VkIcdWsiPlatform platform)
+{
+ switch (platform)
{
case VK_ICD_WSI_PLATFORM_HEADLESS:
return &headless::surface_properties::get_instance();
}
}
+surface_properties *get_surface_properties(VkSurfaceKHR surface)
+{
+ VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(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::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo *pCreateInfo)
+{
+ util::wsi_platform_set ret;
+ for (const auto &ext_provided_by_layer : supported_wsi_extensions)
+ {
+ for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++)
+ {
+ const char* ext_requested_by_user = pCreateInfo->ppEnabledExtensionNames[i];
+ if (strcmp(ext_requested_by_user, ext_provided_by_layer.extension.extensionName) == 0)
+ {
+ ret.add(ext_provided_by_layer.platform);
+ }
+ }
+ }
+ return ret;
+}
+
+VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms,
+ util::extension_list &extensions_to_enable)
+{
+ util::allocator allocator{extensions_to_enable.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND};
+ util::extension_list device_extensions{allocator};
+ VkResult res = device_extensions.add(phys_dev);
+ if (res != VK_SUCCESS)
+ {
+ return res;
+ }
+
+ for (const auto &wsi_ext : supported_wsi_extensions)
+ {
+ /* Skip iterating over platforms not enabled in the instance. */
+ if (!enabled_platforms.contains(wsi_ext.platform))
+ {
+ continue;
+ }
+
+ surface_properties *props = get_surface_properties(wsi_ext.platform);
+ const auto &extensions_required_by_layer = props->get_required_device_extensions();
+ bool supported = device_extensions.contains(extensions_required_by_layer);
+ if (!supported)
+ {
+ /* Can we accept failure? The layer unconditionally advertises support for this platform and the loader uses
+ * this information to enable its own support of the vkCreate*SurfaceKHR entrypoints. The rest of the Vulkan
+ * stack may not support this extension so we cannot blindly fall back to it.
+ * For now treat this as an error.
+ */
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ res = extensions_to_enable.add(extensions_required_by_layer);
+ if (res != VK_SUCCESS)
+ {
+ return res;
+ }
+ }
+ return VK_SUCCESS;
+}
+
void destroy_surface_swapchain(swapchain_base *swapchain, const VkAllocationCallbacks *pAllocator)
{
assert(swapchain);
-
/*
- * Copyright (c) 2019 Arm Limited.
+ * Copyright (c) 2019, 2021 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* @file
* @brief Contains the factory methods for obtaining the specific surface and swapchain implementations.
*/
+
#pragma once
#include "swapchain_base.hpp"
#include "surface_properties.hpp"
-#include <layer/private_data.hpp>
+#include "util/platform_set.hpp"
+
+#include <unordered_map>
namespace wsi
{
/**
- * Obtains the surface properties for the specific surface type.
+ * @brief Obtains the surface properties for the specific surface type.
*
* @param surface The surface for which to get the properties.
*
surface_properties *get_surface_properties(VkSurfaceKHR surface);
/**
- * Allocates a surface specific swapchain.
+ * @brief Allocates a surface specific swapchain.
*
* @param surface The surface for which a swapchain is allocated.
* @param dev_data The device specific data.
const VkAllocationCallbacks *pAllocator);
/**
- * Destroys a swapchain and frees memory. Used with @ref allocate_surface_swapchain.
+ * @brief Destroys a swapchain and frees memory. Used with @ref allocate_surface_swapchain.
*
* @param swapchain Pointer to the swapchain to destroy.
* @param pAllocator The allocator to use for freeing memory.
*/
void destroy_surface_swapchain(swapchain_base *swapchain, const VkAllocationCallbacks *pAllocator);
+/**
+ * @brief Return which platforms the layer can handle for an instance constructed in the specified way.
+ *
+ * @details This function looks at the extensions specified in @p pCreateInfo and based on this returns a list of
+ * platforms that the layer can support. For example, if the @c pCreateInfo.ppEnabledExtensionNames contains the string
+ * "VK_EXT_headless_surface" then the returned platform set will contain @c VK_ICD_WSI_PLATFORM_HEADLESS.
+ *
+ * @param pCreateInfo Structure used when creating the instance in vkCreateInstance().
+ *
+ * @return A list of WS platforms supported by the layer.
+ */
+util::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo *pCreateInfo);
+
+/**
+ * @brief Add extra extensions that the layer requires to support the specified list of enabled platforms.
+ *
+ * @details Check whether @p phys_dev has support for the extensions required by the layer in order to support the
+ * platforms it implements. The extensions that the layer requires to operate are added to @p extensions_to_enable.
+ *
+ * @param[in] phys_dev The physical device to check.
+ * @param[in] enabled_platforms All the platforms that the layer must enable for @p phys_dev.
+ * @param[in,out] extensions_to_enable All the extensions required by the layer are added to this list.
+ *
+ * @retval @c VK_SUCCESS if the operation was successful.
+ */
+VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms,
+ util::extension_list &extensions_to_enable);
+
} // namespace wsi
\ No newline at end of file