diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e84b97..b357d96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,6 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") -Wno-c++98-compat-pedantic -Wno-switch-default -Wno-switch-enum - # allow global deconstructors - -Wno-exit-time-destructors # disable noisy warnings -Wno-missing-designated-field-initializers -Wno-cast-function-type-strict diff --git a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp index 4611b64..a24890b 100644 --- a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp +++ b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp @@ -26,6 +26,11 @@ namespace vk { PFN_vkGetDeviceProcAddr GetDeviceProcAddr; }; + /// initialize vulkan instance function pointers + /// @param instance vulkan instance handle + /// @param mpa function to get instance proc addresses + VulkanInstanceFuncs initVulkanInstanceFuncs(VkInstance instance, PFN_vkGetInstanceProcAddr mpa); + using PhysicalDeviceSelector = const std::function< VkPhysicalDevice( const VulkanInstanceFuncs&, @@ -94,6 +99,11 @@ namespace vk { PFN_vkGetSemaphoreFdKHR GetSemaphoreFdKHR; }; + /// initialize vulkan device function pointers + /// @param fi instance function pointers + /// @param device logical device handle + VulkanDeviceFuncs initVulkanDeviceFuncs(const VulkanInstanceFuncs& fi, VkDevice device); + /// vulkan version wrapper class version { public: diff --git a/lsfg-vk-common/src/vulkan/vulkan.cpp b/lsfg-vk-common/src/vulkan/vulkan.cpp index 6391695..838260d 100644 --- a/lsfg-vk-common/src/vulkan/vulkan.cpp +++ b/lsfg-vk-common/src/vulkan/vulkan.cpp @@ -91,30 +91,6 @@ namespace { ); } - /// initialize vulkan instance function pointers - VulkanInstanceFuncs initVulkanInstanceFuncs(VkInstance i) { - const auto& mpa = get_mpa(); - - return { - .DestroyInstance = ipa(mpa, i, "vkDestroyInstance"), - .EnumeratePhysicalDevices = ipa(mpa, i, - "vkEnumeratePhysicalDevices"), - .EnumerateDeviceExtensionProperties = ipa(mpa, i, - "vkEnumerateDeviceExtensionProperties"), - .GetPhysicalDeviceProperties2 = ipa(mpa, i, - "vkGetPhysicalDeviceProperties2"), - .GetPhysicalDeviceQueueFamilyProperties = - ipa(mpa, i, - "vkGetPhysicalDeviceQueueFamilyProperties"), - .GetPhysicalDeviceFeatures2 = ipa(mpa, i, - "vkGetPhysicalDeviceFeatures2"), - .GetPhysicalDeviceMemoryProperties = ipa(mpa, i, - "vkGetPhysicalDeviceMemoryProperties"), - .CreateDevice = ipa(mpa, i, "vkCreateDevice"), - .GetDeviceProcAddr = ipa(mpa, i, "vkGetDeviceProcAddr"), - }; - } - /// filter for a physical device VkPhysicalDevice findPhysicalDevice(const VulkanInstanceFuncs& fi, VkInstance instance, @@ -222,75 +198,6 @@ namespace { ); } - /// initialize vulkan device function pointers - VulkanDeviceFuncs initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevice d) { - return { - .GetDeviceQueue = dpa(f, d, "vkGetDeviceQueue"), - .DeviceWaitIdle = dpa(f, d, "vkDeviceWaitIdle"), - .CreateCommandPool = dpa(f, d, "vkCreateCommandPool"), - .DestroyCommandPool = dpa(f, d, "vkDestroyCommandPool"), - .CreateDescriptorPool = dpa(f, d, "vkCreateDescriptorPool"), - .DestroyDescriptorPool = dpa(f, d, "vkDestroyDescriptorPool"), - .CreateBuffer = dpa(f, d, "vkCreateBuffer"), - .DestroyBuffer = dpa(f, d, "vkDestroyBuffer"), - .GetBufferMemoryRequirements = dpa(f, d, - "vkGetBufferMemoryRequirements"), - .AllocateMemory = dpa(f, d, "vkAllocateMemory"), - .FreeMemory = dpa(f, d, "vkFreeMemory"), - .BindBufferMemory = dpa(f, d, "vkBindBufferMemory"), - .MapMemory = dpa(f, d, "vkMapMemory"), - .UnmapMemory = dpa(f, d, "vkUnmapMemory"), - .AllocateCommandBuffers = dpa(f, d, - "vkAllocateCommandBuffers"), - .FreeCommandBuffers = dpa(f, d, "vkFreeCommandBuffers"), - .BeginCommandBuffer = dpa(f, d, "vkBeginCommandBuffer"), - .EndCommandBuffer = dpa(f, d, "vkEndCommandBuffer"), - .CmdPipelineBarrier = dpa(f, d, "vkCmdPipelineBarrier"), - .CmdClearColorImage = dpa(f, d, "vkCmdClearColorImage"), - .CmdBindPipeline = dpa(f, d, "vkCmdBindPipeline"), - .CmdBindDescriptorSets = dpa(f, d, "vkCmdBindDescriptorSets"), - .CmdDispatch = dpa(f, d, "vkCmdDispatch"), - .CmdCopyBufferToImage = dpa(f, d, "vkCmdCopyBufferToImage"), - .QueueSubmit = dpa(f, d, "vkQueueSubmit"), - .AllocateDescriptorSets = dpa(f, d, - "vkAllocateDescriptorSets"), - .FreeDescriptorSets = dpa(f, d, "vkFreeDescriptorSets"), - .UpdateDescriptorSets = dpa(f, d, "vkUpdateDescriptorSets"), - .CreateFence = dpa(f, d, "vkCreateFence"), - .DestroyFence = dpa(f, d, "vkDestroyFence"), - .ResetFences = dpa(f, d, "vkResetFences"), - .WaitForFences = dpa(f, d, "vkWaitForFences"), - .CreateImage = dpa(f, d, "vkCreateImage"), - .DestroyImage = dpa(f, d, "vkDestroyImage"), - .GetImageMemoryRequirements = dpa(f, d, - "vkGetImageMemoryRequirements"), - .BindImageMemory = dpa(f, d, "vkBindImageMemory"), - .CreateImageView = dpa(f, d, "vkCreateImageView"), - .DestroyImageView = dpa(f, d, "vkDestroyImageView"), - .CreateSampler = dpa(f, d, "vkCreateSampler"), - .DestroySampler = dpa(f, d, "vkDestroySampler"), - .CreateSemaphore = dpa(f, d, "vkCreateSemaphore"), - .DestroySemaphore = dpa(f, d, "vkDestroySemaphore"), - .CreateShaderModule = dpa(f, d, "vkCreateShaderModule"), - .DestroyShaderModule = dpa(f, d, "vkDestroyShaderModule"), - .CreateDescriptorSetLayout = dpa(f, d, - "vkCreateDescriptorSetLayout"), - .DestroyDescriptorSetLayout = dpa(f, d, - "vkDestroyDescriptorSetLayout"), - .CreatePipelineLayout = dpa(f, d, "vkCreatePipelineLayout"), - .DestroyPipelineLayout = dpa(f, d, "vkDestroyPipelineLayout"), - .CreateComputePipelines = dpa(f, d, - "vkCreateComputePipelines"), - .DestroyPipeline = dpa(f, d, "vkDestroyPipeline"), - .SignalSemaphore = dpa(f, d, "vkSignalSemaphore"), - .WaitSemaphores = dpa(f, d, "vkWaitSemaphores"), - - .GetMemoryFdKHR = dpa(f, d, "vkGetMemoryFdKHR"), - .ImportSemaphoreFdKHR = dpa(f, d, "vkImportSemaphoreFdKHR"), - .GetSemaphoreFdKHR = dpa(f, d, "vkGetSemaphoreFdKHR"), - }; - } - /// get a queue from the logical device VkQueue getQueue(const VulkanDeviceFuncs& fd, VkDevice device, uint32_t cfi) { @@ -352,6 +259,97 @@ namespace { } } +/// initialize vulkan instance function pointers +VulkanInstanceFuncs vk::initVulkanInstanceFuncs(VkInstance i, PFN_vkGetInstanceProcAddr mpa) { + return { + .DestroyInstance = ipa(mpa, i, "vkDestroyInstance"), + .EnumeratePhysicalDevices = ipa(mpa, i, + "vkEnumeratePhysicalDevices"), + .EnumerateDeviceExtensionProperties = ipa(mpa, i, + "vkEnumerateDeviceExtensionProperties"), + .GetPhysicalDeviceProperties2 = ipa(mpa, i, + "vkGetPhysicalDeviceProperties2"), + .GetPhysicalDeviceQueueFamilyProperties = + ipa(mpa, i, + "vkGetPhysicalDeviceQueueFamilyProperties"), + .GetPhysicalDeviceFeatures2 = ipa(mpa, i, + "vkGetPhysicalDeviceFeatures2"), + .GetPhysicalDeviceMemoryProperties = ipa(mpa, i, + "vkGetPhysicalDeviceMemoryProperties"), + .CreateDevice = ipa(mpa, i, "vkCreateDevice"), + .GetDeviceProcAddr = ipa(mpa, i, "vkGetDeviceProcAddr"), + }; +} + +/// initialize vulkan device function pointers +VulkanDeviceFuncs vk::initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevice d) { + return { + .GetDeviceQueue = dpa(f, d, "vkGetDeviceQueue"), + .DeviceWaitIdle = dpa(f, d, "vkDeviceWaitIdle"), + .CreateCommandPool = dpa(f, d, "vkCreateCommandPool"), + .DestroyCommandPool = dpa(f, d, "vkDestroyCommandPool"), + .CreateDescriptorPool = dpa(f, d, "vkCreateDescriptorPool"), + .DestroyDescriptorPool = dpa(f, d, "vkDestroyDescriptorPool"), + .CreateBuffer = dpa(f, d, "vkCreateBuffer"), + .DestroyBuffer = dpa(f, d, "vkDestroyBuffer"), + .GetBufferMemoryRequirements = dpa(f, d, + "vkGetBufferMemoryRequirements"), + .AllocateMemory = dpa(f, d, "vkAllocateMemory"), + .FreeMemory = dpa(f, d, "vkFreeMemory"), + .BindBufferMemory = dpa(f, d, "vkBindBufferMemory"), + .MapMemory = dpa(f, d, "vkMapMemory"), + .UnmapMemory = dpa(f, d, "vkUnmapMemory"), + .AllocateCommandBuffers = dpa(f, d, + "vkAllocateCommandBuffers"), + .FreeCommandBuffers = dpa(f, d, "vkFreeCommandBuffers"), + .BeginCommandBuffer = dpa(f, d, "vkBeginCommandBuffer"), + .EndCommandBuffer = dpa(f, d, "vkEndCommandBuffer"), + .CmdPipelineBarrier = dpa(f, d, "vkCmdPipelineBarrier"), + .CmdClearColorImage = dpa(f, d, "vkCmdClearColorImage"), + .CmdBindPipeline = dpa(f, d, "vkCmdBindPipeline"), + .CmdBindDescriptorSets = dpa(f, d, "vkCmdBindDescriptorSets"), + .CmdDispatch = dpa(f, d, "vkCmdDispatch"), + .CmdCopyBufferToImage = dpa(f, d, "vkCmdCopyBufferToImage"), + .QueueSubmit = dpa(f, d, "vkQueueSubmit"), + .AllocateDescriptorSets = dpa(f, d, + "vkAllocateDescriptorSets"), + .FreeDescriptorSets = dpa(f, d, "vkFreeDescriptorSets"), + .UpdateDescriptorSets = dpa(f, d, "vkUpdateDescriptorSets"), + .CreateFence = dpa(f, d, "vkCreateFence"), + .DestroyFence = dpa(f, d, "vkDestroyFence"), + .ResetFences = dpa(f, d, "vkResetFences"), + .WaitForFences = dpa(f, d, "vkWaitForFences"), + .CreateImage = dpa(f, d, "vkCreateImage"), + .DestroyImage = dpa(f, d, "vkDestroyImage"), + .GetImageMemoryRequirements = dpa(f, d, + "vkGetImageMemoryRequirements"), + .BindImageMemory = dpa(f, d, "vkBindImageMemory"), + .CreateImageView = dpa(f, d, "vkCreateImageView"), + .DestroyImageView = dpa(f, d, "vkDestroyImageView"), + .CreateSampler = dpa(f, d, "vkCreateSampler"), + .DestroySampler = dpa(f, d, "vkDestroySampler"), + .CreateSemaphore = dpa(f, d, "vkCreateSemaphore"), + .DestroySemaphore = dpa(f, d, "vkDestroySemaphore"), + .CreateShaderModule = dpa(f, d, "vkCreateShaderModule"), + .DestroyShaderModule = dpa(f, d, "vkDestroyShaderModule"), + .CreateDescriptorSetLayout = dpa(f, d, + "vkCreateDescriptorSetLayout"), + .DestroyDescriptorSetLayout = dpa(f, d, + "vkDestroyDescriptorSetLayout"), + .CreatePipelineLayout = dpa(f, d, "vkCreatePipelineLayout"), + .DestroyPipelineLayout = dpa(f, d, "vkDestroyPipelineLayout"), + .CreateComputePipelines = dpa(f, d, + "vkCreateComputePipelines"), + .DestroyPipeline = dpa(f, d, "vkDestroyPipeline"), + .SignalSemaphore = dpa(f, d, "vkSignalSemaphore"), + .WaitSemaphores = dpa(f, d, "vkWaitSemaphores"), + + .GetMemoryFdKHR = dpa(f, d, "vkGetMemoryFdKHR"), + .ImportSemaphoreFdKHR = dpa(f, d, "vkImportSemaphoreFdKHR"), + .GetSemaphoreFdKHR = dpa(f, d, "vkGetSemaphoreFdKHR"), + }; +} + Vulkan::Vulkan(const std::string& appName, version appVersion, const std::string& engineName, version engineVersion, PhysicalDeviceSelector selectPhysicalDevice) : @@ -359,7 +357,7 @@ Vulkan::Vulkan(const std::string& appName, version appVersion, appName, appVersion, engineName, engineVersion )), - instance_funcs(initVulkanInstanceFuncs(*this->instance)), + instance_funcs(initVulkanInstanceFuncs(*this->instance, get_mpa())), physdev(findPhysicalDevice(this->instance_funcs, *this->instance, selectPhysicalDevice diff --git a/lsfg-vk-layer/.clang-tidy b/lsfg-vk-layer/.clang-tidy index b6bc01c..8a9ce4f 100644 --- a/lsfg-vk-layer/.clang-tidy +++ b/lsfg-vk-layer/.clang-tidy @@ -26,6 +26,7 @@ Checks: - "-cppcoreguidelines-macro-usage" - "-cppcoreguidelines-pro-type-union-access" - "-cppcoreguidelines-avoid-non-const-global-variables" +- "-cppcoreguidelines-pro-type-const-cast" # disable slow and pointless checks - "-modernize-use-std-numbers" - "-modernize-type-traits" diff --git a/lsfg-vk-layer/src/entrypoint.cpp b/lsfg-vk-layer/src/entrypoint.cpp index 225041d..ba7fe6e 100644 --- a/lsfg-vk-layer/src/entrypoint.cpp +++ b/lsfg-vk-layer/src/entrypoint.cpp @@ -1,11 +1,11 @@ #include "layer.hpp" +#include "lsfg-vk-common/vulkan/vulkan.hpp" #include #include #include #include #include -#include #include #include #include @@ -33,28 +33,36 @@ namespace { return extensions; } + + /// struct containing various helper globals + struct Globals { + layer::Layer layer; + + VkInstance instance{VK_NULL_HANDLE}; // if there are multiple instances, we scream + vk::VulkanInstanceFuncs fi{}; + + std::unordered_map procAddrMap; // all overriden pointers + + std::unordered_map device2InstanceMap; + }; } namespace { - PFN_vkGetInstanceProcAddr nxvkGetInstanceProcAddr{nullptr}; - PFN_vkGetDeviceProcAddr nxvkGetDeviceProcAddr = nullptr; - - auto& layer() { - static std::optional instance; // NOLINT - return instance; - } - - VkInstance gInstance{VK_NULL_HANDLE}; // if there are multiple instances, we scream out loud, oke? + Globals* global{nullptr}; + void populateProcAddrMap(); // create instance + PFN_vkGetInstanceProcAddr nxvkGetInstanceProcAddr{nullptr}; VkResult myvkCreateInstance( const VkInstanceCreateInfo* info, const VkAllocationCallbacks* alloc, VkInstance* instance) { // try to load lsfg-vk layer try { - if (!layer().has_value()) - layer().emplace(); + if (!global) { // cleanup in vkDestroyInstance + global = new Globals(); + populateProcAddrMap(); + } } catch (const std::exception& e) { std::cerr << "lsfg-vk: something went wrong during lsfg-vk layer initialization:\n"; std::cerr << "- " << e.what() << '\n'; @@ -97,14 +105,14 @@ namespace { return VK_ERROR_INITIALIZATION_FAILED; } - const auto& l = layer(); - if (!l.has_value() || !l->active()) // skip inactive + const auto& l = global; + if (!l || !l->layer.active()) // skip inactive return vkCreateInstance(info, alloc, instance); auto extensions = add_extensions( info->ppEnabledExtensionNames, info->enabledExtensionCount, - l->instanceExtensions()); + l->layer.instanceExtensions()); VkInstanceCreateInfo newInfo = *info; newInfo.enabledExtensionCount = static_cast(extensions.size()); @@ -118,17 +126,13 @@ namespace { if (res != VK_SUCCESS) return res; - gInstance = *instance; + l->instance = *instance; + l->fi = vk::initVulkanInstanceFuncs(l->instance, nxvkGetInstanceProcAddr); return VK_SUCCESS; } - // map of devices to layer instances - std::unordered_map& device2InstanceMap() { - static std::unordered_map map; // NOLINT - return map; - } - // create device + PFN_vkGetDeviceProcAddr nxvkGetDeviceProcAddr{nullptr}; VkResult myvkCreateDevice( VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* info, @@ -153,8 +157,9 @@ namespace { return VK_ERROR_INITIALIZATION_FAILED; } + global->fi.GetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr; nxvkGetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr; - if (!nxvkGetDeviceProcAddr) { + if (!linkInfo->pfnNextGetDeviceProcAddr) { std::cerr << "lsfg-vk: next layer's vkGetDeviceProcAddr is null, " "the previous layer does not follow spec\n"; return VK_ERROR_INITIALIZATION_FAILED; @@ -180,28 +185,16 @@ namespace { } // create device - auto* vkCreateDevice = reinterpret_cast( - nxvkGetInstanceProcAddr(gInstance, "vkCreateDevice")); - if (!vkCreateDevice) { - std::cerr << "lsfg-vk: failed to get next layer's vkCreateDevice, " - "the previous layer does not follow spec\n"; - return VK_ERROR_INITIALIZATION_FAILED; - } - - const auto& l = layer(); - if (!l.has_value() || !l->active()) // skip inactive - return vkCreateDevice(physicalDevice, info, alloc, device); - auto extensions = add_extensions( info->ppEnabledExtensionNames, info->enabledExtensionCount, - l->deviceExtensions()); + global->layer.deviceExtensions()); VkDeviceCreateInfo newInfo = *info; newInfo.enabledExtensionCount = static_cast(extensions.size()); newInfo.ppEnabledExtensionNames = extensions.data(); - auto res = vkCreateDevice(physicalDevice, &newInfo, alloc, device); + auto res = global->fi.CreateDevice(physicalDevice, &newInfo, alloc, device); if (res == VK_ERROR_EXTENSION_NOT_PRESENT) std::cerr << "lsfg-vk: required Vulkan device extensions are not present. " "Your GPU driver is not supported.\n"; @@ -211,8 +204,14 @@ namespace { // create layer instance try { - device2InstanceMap().emplace(*device, - layer::LayerInstance(*l, gInstance, *device, setLoaderData)); + global->device2InstanceMap.emplace( + *device, + layer::LayerInstance( + global->layer, vk::initVulkanDeviceFuncs(global->fi, *device), + global->instance, *device, + setLoaderData + ) + ); } catch (const std::exception& e) { std::cerr << "lsfg-vk: something went wrong during lsfg-vk initialization:\n"; std::cerr << "- " << e.what() << '\n'; @@ -221,12 +220,32 @@ namespace { return VK_SUCCESS; } - PFN_vkVoidFunction getProcAddr(const std::string& name); + // populate function pointer override map + void populateProcAddrMap() { +#define VKPTR(name) reinterpret_cast(name) + global->procAddrMap = { + { "vkCreateInstance", VKPTR(myvkCreateInstance) }, + { "vkCreateDevice", VKPTR(myvkCreateDevice) }, + }; +#undef VKPTR + } + + // get optional function pointer override + PFN_vkVoidFunction getProcAddr(const std::string& name) { + if (!global) return nullptr; + auto it = global->procAddrMap.find(name); + if (it != global->procAddrMap.end()) + return it->second; + return nullptr; + } // get instance-level function pointers PFN_vkVoidFunction myvkGetInstanceProcAddr(VkInstance instance, const char* pName) { if (!pName) return nullptr; + if (std::string(pName) == "vkCreateInstance") // pre-instance function + return reinterpret_cast(myvkCreateInstance); + auto func = getProcAddr(pName); if (func) return func; @@ -245,15 +264,6 @@ namespace { return nxvkGetDeviceProcAddr(device, pName); } - // get optional function pointer override - PFN_vkVoidFunction getProcAddr(const std::string& name) { - if (name == "vkCreateInstance") - return reinterpret_cast(&myvkCreateInstance); - if (name == "vkCreateDevice") - return reinterpret_cast(&myvkCreateDevice); - return nullptr; - } - } /// Vulkan layer entrypoint diff --git a/lsfg-vk-layer/src/layer.cpp b/lsfg-vk-layer/src/layer.cpp index b4a0032..25c3c22 100644 --- a/lsfg-vk-layer/src/layer.cpp +++ b/lsfg-vk-layer/src/layer.cpp @@ -1,5 +1,6 @@ #include "layer.hpp" #include "detection.hpp" +#include "lsfg-vk-common/vulkan/vulkan.hpp" #include #include @@ -72,7 +73,7 @@ std::vector Layer::deviceExtensions() const { }; } -layer::LayerInstance::LayerInstance(const Layer& layer, +layer::LayerInstance::LayerInstance(const Layer& layer, vk::VulkanDeviceFuncs df, VkInstance instance, VkDevice device, PFN_vkSetDeviceLoaderData setLoaderData) { std::cerr << "lsfg-vk: Hello, world!\n"; diff --git a/lsfg-vk-layer/src/layer.hpp b/lsfg-vk-layer/src/layer.hpp index b475035..b3da8e2 100644 --- a/lsfg-vk-layer/src/layer.hpp +++ b/lsfg-vk-layer/src/layer.hpp @@ -2,9 +2,9 @@ #include "config.hpp" #include "detection.hpp" +#include "lsfg-vk-common/vulkan/vulkan.hpp" #include -#include #include #include @@ -48,10 +48,11 @@ namespace lsfgvk::layer { public: /// create a new layer instance /// @param layer parent layer + /// @param df Vulkan device function pointers /// @param instance Vulkan instance /// @param device Vulkan device /// @param setLoaderData function to set device loader data - LayerInstance(const Layer& layer, + LayerInstance(const Layer& layer, vk::VulkanDeviceFuncs df, VkInstance instance, VkDevice device, PFN_vkSetDeviceLoaderData setLoaderData); private: