mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-26 22:40:08 +01:00
Refactor dispatch table to fix extension entry point visibility
Add functionality to the dispatch tables enabling the layer to hide entrypoints from user. Add filtering to vkGetDeviceProcAddr/vkGetInstanceProcAddr to only return pointers to entrypoints which belongs to user enabled extensions. Signed-off-by: Dennis Wildmark <dennis.wildmark@arm.com> Change-Id: Ieec305cc9479363de0b8e1618c671c08f7af3997
This commit is contained in:
parent
bf7d090fdc
commit
2837bab5c4
4 changed files with 511 additions and 191 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2023 Arm Limited.
|
||||
* Copyright (c) 2016-2024 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -149,30 +149,27 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con
|
|||
*/
|
||||
TRY_LOG(fpCreateInstance(&modified_info, pAllocator, pInstance), "Failed to create the instance");
|
||||
|
||||
instance_dispatch_table table{};
|
||||
VkResult result;
|
||||
result = table.populate(*pInstance, fpGetInstanceProcAddr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
if (table.DestroyInstance != nullptr)
|
||||
{
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Following the spec: use the callbacks provided to vkCreateInstance() if not nullptr,
|
||||
* otherwise use the default callbacks.
|
||||
*/
|
||||
util::allocator instance_allocator{ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, pAllocator };
|
||||
result = instance_private_data::associate(*pInstance, table, loader_callback, layer_platforms_to_enable,
|
||||
instance_dispatch_table table{ instance_allocator };
|
||||
VkResult result = table.populate(*pInstance, fpGetInstanceProcAddr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
return result;
|
||||
}
|
||||
table.set_user_enabled_extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount);
|
||||
|
||||
uint32_t api_version =
|
||||
pCreateInfo->pApplicationInfo != nullptr ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_3;
|
||||
|
||||
result = instance_private_data::associate(*pInstance, table, loader_callback, layer_platforms_to_enable, api_version,
|
||||
instance_allocator);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
if (table.DestroyInstance != nullptr)
|
||||
{
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
}
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -186,10 +183,7 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con
|
|||
if (result != VK_SUCCESS)
|
||||
{
|
||||
instance_private_data::disassociate(*pInstance);
|
||||
if (table.DestroyInstance != nullptr)
|
||||
{
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
}
|
||||
table.DestroyInstance(*pInstance, pAllocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -249,29 +243,27 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
/* Now call create device on the chain further down the list. */
|
||||
TRY_LOG(fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice), "Failed to create the device");
|
||||
|
||||
device_dispatch_table table{};
|
||||
VkResult result = table.populate(*pDevice, fpGetDeviceProcAddr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
if (table.DestroyDevice != nullptr)
|
||||
{
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Following the spec: use the callbacks provided to vkCreateDevice() if not nullptr, otherwise use the callbacks
|
||||
* provided to the instance (if no allocator callbacks was provided to the instance, it will use default ones).
|
||||
*/
|
||||
util::allocator device_allocator{ inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE, pAllocator };
|
||||
device_dispatch_table table{ device_allocator };
|
||||
VkResult result = table.populate(*pDevice, fpGetDeviceProcAddr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
table.set_user_enabled_extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount);
|
||||
|
||||
result =
|
||||
device_private_data::associate(*pDevice, inst_data, physicalDevice, table, loader_callback, device_allocator);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
if (table.DestroyDevice != nullptr)
|
||||
{
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
}
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -284,10 +276,7 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
if (result != VK_SUCCESS)
|
||||
{
|
||||
layer::device_private_data::disassociate(*pDevice);
|
||||
if (table.DestroyDevice != nullptr)
|
||||
{
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
}
|
||||
table.DestroyDevice(*pDevice, pAllocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -322,15 +311,16 @@ wsi_layer_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pA
|
|||
return;
|
||||
}
|
||||
|
||||
auto fn_destroy_instance = layer::instance_private_data::get(instance).disp.DestroyInstance;
|
||||
auto fn_destroy_instance =
|
||||
layer::instance_private_data::get(instance).disp.get_fn<PFN_vkDestroyInstance>("vkDestroyInstance");
|
||||
|
||||
/* Call disassociate() before doing vkDestroyInstance as an instance may be created by a different thread
|
||||
* just after we call vkDestroyInstance() and it could get the same address if we are unlucky.
|
||||
*/
|
||||
layer::instance_private_data::disassociate(instance);
|
||||
|
||||
assert(fn_destroy_instance);
|
||||
fn_destroy_instance(instance, pAllocator);
|
||||
assert(fn_destroy_instance.has_value());
|
||||
(*fn_destroy_instance)(instance, pAllocator);
|
||||
}
|
||||
|
||||
VWL_VKAPI_CALL(void)
|
||||
|
|
@ -341,15 +331,15 @@ wsi_layer_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocat
|
|||
return;
|
||||
}
|
||||
|
||||
auto fn_destroy_device = layer::device_private_data::get(device).disp.DestroyDevice;
|
||||
auto fn_destroy_device = layer::device_private_data::get(device).disp.get_fn<PFN_vkDestroyDevice>("vkDestroyDevice");
|
||||
|
||||
/* Call disassociate() before doing vkDestroyDevice as a device may be created by a different thread
|
||||
* just after we call vkDestroyDevice().
|
||||
*/
|
||||
layer::device_private_data::disassociate(device);
|
||||
|
||||
assert(fn_destroy_device);
|
||||
fn_destroy_device(device, pAllocator);
|
||||
assert(fn_destroy_device.has_value());
|
||||
(*fn_destroy_device)(device, pAllocator);
|
||||
}
|
||||
|
||||
VWL_VKAPI_CALL(VkResult)
|
||||
|
|
@ -430,7 +420,8 @@ wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName) VWL_API_POS
|
|||
GET_PROC_ADDR(vkCreateImage);
|
||||
GET_PROC_ADDR(vkBindImageMemory2);
|
||||
|
||||
return layer::device_private_data::get(device).disp.GetDeviceProcAddr(device, funcName);
|
||||
return layer::device_private_data::get(device).disp.get_user_enabled_entrypoint(
|
||||
device, layer::device_private_data::get(device).instance_data.api_version, funcName);
|
||||
}
|
||||
|
||||
VWL_VKAPI_CALL(PFN_vkVoidFunction)
|
||||
|
|
@ -476,5 +467,5 @@ wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName) VWL_A
|
|||
}
|
||||
}
|
||||
|
||||
return instance_data.disp.GetInstanceProcAddr(instance, funcName);
|
||||
return instance_data.disp.get_user_enabled_entrypoint(instance, instance_data.api_version, funcName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2022 Arm Limited.
|
||||
* Copyright (c) 2018-2022, 2024 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -43,45 +43,134 @@ static std::mutex g_data_lock;
|
|||
static util::unordered_map<void *, instance_private_data *> g_instance_data{ util::allocator::get_generic() };
|
||||
static util::unordered_map<void *, device_private_data *> g_device_data{ util::allocator::get_generic() };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
static constexpr entrypoint entrypoints_init[] = {
|
||||
#define DISPATCH_TABLE_ENTRY(name, ext_name, api_version, required) \
|
||||
{ "vk" #name, ext_name, nullptr, api_version, false, required },
|
||||
INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY)
|
||||
#undef DISPATCH_TABLE_ENTRY
|
||||
};
|
||||
static constexpr auto num_entrypoints = std::distance(std::begin(entrypoints_init), std::end(entrypoints_init));
|
||||
|
||||
for (size_t i = 0; i < num_entrypoints; i++)
|
||||
{
|
||||
const entrypoint *entrypoint = &entrypoints_init[i];
|
||||
PFN_vkVoidFunction ret = get_proc(instance, entrypoint->name);
|
||||
if (!ret && entrypoint->required)
|
||||
{
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
struct entrypoint e = *entrypoint;
|
||||
e.fn = ret;
|
||||
e.user_visible = false;
|
||||
|
||||
if (!entrypoints->try_insert(std::make_pair(e.name, e)).has_value())
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to allocate memory for instance dispatch table entry.");
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult device_dispatch_table::populate(VkDevice device, PFN_vkGetDeviceProcAddr get_proc)
|
||||
void dispatch_table::set_user_enabled_extensions(const char *const *extension_names, size_t extension_count)
|
||||
{
|
||||
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;
|
||||
for (size_t i = 0; i < extension_count; i++)
|
||||
{
|
||||
for (auto &entrypoint : *entrypoints)
|
||||
{
|
||||
if (!strcmp(entrypoint.second.ext_name, extension_names[i]))
|
||||
{
|
||||
entrypoint.second.user_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instance_private_data::instance_private_data(const instance_dispatch_table &table,
|
||||
PFN_vkVoidFunction instance_dispatch_table::get_user_enabled_entrypoint(VkInstance instance, uint32_t api_version,
|
||||
const char *fn_name) const
|
||||
{
|
||||
auto item = entrypoints->find(fn_name);
|
||||
if (item != entrypoints->end())
|
||||
{
|
||||
/* An entrypoint is allowed to use if it has been enabled by the user or is included in the core specficiation of the API version.
|
||||
* Entrypoints included in API version 1.0 are allowed by default. */
|
||||
if (item->second.user_visible || item->second.api_version <= api_version ||
|
||||
item->second.api_version == VK_API_VERSION_1_0)
|
||||
{
|
||||
return item->second.fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return GetInstanceProcAddr(instance, fn_name).value_or(nullptr);
|
||||
}
|
||||
|
||||
VkResult device_dispatch_table::populate(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc_fn)
|
||||
{
|
||||
static constexpr entrypoint entrypoints_init[] = {
|
||||
#define DISPATCH_TABLE_ENTRY(name, ext_name, api_version, required) \
|
||||
{ "vk" #name, ext_name, nullptr, api_version, false, required },
|
||||
DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY)
|
||||
#undef DISPATCH_TABLE_ENTRY
|
||||
};
|
||||
static constexpr auto num_entrypoints = std::distance(std::begin(entrypoints_init), std::end(entrypoints_init));
|
||||
|
||||
for (size_t i = 0; i < num_entrypoints; i++)
|
||||
{
|
||||
const entrypoint entrypoint = entrypoints_init[i];
|
||||
PFN_vkVoidFunction ret = get_proc_fn(dev, entrypoint.name);
|
||||
if (!ret && entrypoint.required)
|
||||
{
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
struct entrypoint e = entrypoint;
|
||||
e.fn = ret;
|
||||
e.user_visible = false;
|
||||
|
||||
if (!entrypoints->try_insert(std::make_pair(e.name, e)).has_value())
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to allocate memory for device dispatch table entry.");
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
PFN_vkVoidFunction device_dispatch_table::get_user_enabled_entrypoint(VkDevice device, uint32_t api_version,
|
||||
const char *fn_name) const
|
||||
{
|
||||
auto item = entrypoints->find(fn_name);
|
||||
if (item != entrypoints->end())
|
||||
{
|
||||
/* An entrypoint is allowed to use if it has been enabled by the user or is included in the core specficiation of the API version.
|
||||
* Entrypoints included in API version 1.0 are allowed by default. */
|
||||
if (item->second.user_visible || item->second.api_version <= api_version ||
|
||||
item->second.api_version == VK_API_VERSION_1_0)
|
||||
{
|
||||
return item->second.fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return GetDeviceProcAddr(device, fn_name).value_or(nullptr);
|
||||
}
|
||||
|
||||
instance_private_data::instance_private_data(instance_dispatch_table &table,
|
||||
PFN_vkSetInstanceLoaderData set_loader_data,
|
||||
util::wsi_platform_set enabled_layer_platforms,
|
||||
util::wsi_platform_set enabled_layer_platforms, const uint32_t api_version,
|
||||
const util::allocator &alloc)
|
||||
: disp{ table }
|
||||
: disp{ std::move(table) }
|
||||
, api_version{ api_version }
|
||||
, SetInstanceLoaderData{ set_loader_data }
|
||||
, enabled_layer_platforms{ enabled_layer_platforms }
|
||||
, allocator{ alloc }
|
||||
|
|
@ -104,11 +193,11 @@ static inline void *get_key(dispatchable_type dispatchable_object)
|
|||
|
||||
VkResult instance_private_data::associate(VkInstance instance, instance_dispatch_table &table,
|
||||
PFN_vkSetInstanceLoaderData set_loader_data,
|
||||
util::wsi_platform_set enabled_layer_platforms,
|
||||
util::wsi_platform_set enabled_layer_platforms, const uint32_t api_version,
|
||||
const util::allocator &allocator)
|
||||
{
|
||||
auto instance_data =
|
||||
allocator.make_unique<instance_private_data>(table, set_loader_data, enabled_layer_platforms, allocator);
|
||||
auto instance_data = allocator.make_unique<instance_private_data>(table, set_loader_data, enabled_layer_platforms,
|
||||
api_version, allocator);
|
||||
|
||||
if (instance_data == nullptr)
|
||||
{
|
||||
|
|
@ -294,9 +383,9 @@ bool instance_private_data::is_instance_extension_enabled(const char *extension_
|
|||
}
|
||||
|
||||
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,
|
||||
device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
const util::allocator &alloc)
|
||||
: disp{ table }
|
||||
: disp{ std::move(table) }
|
||||
, instance_data{ inst_data }
|
||||
, SetDeviceLoaderData{ set_loader_data }
|
||||
, physical_device{ phys_dev }
|
||||
|
|
@ -312,7 +401,7 @@ device_private_data::device_private_data(instance_private_data &inst_data, VkPhy
|
|||
}
|
||||
|
||||
VkResult device_private_data::associate(VkDevice dev, instance_private_data &inst_data, VkPhysicalDevice phys_dev,
|
||||
const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
const util::allocator &allocator)
|
||||
{
|
||||
auto device_data =
|
||||
|
|
@ -426,7 +515,7 @@ bool device_private_data::should_layer_create_swapchain(VkSurfaceKHR vk_surface)
|
|||
|
||||
bool device_private_data::can_icds_create_swapchain(VkSurfaceKHR vk_surface)
|
||||
{
|
||||
return disp.CreateSwapchainKHR != nullptr;
|
||||
return disp.get_fn<PFN_vkCreateSwapchainKHR>("vkCreateSwapchainKHR").has_value();
|
||||
}
|
||||
|
||||
VkResult device_private_data::set_device_enabled_extensions(const char *const *extension_names, size_t extension_count)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2022 Arm Limited.
|
||||
* Copyright (c) 2018-2022, 2024 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -39,6 +39,8 @@
|
|||
#include <unordered_set>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
#include <limits>
|
||||
#include <cstring>
|
||||
|
||||
using scoped_mutex = std::lock_guard<std::mutex>;
|
||||
|
||||
|
|
@ -51,45 +53,211 @@ class surface;
|
|||
namespace layer
|
||||
{
|
||||
|
||||
/* 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().
|
||||
/**
|
||||
* @brief Definition of an entrypoint.
|
||||
*/
|
||||
#define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
|
||||
/* Vulkan 1.0 */ \
|
||||
REQUIRED(GetInstanceProcAddr) \
|
||||
REQUIRED(DestroyInstance) \
|
||||
REQUIRED(GetPhysicalDeviceProperties) \
|
||||
REQUIRED(GetPhysicalDeviceImageFormatProperties) \
|
||||
REQUIRED(EnumerateDeviceExtensionProperties) \
|
||||
/* VK_KHR_surface */ \
|
||||
OPTIONAL(DestroySurfaceKHR) \
|
||||
OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \
|
||||
OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \
|
||||
OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \
|
||||
OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \
|
||||
/* VK_EXT_headless_surface */ \
|
||||
OPTIONAL(CreateHeadlessSurfaceEXT) \
|
||||
/* VK_KHR_wayland_surface */ \
|
||||
OPTIONAL(CreateWaylandSurfaceKHR) \
|
||||
/* VK_KHR_get_surface_capabilities2 */ \
|
||||
OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \
|
||||
OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \
|
||||
/* VK_KHR_get_physical_device_properties2 or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \
|
||||
OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \
|
||||
OPTIONAL(GetPhysicalDeviceFeatures2KHR) \
|
||||
/* VK_KHR_device_group + VK_KHR_surface or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) \
|
||||
/* VK_KHR_external_fence_capabilities or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
OPTIONAL(GetPhysicalDeviceExternalFencePropertiesKHR)
|
||||
|
||||
struct instance_dispatch_table
|
||||
struct entrypoint
|
||||
{
|
||||
const char *name;
|
||||
const char *ext_name;
|
||||
PFN_vkVoidFunction fn;
|
||||
uint32_t api_version;
|
||||
bool user_visible;
|
||||
bool required;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dispatch table base.
|
||||
*
|
||||
* This struct defines generic get and call function templates for a dispatch table.
|
||||
*/
|
||||
class dispatch_table
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new dispatch table object
|
||||
*
|
||||
* @param allocator Allocator for entrypoints vector
|
||||
*/
|
||||
dispatch_table(const util::allocator &allocator)
|
||||
{
|
||||
entrypoints = allocator.make_unique<util::unordered_map<std::string, entrypoint>>(allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the function object from the entrypoints.
|
||||
*
|
||||
* @tparam FunctionType The signature of the requested function.
|
||||
* @param fn_name The name of the function.
|
||||
* @return the requested function pointer, or std::nullopt.
|
||||
*/
|
||||
template <typename FunctionType>
|
||||
std::optional<FunctionType> get_fn(const char *fn_name) const
|
||||
{
|
||||
auto fn = entrypoints->find(fn_name);
|
||||
if (fn != entrypoints->end())
|
||||
{
|
||||
return reinterpret_cast<FunctionType>(fn->second.fn);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the user enabled extensions.
|
||||
*
|
||||
* @param extension_names Names of the extensions enabled by user.
|
||||
* @param extension_count Number of extensions enabled by the user.
|
||||
*/
|
||||
void set_user_enabled_extensions(const char *const *extension_names, size_t extension_count);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Call function from the dispatch table entrypoints.
|
||||
*
|
||||
* @tparam FunctionType The signature of the function to call.
|
||||
* @tparam Args Argument types of the function to call.
|
||||
*
|
||||
* @param fn_name Name of the function to call.
|
||||
* @param args Arguments to the function to call.
|
||||
* @return function return value or std::nullopt if function is not present in entrypoints
|
||||
*/
|
||||
template <
|
||||
typename FunctionType, class... Args, typename ReturnType = std::invoke_result_t<FunctionType, Args...>,
|
||||
std::enable_if_t<!std::is_void<ReturnType>::value && !std::is_same<ReturnType, VkResult>::value, bool> = true>
|
||||
std::optional<ReturnType> call_fn(const char *fn_name, Args &&... args) const
|
||||
{
|
||||
auto fn = get_fn<FunctionType>(fn_name);
|
||||
if (fn.has_value())
|
||||
{
|
||||
return (*fn)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
WSI_LOG_WARNING("Call to %s failed, dispatch table does not contain the function.", fn_name);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call function from the dispatch table entrypoints.
|
||||
* @note This overload matches for functions with void return type.
|
||||
*
|
||||
* @tparam FunctionType The signature of the function to call.
|
||||
* @tparam Args Argument types of the function to call.
|
||||
*
|
||||
* @param fn_name Name of the function to call.
|
||||
* @param args Arguments to the function to call.
|
||||
*/
|
||||
template <typename FunctionType, class... Args, typename ReturnType = std::invoke_result_t<FunctionType, Args...>,
|
||||
std::enable_if_t<std::is_void<ReturnType>::value, bool> = true>
|
||||
void call_fn(const char *fn_name, Args &&... args) const
|
||||
{
|
||||
auto fn = get_fn<FunctionType>(fn_name);
|
||||
if (fn.has_value())
|
||||
{
|
||||
return (*fn)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
WSI_LOG_WARNING("Call to %s failed, dispatch table does not contain the function.", fn_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call function from the dispatch table entrypoints.
|
||||
* @note This overload matches for functions with VkResult return type.
|
||||
*
|
||||
* @tparam FunctionType The signature of the function to call.
|
||||
* @tparam Args Argument types of the function to call.
|
||||
*
|
||||
* @param fn_name Name of the function to call.
|
||||
* @param args Arguments to the function to call.
|
||||
* @return function return value or VK_ERROR_EXTENSION_NOT_PRESENT if function is not present in entrypoints
|
||||
*/
|
||||
template <typename FunctionType, class... Args, typename ReturnType = std::invoke_result_t<FunctionType, Args...>,
|
||||
std::enable_if_t<std::is_same<ReturnType, VkResult>::value, bool> = true>
|
||||
VkResult call_fn(const char *fn_name, Args &&... args) const
|
||||
{
|
||||
auto fn = get_fn<FunctionType>(fn_name);
|
||||
if (fn.has_value())
|
||||
{
|
||||
return (*fn)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
WSI_LOG_WARNING("Call to %s failed, dispatch table does not contain the function.", fn_name);
|
||||
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
/** @brief Vector that holds the entrypoints of the dispatch table */
|
||||
util::unique_ptr<util::unordered_map<std::string, entrypoint>> entrypoints;
|
||||
};
|
||||
|
||||
/* Represents the maximum possible Vulkan API version. */
|
||||
static constexpr uint32_t API_VERSION_MAX = UINT32_MAX;
|
||||
|
||||
/* List of instance 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 required == true / false. The layer
|
||||
* fails if vkGetInstanceProcAddr returns null for entrypoints that are required.
|
||||
*
|
||||
* Format of an entry is: EP(entrypoint_name, extension_name, api_version, required)
|
||||
* entrypoint_name: Name of the entrypoint.
|
||||
* extension_name: Name of the extension that provides the entrypoint.
|
||||
* api_version: Vulkan API version where the entrypoint is part of the core specification, or API_VERSION_MAX.
|
||||
* required: Boolean to indicate whether the entrypoint is required by the WSI layer or optional.
|
||||
*/
|
||||
#define INSTANCE_ENTRYPOINTS_LIST(EP) \
|
||||
/* Vulkan 1.0 */ \
|
||||
EP(GetInstanceProcAddr, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroyInstance, "", VK_API_VERSION_1_0, true) \
|
||||
EP(GetPhysicalDeviceProperties, "", VK_API_VERSION_1_0, true) \
|
||||
EP(GetPhysicalDeviceImageFormatProperties, "", VK_API_VERSION_1_0, true) \
|
||||
EP(EnumerateDeviceExtensionProperties, "", VK_API_VERSION_1_0, true) \
|
||||
/* VK_KHR_surface */ \
|
||||
EP(DestroySurfaceKHR, VK_KHR_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetPhysicalDeviceSurfacePresentModesKHR, VK_KHR_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_EXT_headless_surface */ \
|
||||
EP(CreateHeadlessSurfaceEXT, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_wayland_surface */ \
|
||||
EP(CreateWaylandSurfaceKHR, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_get_surface_capabilities2 */ \
|
||||
EP(GetPhysicalDeviceSurfaceCapabilities2KHR, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, API_VERSION_MAX, \
|
||||
false) \
|
||||
EP(GetPhysicalDeviceSurfaceFormats2KHR, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_get_physical_device_properties2 or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
EP(GetPhysicalDeviceImageFormatProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
EP(GetPhysicalDeviceFormatProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
EP(GetPhysicalDeviceFeatures2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1, \
|
||||
false) \
|
||||
EP(GetPhysicalDeviceProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1, \
|
||||
false) \
|
||||
EP(GetPhysicalDeviceQueueFamilyProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
EP(GetPhysicalDeviceMemoryProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
EP(GetPhysicalDeviceSparseImageFormatProperties2KHR, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_device_group + VK_KHR_surface or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
EP(GetPhysicalDevicePresentRectanglesKHR, VK_KHR_DEVICE_GROUP_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_external_fence_capabilities or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
EP(GetPhysicalDeviceExternalFencePropertiesKHR, VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false) \
|
||||
EP(GetPhysicalDeviceExternalBufferPropertiesKHR, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \
|
||||
VK_API_VERSION_1_1, false)
|
||||
|
||||
/**
|
||||
* @brief Struct representing the instance dispatch table.
|
||||
*/
|
||||
class instance_dispatch_table : public dispatch_table
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Populate the instance dispatch table with functions that it requires.
|
||||
* @note The function greedy fetches all the functions it needs so even in the
|
||||
|
|
@ -101,9 +269,31 @@ struct instance_dispatch_table
|
|||
*/
|
||||
VkResult populate(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
|
||||
|
||||
#define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
|
||||
INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
|
||||
#undef DISPATCH_TABLE_ENTRY
|
||||
/**
|
||||
* @brief Get the user enabled instance extension entrypoint by name
|
||||
*
|
||||
* @param instance The Vulkan instance that the extension was enabled on.
|
||||
* @param api_version The API version of the Vulkan instance.
|
||||
* @param fn_name The name of the function.
|
||||
* @return pointer to the function if it is enabled by the user, otherwise nullptr.
|
||||
*/
|
||||
PFN_vkVoidFunction get_user_enabled_entrypoint(VkInstance instance, uint32_t api_version, const char *fn_name) const;
|
||||
|
||||
/* Generate alias functions for internal use of the dispatch table entrypoints.
|
||||
* These will be named as the entrypoint, but without the "vk" prefix.
|
||||
* Assuming disp is an instance of instance_dispatch_table, the following syntax is supported:
|
||||
* disp.GetInstanceProcAddr(instance, fn_name);
|
||||
* The result type will be matching the function signature, so there is no need for casting.
|
||||
*/
|
||||
#define DISPATCH_TABLE_SHORTCUT(name, unused1, unused2, unused3) \
|
||||
template <class... Args> \
|
||||
auto name(Args &&... args) const \
|
||||
{ \
|
||||
return call_fn<PFN_vk##name>("vk" #name, std::forward<Args>(args)...); \
|
||||
};
|
||||
|
||||
INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_SHORTCUT)
|
||||
#undef DISPATCH_TABLE_SHORTCUT
|
||||
};
|
||||
|
||||
/* List of device entrypoints in the layer's device dispatch table.
|
||||
|
|
@ -114,59 +304,83 @@ struct instance_dispatch_table
|
|||
* 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.
|
||||
*
|
||||
* Format of an entry is: EP(entrypoint_name, extension_name, api_version, required)
|
||||
* entrypoint_name: Name of the entrypoint.
|
||||
* extension_name: Name of the extension that provides the entrypoint.
|
||||
* api_version: Vulkan API version where the entrypoint is part of the core specification, or API_VERSION_MAX.
|
||||
* required: Boolean to indicate whether the entrypoint is required by the WSI layer or optional.
|
||||
*/
|
||||
#define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
|
||||
/* Vulkan 1.0 */ \
|
||||
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(CreateSemaphore) \
|
||||
REQUIRED(DestroySemaphore) \
|
||||
REQUIRED(ResetFences) \
|
||||
REQUIRED(WaitForFences) \
|
||||
REQUIRED(DestroyDevice) \
|
||||
/* VK_KHR_swapchain */ \
|
||||
OPTIONAL(CreateSwapchainKHR) \
|
||||
OPTIONAL(DestroySwapchainKHR) \
|
||||
OPTIONAL(GetSwapchainImagesKHR) \
|
||||
OPTIONAL(AcquireNextImageKHR) \
|
||||
OPTIONAL(QueuePresentKHR) \
|
||||
/* VK_KHR_device_group + VK_KHR_swapchain or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
OPTIONAL(AcquireNextImage2KHR) \
|
||||
/* VK_KHR_device_group + VK_KHR_surface or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
OPTIONAL(GetDeviceGroupSurfacePresentModesKHR) \
|
||||
OPTIONAL(GetDeviceGroupPresentCapabilitiesKHR) \
|
||||
/* VK_KHR_external_memory_fd */ \
|
||||
OPTIONAL(GetMemoryFdPropertiesKHR) \
|
||||
/* VK_KHR_bind_memory2 or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
OPTIONAL(BindImageMemory2KHR) \
|
||||
/* VK_KHR_external_fence_fd */ \
|
||||
OPTIONAL(GetFenceFdKHR) \
|
||||
OPTIONAL(ImportFenceFdKHR) \
|
||||
/* VK_KHR_external_semaphore_fd */ \
|
||||
OPTIONAL(ImportSemaphoreFdKHR)
|
||||
#define DEVICE_ENTRYPOINTS_LIST(EP) \
|
||||
/* Vulkan 1.0 */ \
|
||||
EP(GetDeviceProcAddr, "", VK_API_VERSION_1_0, true) \
|
||||
EP(GetDeviceQueue, "", VK_API_VERSION_1_0, true) \
|
||||
EP(QueueSubmit, "", VK_API_VERSION_1_0, true) \
|
||||
EP(QueueWaitIdle, "", VK_API_VERSION_1_0, true) \
|
||||
EP(CreateCommandPool, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroyCommandPool, "", VK_API_VERSION_1_0, true) \
|
||||
EP(AllocateCommandBuffers, "", VK_API_VERSION_1_0, true) \
|
||||
EP(FreeCommandBuffers, "", VK_API_VERSION_1_0, true) \
|
||||
EP(ResetCommandBuffer, "", VK_API_VERSION_1_0, true) \
|
||||
EP(BeginCommandBuffer, "", VK_API_VERSION_1_0, true) \
|
||||
EP(EndCommandBuffer, "", VK_API_VERSION_1_0, true) \
|
||||
EP(CreateImage, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroyImage, "", VK_API_VERSION_1_0, true) \
|
||||
EP(GetImageMemoryRequirements, "", VK_API_VERSION_1_0, true) \
|
||||
EP(BindImageMemory, "", VK_API_VERSION_1_0, true) \
|
||||
EP(AllocateMemory, "", VK_API_VERSION_1_0, true) \
|
||||
EP(FreeMemory, "", VK_API_VERSION_1_0, true) \
|
||||
EP(CreateFence, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroyFence, "", VK_API_VERSION_1_0, true) \
|
||||
EP(CreateSemaphore, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroySemaphore, "", VK_API_VERSION_1_0, true) \
|
||||
EP(ResetFences, "", VK_API_VERSION_1_0, true) \
|
||||
EP(WaitForFences, "", VK_API_VERSION_1_0, true) \
|
||||
EP(DestroyDevice, "", VK_API_VERSION_1_0, true) \
|
||||
/* VK_KHR_swapchain */ \
|
||||
EP(CreateSwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(DestroySwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(AcquireNextImageKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(QueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_device_group + VK_KHR_swapchain or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
EP(AcquireNextImage2KHR, VK_KHR_DEVICE_GROUP_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_device_group + VK_KHR_surface or */ \
|
||||
/* 1.1 with VK_KHR_swapchain */ \
|
||||
EP(GetDeviceGroupSurfacePresentModesKHR, VK_KHR_DEVICE_GROUP_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
EP(GetDeviceGroupPresentCapabilitiesKHR, VK_KHR_DEVICE_GROUP_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_external_memory_fd */ \
|
||||
EP(GetMemoryFdKHR, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetMemoryFdPropertiesKHR, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_bind_memory2 or */ \
|
||||
/* 1.1 (without KHR suffix) */ \
|
||||
EP(BindImageMemory2KHR, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
EP(BindBufferMemory2KHR, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_external_fence_fd */ \
|
||||
EP(GetFenceFdKHR, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(ImportFenceFdKHR, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_external_semaphore_fd */ \
|
||||
EP(ImportSemaphoreFdKHR, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
EP(GetSemaphoreFdKHR, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_image_drm_format_modifier */ \
|
||||
EP(GetImageDrmFormatModifierPropertiesEXT, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, API_VERSION_MAX, false) \
|
||||
/* VK_KHR_sampler_ycbcr_conversion */ \
|
||||
EP(CreateSamplerYcbcrConversionKHR, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
EP(DestroySamplerYcbcrConversionKHR, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_maintenance1 */ \
|
||||
EP(TrimCommandPoolKHR, VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
/* VK_KHR_get_memory_requirements2 */ \
|
||||
EP(GetImageMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
EP(GetBufferMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, false) \
|
||||
EP(GetImageSparseMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, false)
|
||||
|
||||
struct device_dispatch_table
|
||||
/**
|
||||
* @brief Struct representing the device dispatch table.
|
||||
*/
|
||||
class device_dispatch_table : public dispatch_table
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Populate the device dispatch table with functions that it requires.
|
||||
* @note The function greedy fetches all the functions it needs so even in the
|
||||
|
|
@ -178,9 +392,31 @@ struct device_dispatch_table
|
|||
*/
|
||||
VkResult populate(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
|
||||
|
||||
#define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
|
||||
DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
|
||||
#undef DISPATCH_TABLE_ENTRY
|
||||
/**
|
||||
* @brief Get the user enabled device extension entrypoint by name
|
||||
*
|
||||
* @param device The Vulkan device that the extension was enabled on.
|
||||
* @param api_version The API version of the Vulkan instance.
|
||||
* @param fn_name The name of the function.
|
||||
* @return pointer to the function if it is enabled by the user, otherwise nullptr.
|
||||
*/
|
||||
PFN_vkVoidFunction get_user_enabled_entrypoint(VkDevice device, uint32_t api_version, const char *fn_name) const;
|
||||
|
||||
/* Generate alias functions for internal use of the dispatch table entrypoints.
|
||||
* These will be named as the entrypoint, but without the "vk" prefix.
|
||||
* Assuming disp is an instance of device_dispatch_table, the following syntax is supported:
|
||||
* disp.GetDeviceProcAddr(instance, fn_name);
|
||||
* The result type will be matching the function signature, so there is no need for casting.
|
||||
*/
|
||||
#define DISPATCH_TABLE_SHORTCUT(name, unused1, unused2, unused3) \
|
||||
template <class... Args> \
|
||||
auto name(Args &&... args) const \
|
||||
{ \
|
||||
return call_fn<PFN_vk##name>("vk" #name, std::forward<Args>(args)...); \
|
||||
};
|
||||
|
||||
DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_SHORTCUT)
|
||||
#undef DISPATCH_TABLE_SHORTCUT
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -214,7 +450,8 @@ public:
|
|||
*/
|
||||
static VkResult associate(VkInstance instance, instance_dispatch_table &table,
|
||||
PFN_vkSetInstanceLoaderData set_loader_data,
|
||||
util::wsi_platform_set enabled_layer_platforms, const util::allocator &allocator);
|
||||
util::wsi_platform_set enabled_layer_platforms, const uint32_t api_version,
|
||||
const util::allocator &allocator);
|
||||
|
||||
/**
|
||||
* @brief Disassociate and destroy the #instance_private_data associated to the given VkInstance.
|
||||
|
|
@ -336,6 +573,7 @@ public:
|
|||
bool is_instance_extension_enabled(const char *extension_name) const;
|
||||
|
||||
const instance_dispatch_table disp;
|
||||
const uint32_t api_version;
|
||||
|
||||
private:
|
||||
/* Allow util::allocator to access the private constructor */
|
||||
|
|
@ -350,15 +588,16 @@ private:
|
|||
* @param enabled_layer_platforms The platforms that are enabled by the layer.
|
||||
* @param alloc The allocator that the instance_private_data will use.
|
||||
*/
|
||||
instance_private_data(const instance_dispatch_table &table, PFN_vkSetInstanceLoaderData set_loader_data,
|
||||
util::wsi_platform_set enabled_layer_platforms, const util::allocator &alloc);
|
||||
instance_private_data(instance_dispatch_table &table, PFN_vkSetInstanceLoaderData set_loader_data,
|
||||
util::wsi_platform_set enabled_layer_platforms, const uint32_t api_version,
|
||||
const util::allocator &alloc);
|
||||
|
||||
/**
|
||||
* @brief Destroy the instance_private_data properly with its allocator
|
||||
*
|
||||
* @param instance_data A valid pointer to instance_private_data
|
||||
*/
|
||||
static void destroy(instance_private_data* instance_data);
|
||||
static void destroy(instance_private_data *instance_data);
|
||||
|
||||
/**
|
||||
* @brief Check whether the given surface is already supported for presentation without the layer.
|
||||
|
|
@ -386,7 +625,6 @@ private:
|
|||
* @brief List with the names of the enabled instance extensions.
|
||||
*/
|
||||
util::extension_list enabled_extensions;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -414,7 +652,7 @@ public:
|
|||
* @return VkResult VK_SUCCESS if successful, otherwise an error
|
||||
*/
|
||||
static VkResult associate(VkDevice dev, instance_private_data &inst_data, VkPhysicalDevice phys_dev,
|
||||
const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
const util::allocator &allocator);
|
||||
|
||||
static void disassociate(VkDevice dev);
|
||||
|
|
@ -447,7 +685,8 @@ public:
|
|||
/**
|
||||
* @brief Check whether the given swapchain is owned by us (the WSI Layer).
|
||||
*/
|
||||
bool layer_owns_swapchain(VkSwapchainKHR swapchain) const {
|
||||
bool layer_owns_swapchain(VkSwapchainKHR swapchain) const
|
||||
{
|
||||
return layer_owns_all_swapchains(&swapchain, 1);
|
||||
}
|
||||
|
||||
|
|
@ -528,7 +767,7 @@ private:
|
|||
* @param alloc The allocator that the device_private_data will use.
|
||||
*/
|
||||
device_private_data(instance_private_data &inst_data, VkPhysicalDevice phys_dev, VkDevice dev,
|
||||
const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data,
|
||||
const util::allocator &alloc);
|
||||
|
||||
/**
|
||||
|
|
@ -536,7 +775,7 @@ private:
|
|||
*
|
||||
* @param device_data A valid pointer to device_private_data
|
||||
*/
|
||||
static void destroy(device_private_data* device_data);
|
||||
static void destroy(device_private_data *device_data);
|
||||
|
||||
const util::allocator allocator;
|
||||
util::unordered_set<VkSwapchainKHR> swapchains;
|
||||
|
|
|
|||
|
|
@ -396,7 +396,8 @@ VkResult swapchain_base::acquire_next_image(uint64_t timeout, VkSemaphore semaph
|
|||
image_status_lock.unlock();
|
||||
|
||||
/* Try to signal fences/semaphores with a sync FD for optimal performance. */
|
||||
if (m_device_data.disp.ImportFenceFdKHR != nullptr && m_device_data.disp.ImportSemaphoreFdKHR != nullptr)
|
||||
if (m_device_data.disp.get_fn<PFN_vkImportFenceFdKHR>("vkImportFenceFdKHR").has_value() &&
|
||||
m_device_data.disp.get_fn<PFN_vkImportSemaphoreFdKHR>("vkImportSemaphoreFdKHR").has_value())
|
||||
{
|
||||
if (fence != VK_NULL_HANDLE)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue