Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -4877,6 +4877,8 @@ VKAPI_ATTR VkResult VKAPI_CALL loader_layer_create_device(VkInstance instance, V
struct loader_device *dev = NULL;
struct loader_instance *inst = NULL;

loader_platform_thread_lock_mutex(&loader_lock);

if (instance != VK_NULL_HANDLE) {
inst = loader_get_instance(instance);
internal_device = physicalDevice;
Expand Down Expand Up @@ -4977,6 +4979,8 @@ VKAPI_ATTR VkResult VKAPI_CALL loader_layer_create_device(VkInstance instance, V
if (NULL != icd_exts.list) {
loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
}
loader_platform_thread_unlock_mutex(&loader_lock);

return res;
}

Expand All @@ -4988,6 +4992,8 @@ VKAPI_ATTR void VKAPI_CALL loader_layer_destroy_device(VkDevice device, const Vk
return;
}

loader_platform_thread_lock_mutex(&loader_lock);

struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev);

destroyFunction(device, pAllocator);
Expand All @@ -4996,6 +5002,7 @@ VKAPI_ATTR void VKAPI_CALL loader_layer_destroy_device(VkDevice device, const Vk
dev->icd_device = NULL;
loader_remove_logical_device(icd_term, dev, pAllocator);
}
loader_platform_thread_unlock_mutex(&loader_lock);
}

// Given the list of layers to activate in the loader_instance
Expand Down
9 changes: 1 addition & 8 deletions loader/trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,10 +1034,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice phy
"vkCreateDevice: Invalid physicalDevice [VUID-vkCreateDevice-physicalDevice-parameter]");
abort(); /* Intentionally fail so user can correct issue. */
}
loader_platform_thread_lock_mutex(&loader_lock);
VkResult res = loader_layer_create_device(NULL, physicalDevice, pCreateInfo, pAllocator, pDevice, NULL, NULL);
loader_platform_thread_unlock_mutex(&loader_lock);
return res;
return loader_layer_create_device(NULL, physicalDevice, pCreateInfo, pAllocator, pDevice, NULL, NULL);
}

LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
Expand All @@ -1053,11 +1050,7 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const
abort(); /* Intentionally fail so user can correct issue. */
}

loader_platform_thread_lock_mutex(&loader_lock);

loader_layer_destroy_device(device, pAllocator, disp->DestroyDevice);

loader_platform_thread_unlock_mutex(&loader_lock);
}

LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
Expand Down
44 changes: 34 additions & 10 deletions tests/framework/layer/test_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateInstance(const VkInstanceCreateInfo*
return VK_ERROR_INITIALIZATION_FAILED;
}

