Skip to content

Commit

Permalink
Fix vkGetInstanceProcAddr() interception (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
solidpixel authored Dec 6, 2024
1 parent 036b0da commit e181c48
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 47 deletions.
2 changes: 1 addition & 1 deletion generator/generate_vulkan_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ def generate_layer_instance_dispatch_table(file, mapping, commands):
itable_members = []
dispatch_table_members = []
dispatch_table_inits = []

for command in commands:
# Skip commands that are not instance commands
if command.dispatch_type != 'instance':
Expand Down Expand Up @@ -369,7 +370,6 @@ def generate_layer_instance_dispatch_table(file, mapping, commands):
dispatch_table_members.append('#endif')
dispatch_table_inits.append('#endif')


data = data.replace('{ITABLE_MEMBERS}', '\n'.join(itable_members))
data = data.replace('{DTABLE_MEMBERS}', '\n'.join(dispatch_table_members))
data = data.replace('{DTABLE_INITS}', '\n'.join(dispatch_table_inits))
Expand Down
67 changes: 44 additions & 23 deletions generator/vk_common/entry_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,42 @@ struct DispatchTableEntry
* \return The layer function pointer, or \c nullptr if the layer doesn't
* intercept the function.
*/
static PFN_vkVoidFunction get_instance_layer_function(
static PFN_vkVoidFunction get_fixed_instance_layer_function(
const char* name
) {
static const DispatchTableEntry layer_functions[] = {
static const DispatchTableEntry layerFunctions[] = {
VK_TABLE_ENTRY(vkGetInstanceProcAddr),
VK_TABLE_ENTRY(vkEnumerateDeviceLayerProperties),
VK_TABLE_ENTRY(vkEnumerateDeviceExtensionProperties),
VK_TABLE_ENTRY(vkEnumerateInstanceLayerProperties),
VK_TABLE_ENTRY(vkEnumerateInstanceExtensionProperties),
};

for (auto &function : instanceIntercepts)
for (auto &function : layerFunctions)
{
if (!strcmp(function.name, name))
{
return function.function;
}
}

for (auto &function : layer_functions)
return nullptr;
}

/**
* @brief Fetch the layer function for a given instance entrypoint name.
*
* @param name The layer entry point name.
*
* \return The layer function pointer, or \c nullptr if the layer doesn't
* intercept the function.
*/
static PFN_vkVoidFunction get_instance_layer_function(
const char* name
) {
for (auto &function : instanceIntercepts)
{
if (strcmp(function.name, name) == 0)
if (!strcmp(function.name, name))
{
return function.function;
}
Expand All @@ -136,21 +152,21 @@ static PFN_vkVoidFunction get_instance_layer_function(
static PFN_vkVoidFunction get_device_layer_function(
const char* name
) {
static const DispatchTableEntry layer_functions[] = {
static const DispatchTableEntry layerFunctions[] = {
VK_TABLE_ENTRY(vkGetDeviceProcAddr),
VK_TABLE_ENTRY(vkEnumerateDeviceExtensionProperties),
VK_TABLE_ENTRY(vkEnumerateDeviceLayerProperties),
};

for (auto &function : deviceIntercepts)
for (auto &function : layerFunctions)
{
if (!strcmp(function.name, name))
{
return function.function;
}
}

for (auto &function : layer_functions)
for (auto &function : deviceIntercepts)
{
if (!strcmp(function.name, name))
{
Expand All @@ -175,12 +191,14 @@ static PFN_vkVoidFunction vkGetDeviceProcAddr_default(
// queryable interface behavior seen by the application
auto driver_function = layer->driver.vkGetDeviceProcAddr(device, pName);
auto layer_function = get_device_layer_function(pName);

// If driver exposes it and the layer has one, use the layer function
if (driver_function && layer_function)
{
return layer_function;
}

// This may be nullptr if the driver doesn't expose the function
// Otherwise just use the driver function, which may be nullptr
return driver_function;
}

Expand All @@ -189,32 +207,35 @@ static PFN_vkVoidFunction vkGetInstanceProcAddr_default(
VkInstance instance,
const char* pName
) {
// Always return layer instance functions
auto layer_function = get_instance_layer_function(pName);
if (layer_function)
// Always expose these functions ...
PFN_vkVoidFunction layerFunction = get_fixed_instance_layer_function(pName);
if (layerFunction)
{
return layer_function;
return layerFunction;
}

// If this is an instance method hold the lock to access layer-wide global store
PFN_vkVoidFunction driver_function { nullptr };
// Otherwise, only expose functions that the driver exposes to avoid
// changing queryable interface behavior seen by the application
layerFunction = get_instance_layer_function(pName);
if (instance) {
std::unique_lock<std::mutex> lock { g_vulkanLock };
auto* layer = Instance::retrieve(instance);

// Don't hold the lock while calling the driver
lock.unlock();
driver_function = layer->nlayerGetProcAddress(layer->instance, pName);
}
PFN_vkVoidFunction driverFunction = layer->nlayerGetProcAddress(layer->instance, pName);

layer_function = get_device_layer_function(pName);
if ((!instance || driver_function) && layer_function)
{
return layer_function;
// If driver exposes it and the layer has one, use the layer function
if (driverFunction && layerFunction)
{
return layerFunction;
}

// Otherwise just use the driver function, which may be nullptr
return driverFunction;
}

// This may be nullptr if the driver doesn't expose the function
return driver_function;
return layerFunction;
}

/** See Vulkan API for documentation. */
Expand Down
67 changes: 44 additions & 23 deletions source_common/framework/entry_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,42 @@ struct DispatchTableEntry
* \return The layer function pointer, or \c nullptr if the layer doesn't
* intercept the function.
*/
static PFN_vkVoidFunction get_instance_layer_function(
static PFN_vkVoidFunction get_fixed_instance_layer_function(
const char* name
) {
static const DispatchTableEntry layer_functions[] = {
static const DispatchTableEntry layerFunctions[] = {
VK_TABLE_ENTRY(vkGetInstanceProcAddr),
VK_TABLE_ENTRY(vkEnumerateDeviceLayerProperties),
VK_TABLE_ENTRY(vkEnumerateDeviceExtensionProperties),
VK_TABLE_ENTRY(vkEnumerateInstanceLayerProperties),
VK_TABLE_ENTRY(vkEnumerateInstanceExtensionProperties),
};

for (auto &function : instanceIntercepts)
for (auto &function : layerFunctions)
{
if (!strcmp(function.name, name))
{
return function.function;
}
}

for (auto &function : layer_functions)
return nullptr;
}

/**
* @brief Fetch the layer function for a given instance entrypoint name.
*
* @param name The layer entry point name.
*
* \return The layer function pointer, or \c nullptr if the layer doesn't
* intercept the function.
*/
static PFN_vkVoidFunction get_instance_layer_function(
const char* name
) {
for (auto &function : instanceIntercepts)
{
if (strcmp(function.name, name) == 0)
if (!strcmp(function.name, name))
{
return function.function;
}
Expand All @@ -136,21 +152,21 @@ static PFN_vkVoidFunction get_instance_layer_function(
static PFN_vkVoidFunction get_device_layer_function(
const char* name
) {
static const DispatchTableEntry layer_functions[] = {
static const DispatchTableEntry layerFunctions[] = {
VK_TABLE_ENTRY(vkGetDeviceProcAddr),
VK_TABLE_ENTRY(vkEnumerateDeviceExtensionProperties),
VK_TABLE_ENTRY(vkEnumerateDeviceLayerProperties),
};

for (auto &function : deviceIntercepts)
for (auto &function : layerFunctions)
{
if (!strcmp(function.name, name))
{
return function.function;
}
}

for (auto &function : layer_functions)
for (auto &function : deviceIntercepts)
{
if (!strcmp(function.name, name))
{
Expand All @@ -175,12 +191,14 @@ static PFN_vkVoidFunction vkGetDeviceProcAddr_default(
// queryable interface behavior seen by the application
auto driver_function = layer->driver.vkGetDeviceProcAddr(device, pName);
auto layer_function = get_device_layer_function(pName);

// If driver exposes it and the layer has one, use the layer function
if (driver_function && layer_function)
{
return layer_function;
}

// This may be nullptr if the driver doesn't expose the function
// Otherwise just use the driver function, which may be nullptr
return driver_function;
}

Expand All @@ -189,32 +207,35 @@ static PFN_vkVoidFunction vkGetInstanceProcAddr_default(
VkInstance instance,
const char* pName
) {
// Always return layer instance functions
auto layer_function = get_instance_layer_function(pName);
if (layer_function)
// Always expose these functions ...
PFN_vkVoidFunction layerFunction = get_fixed_instance_layer_function(pName);
if (layerFunction)
{
return layer_function;
return layerFunction;
}

// If this is an instance method hold the lock to access layer-wide global store
PFN_vkVoidFunction driver_function { nullptr };
// Otherwise, only expose functions that the driver exposes to avoid
// changing queryable interface behavior seen by the application
layerFunction = get_instance_layer_function(pName);
if (instance) {
std::unique_lock<std::mutex> lock { g_vulkanLock };
auto* layer = Instance::retrieve(instance);

// Don't hold the lock while calling the driver
lock.unlock();
driver_function = layer->nlayerGetProcAddress(layer->instance, pName);
}
PFN_vkVoidFunction driverFunction = layer->nlayerGetProcAddress(layer->instance, pName);

layer_function = get_device_layer_function(pName);
if ((!instance || driver_function) && layer_function)
{
return layer_function;
// If driver exposes it and the layer has one, use the layer function
if (driverFunction && layerFunction)
{
return layerFunction;
}

// Otherwise just use the driver function, which may be nullptr
return driverFunction;
}

// This may be nullptr if the driver doesn't expose the function
return driver_function;
return layerFunction;
}

/** See Vulkan API for documentation. */
Expand Down

0 comments on commit e181c48

Please sign in to comment.