if (layer.call_create_device_while_create_device_is_called) {
if (layer.call_create_device_while_create_device_is_called || layer.call_create_and_destroy_device_in_GetQueue) {
auto* createDeviceCallback = get_chain_info(pCreateInfo, VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK);
layer.callback_vkCreateDevice = createDeviceCallback->u.layerDevice.pfnLayerCreateDevice;
layer.callback_vkDestroyDevice = createDeviceCallback->u.layerDevice.pfnLayerDestroyDevice;
Expand Down Expand Up @@ -381,7 +381,7 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateInstance(const VkInstanceCreateInfo*
reinterpret_cast<PFN_vkCreateDevice>(fpGetInstanceProcAddr(nullptr, "vkCreateDevice"));
}

if (layer.call_create_device_while_create_device_is_called) {
if (layer.call_create_device_while_create_device_is_called || layer.call_create_and_destroy_device_in_GetQueue) {
uint32_t phys_dev_count = 0;
result = layer.instance_dispatch_table.EnumeratePhysicalDevices(layer.instance_handle, &phys_dev_count, nullptr);
if (result != VK_SUCCESS) {
Expand Down Expand Up @@ -433,8 +433,6 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
return VK_ERROR_INITIALIZATION_FAILED;
}

layer.next_vkGetDeviceProcAddr = fpGetDeviceProcAddr;

if (layer.check_if_EnumDevExtProps_is_same_as_queried_function) {
auto chain_info_EnumDeviceExtProps = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
fpGetInstanceProcAddr(layer.instance_handle, "vkEnumerateDeviceExtensionProperties"));
Expand All @@ -455,6 +453,7 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
}
TestLayer::Device device{};
device.device_handle = *pDevice;
device.next_vkGetDeviceProcAddr = fpGetDeviceProcAddr;

// initialize layer's dispatch table
layer_init_device_dispatch_table(device.device_handle, &device.dispatch_table, fpGetDeviceProcAddr);
Expand All @@ -464,7 +463,7 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
}

for (auto& func : layer.custom_device_interception_functions) {
auto next_func = layer.next_vkGetDeviceProcAddr(*pDevice, func.name.c_str());
auto next_func = fpGetDeviceProcAddr(*pDevice, func.name.c_str());
layer.custom_dispatch_functions.at(func.name.c_str()) = next_func;
}

Expand All @@ -485,7 +484,7 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
}

if (layer.call_create_device_while_create_device_is_called) {
PFN_vkGetDeviceProcAddr next_gdpa = layer.next_vkGetDeviceProcAddr;
PFN_vkGetDeviceProcAddr next_gdpa = fpGetDeviceProcAddr;
result = layer.callback_vkCreateDevice(
instance_to_use, layer.queried_physical_devices.at(layer.physical_device_index_to_use_during_create_device),
pCreateInfo, pAllocator, &layer.second_device_created_during_create_device.device_handle, get_instance_func,
Expand Down Expand Up @@ -684,6 +683,30 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkEnumeratePhysicalDeviceGroups(

// device functions

VKAPI_ATTR void VKAPI_CALL test_vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) {
auto it = layer.get_created_device(device);

if (layer.call_create_and_destroy_device_in_GetQueue) {
TestLayer::Device local_device{};
VkDeviceCreateInfo pCreateInfo{};

pCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
PFN_vkGetDeviceProcAddr next_gdpa = it->next_vkGetDeviceProcAddr;
VkResult result = layer.callback_vkCreateDevice(
layer.instance_handle, layer.queried_physical_devices.at(layer.physical_device_index_to_use_during_create_device),
&pCreateInfo, nullptr, &local_device.device_handle, get_instance_func, &next_gdpa);
if (result != VK_SUCCESS) {
return;
}
// initialize the other device's dispatch table
layer_init_device_dispatch_table(local_device.device_handle, &local_device.dispatch_table, next_gdpa);

layer.callback_vkDestroyDevice(local_device.device_handle, nullptr, local_device.dispatch_table.DestroyDevice);
}

it->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
}

VKAPI_ATTR void VKAPI_CALL test_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
for (uint32_t i = 0; i < layer.spurious_device_memory_allocations.size();) {
auto& allocation = layer.spurious_device_memory_allocations[i];
Expand Down Expand Up @@ -830,9 +853,10 @@ FRAMEWORK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDev

// trampolines
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func(VkDevice device, const char* pName);
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func_impl([[maybe_unused]] VkDevice device, const char* pName) {
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func_impl(VkDevice device, const char* pName) {
if (string_eq(pName, "vkGetDeviceProcAddr")) return to_vkVoidFunction(get_device_func);
if (string_eq(pName, "vkDestroyDevice")) return to_vkVoidFunction(test_vkDestroyDevice);
if (string_eq(pName, "vkGetDeviceQueue")) return to_vkVoidFunction(test_vkGetDeviceQueue);

if (IsDeviceExtensionAvailable(device, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
if (string_eq(pName, "vkDebugMarkerSetObjectTagEXT")) return to_vkVoidFunction(test_vkDebugMarkerSetObjectTagEXT);
Expand Down Expand Up @@ -867,11 +891,11 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func_impl([[maybe_unused]] V
return nullptr;
}

VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func([[maybe_unused]] VkDevice device, const char* pName) {
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_device_func(VkDevice device, const char* pName) {
PFN_vkVoidFunction ret_dev = get_device_func_impl(device, pName);
if (ret_dev != nullptr) return ret_dev;

return layer.next_vkGetDeviceProcAddr(device, pName);
auto it = layer.get_created_device(device);
return it != layer.created_devices.end() ? it->next_vkGetDeviceProcAddr(device, pName) : nullptr;
}

VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_physical_device_func([[maybe_unused]] VkInstance instance, const char* pName) {
Expand Down
8 changes: 7 additions & 1 deletion tests/framework/layer/test_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#pragma once

#include <algorithm>
#include <functional>
#include <filesystem>

Expand Down Expand Up @@ -194,6 +195,7 @@ struct TestLayer {

// Makes the layer try to create a device using the loader provided function in the layer chain
BUILDER_VALUE(bool, call_create_device_while_create_device_is_called)
BUILDER_VALUE(bool, call_create_and_destroy_device_in_GetQueue)
BUILDER_VALUE(uint32_t, physical_device_index_to_use_during_create_device)

BUILDER_VALUE(bool, check_if_EnumDevExtProps_is_same_as_queried_function)
Expand All @@ -209,7 +211,6 @@ struct TestLayer {

PFN_vkGetInstanceProcAddr next_vkGetInstanceProcAddr = VK_NULL_HANDLE;
PFN_GetPhysicalDeviceProcAddr next_GetPhysicalDeviceProcAddr = VK_NULL_HANDLE;
PFN_vkGetDeviceProcAddr next_vkGetDeviceProcAddr = VK_NULL_HANDLE;

VkInstance instance_handle = VK_NULL_HANDLE;
VkLayerInstanceDispatchTable instance_dispatch_table{};
Expand All @@ -218,8 +219,13 @@ struct TestLayer {
VkDevice device_handle = VK_NULL_HANDLE;
VkLayerDispatchTable dispatch_table{};
std::vector<Extension> enabled_extensions;
PFN_vkGetDeviceProcAddr next_vkGetDeviceProcAddr;
};
std::vector<Device> created_devices;
auto get_created_device(VkDevice device) {
return std::find_if(std::begin(created_devices), std::end(created_devices),
[device](const TestLayer::Device& dev) { return device == dev.device_handle; });
}

// Stores the callback that allows layers to create devices on their own
PFN_vkLayerCreateDevice callback_vkCreateDevice{};
Expand Down
33 changes: 33 additions & 0 deletions tests/loader_threading_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,39 @@ TEST(Threading, DeviceCreateDestroyLoop) {
}
}

TEST(Threading, LayersDeviceCreateDestroyLoop) {
const auto processor_count = std::thread::hardware_concurrency();

FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("")};
auto& driver = env.add_icd(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA);

env.add_implicit_layer({}, ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")));
env.get_test_layer(0).set_call_create_and_destroy_device_in_GetQueue(true);

uint32_t num_loops_create_destroy_device = 100;
uint32_t num_loops_try_get_device_proc_addr = 5;

driver.add_and_get_physical_device("physical_device_0").known_device_functions = {
{"vkCmdBindPipeline", to_vkVoidFunction(test_vkCmdBindPipeline)},
{"vkCmdBindDescriptorSets", to_vkVoidFunction(test_vkCmdBindDescriptorSets)},
{"vkCmdBindVertexBuffers", to_vkVoidFunction(test_vkCmdBindVertexBuffers)},
{"vkCmdBindIndexBuffer", to_vkVoidFunction(test_vkCmdBindIndexBuffer)},
{"vkCmdDraw", to_vkVoidFunction(test_vkCmdDraw)}};

std::vector<std::thread> device_creation_threads;

for (uint32_t i = 0; i < processor_count; i++) {
device_creation_threads.emplace_back(create_destroy_device_loop, &env, num_loops_create_destroy_device,
num_loops_try_get_device_proc_addr);
}
for (uint32_t i = 0; i < processor_count; i++) {
device_creation_threads[i].join();
}
}

void set_debug_utils_name_loop(FrameworkEnvironment* env, uint32_t num_loops, InstWrapper* inst,
std::vector<VkPhysicalDevice>* phys_devs) {
auto load_function = [&inst](const char* func_name) { return inst->load(func_name); };
Expand Down
Loading