mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-05-10 03:01:40 +00:00
refactor(cleanup): deinitialization logic
This commit is contained in:
parent
6f5f8edbdd
commit
6bd907516a
1 changed files with 122 additions and 66 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <vulkan/vk_layer.h>
|
#include <vulkan/vk_layer.h>
|
||||||
|
|
@ -33,41 +34,38 @@ namespace {
|
||||||
|
|
||||||
return extensions;
|
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<std::string, PFN_vkVoidFunction> procAddrMap; // all overriden pointers
|
|
||||||
|
|
||||||
std::unordered_map<VkDevice, layer::LayerInstance> device2InstanceMap;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Globals* global{nullptr};
|
// device-wide info initialized at device creation
|
||||||
void populateProcAddrMap();
|
struct DeviceInfo {
|
||||||
|
VkDevice handle;
|
||||||
|
vk::VulkanDeviceFuncs funcs;
|
||||||
|
|
||||||
|
layer::Instance layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// instance-wide info initialized at instance creation
|
||||||
|
struct InstanceInfo {
|
||||||
|
VkInstance handle;
|
||||||
|
vk::VulkanInstanceFuncs funcs;
|
||||||
|
|
||||||
|
std::unordered_map<VkDevice, DeviceInfo*> devices;
|
||||||
|
}* instance_info;
|
||||||
|
|
||||||
|
// global layer info initialized at layer negotiation
|
||||||
|
struct LayerInfo {
|
||||||
|
layer::Layer layer; //!< basic layer info
|
||||||
|
std::unordered_map<std::string, PFN_vkVoidFunction> map; //!< function pointer override map
|
||||||
|
|
||||||
|
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||||
|
}* layer_info;
|
||||||
|
|
||||||
// create instance
|
// create instance
|
||||||
PFN_vkGetInstanceProcAddr nxvkGetInstanceProcAddr{nullptr};
|
|
||||||
VkResult myvkCreateInstance(
|
VkResult myvkCreateInstance(
|
||||||
const VkInstanceCreateInfo* info,
|
const VkInstanceCreateInfo* info,
|
||||||
const VkAllocationCallbacks* alloc,
|
const VkAllocationCallbacks* alloc,
|
||||||
VkInstance* instance) {
|
VkInstance* instance) {
|
||||||
// try to load lsfg-vk layer
|
|
||||||
try {
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply layer chaining
|
// apply layer chaining
|
||||||
auto* layerInfo = reinterpret_cast<VkLayerInstanceCreateInfo*>(const_cast<void*>(info->pNext));
|
auto* layerInfo = reinterpret_cast<VkLayerInstanceCreateInfo*>(const_cast<void*>(info->pNext));
|
||||||
while (layerInfo && (layerInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
while (layerInfo && (layerInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||||
|
|
@ -87,8 +85,8 @@ namespace {
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxvkGetInstanceProcAddr = linkInfo->pfnNextGetInstanceProcAddr;
|
layer_info->GetInstanceProcAddr = linkInfo->pfnNextGetInstanceProcAddr;
|
||||||
if (!nxvkGetInstanceProcAddr) {
|
if (!layer_info->GetInstanceProcAddr) {
|
||||||
std::cerr << "lsfg-vk: next layer's vkGetInstanceProcAddr is null, "
|
std::cerr << "lsfg-vk: next layer's vkGetInstanceProcAddr is null, "
|
||||||
"the previous layer does not follow spec\n";
|
"the previous layer does not follow spec\n";
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
|
|
@ -98,21 +96,17 @@ namespace {
|
||||||
|
|
||||||
// create instance
|
// create instance
|
||||||
auto* vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
|
auto* vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
|
||||||
nxvkGetInstanceProcAddr(nullptr, "vkCreateInstance"));
|
layer_info->GetInstanceProcAddr(nullptr, "vkCreateInstance"));
|
||||||
if (!vkCreateInstance) {
|
if (!vkCreateInstance) {
|
||||||
std::cerr << "lsfg-vk: failed to get next layer's vkCreateInstance, "
|
std::cerr << "lsfg-vk: failed to get next layer's vkCreateInstance, "
|
||||||
"the previous layer does not follow spec\n";
|
"the previous layer does not follow spec\n";
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& l = global;
|
|
||||||
if (!l || !l->layer.active()) // skip inactive
|
|
||||||
return vkCreateInstance(info, alloc, instance);
|
|
||||||
|
|
||||||
auto extensions = add_extensions(
|
auto extensions = add_extensions(
|
||||||
info->ppEnabledExtensionNames,
|
info->ppEnabledExtensionNames,
|
||||||
info->enabledExtensionCount,
|
info->enabledExtensionCount,
|
||||||
l->layer.instanceExtensions());
|
layer_info->layer.instanceExtensions());
|
||||||
|
|
||||||
VkInstanceCreateInfo newInfo = *info;
|
VkInstanceCreateInfo newInfo = *info;
|
||||||
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
|
|
@ -126,13 +120,15 @@ namespace {
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
l->instance = *instance;
|
instance_info = new InstanceInfo{
|
||||||
l->fi = vk::initVulkanInstanceFuncs(l->instance, nxvkGetInstanceProcAddr);
|
.handle = *instance,
|
||||||
|
.funcs = vk::initVulkanInstanceFuncs(*instance, layer_info->GetInstanceProcAddr),
|
||||||
|
.devices = {}
|
||||||
|
};
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create device
|
// create device
|
||||||
PFN_vkGetDeviceProcAddr nxvkGetDeviceProcAddr{nullptr};
|
|
||||||
VkResult myvkCreateDevice(
|
VkResult myvkCreateDevice(
|
||||||
VkPhysicalDevice physdev,
|
VkPhysicalDevice physdev,
|
||||||
const VkDeviceCreateInfo* info,
|
const VkDeviceCreateInfo* info,
|
||||||
|
|
@ -157,8 +153,7 @@ namespace {
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
global->fi.GetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr;
|
instance_info->funcs.GetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr;
|
||||||
nxvkGetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr;
|
|
||||||
if (!linkInfo->pfnNextGetDeviceProcAddr) {
|
if (!linkInfo->pfnNextGetDeviceProcAddr) {
|
||||||
std::cerr << "lsfg-vk: next layer's vkGetDeviceProcAddr is null, "
|
std::cerr << "lsfg-vk: next layer's vkGetDeviceProcAddr is null, "
|
||||||
"the previous layer does not follow spec\n";
|
"the previous layer does not follow spec\n";
|
||||||
|
|
@ -188,13 +183,13 @@ namespace {
|
||||||
auto extensions = add_extensions(
|
auto extensions = add_extensions(
|
||||||
info->ppEnabledExtensionNames,
|
info->ppEnabledExtensionNames,
|
||||||
info->enabledExtensionCount,
|
info->enabledExtensionCount,
|
||||||
global->layer.deviceExtensions());
|
layer_info->layer.deviceExtensions());
|
||||||
|
|
||||||
VkDeviceCreateInfo newInfo = *info;
|
VkDeviceCreateInfo newInfo = *info;
|
||||||
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
newInfo.ppEnabledExtensionNames = extensions.data();
|
newInfo.ppEnabledExtensionNames = extensions.data();
|
||||||
|
|
||||||
auto res = global->fi.CreateDevice(physdev, &newInfo, alloc, device);
|
auto res = instance_info->funcs.CreateDevice(physdev, &newInfo, alloc, device);
|
||||||
if (res == VK_ERROR_EXTENSION_NOT_PRESENT)
|
if (res == VK_ERROR_EXTENSION_NOT_PRESENT)
|
||||||
std::cerr << "lsfg-vk: required Vulkan device extensions are not present. "
|
std::cerr << "lsfg-vk: required Vulkan device extensions are not present. "
|
||||||
"Your GPU driver is not supported.\n";
|
"Your GPU driver is not supported.\n";
|
||||||
|
|
@ -204,18 +199,21 @@ namespace {
|
||||||
|
|
||||||
// create layer instance
|
// create layer instance
|
||||||
try {
|
try {
|
||||||
global->device2InstanceMap.emplace(
|
instance_info->devices.emplace(
|
||||||
*device,
|
*device,
|
||||||
layer::LayerInstance(
|
new DeviceInfo{
|
||||||
global->layer,
|
.handle = *device,
|
||||||
vk::Vulkan(
|
.funcs = vk::initVulkanDeviceFuncs(instance_info->funcs, *device),
|
||||||
global->instance, *device,
|
.layer = layer::Instance(
|
||||||
physdev,
|
layer_info->layer,
|
||||||
global->fi,
|
vk::Vulkan(
|
||||||
vk::initVulkanDeviceFuncs(global->fi, *device),
|
instance_info->handle, *device, physdev,
|
||||||
setLoaderData
|
instance_info->funcs,
|
||||||
|
vk::initVulkanDeviceFuncs(instance_info->funcs, *device),
|
||||||
|
true, setLoaderData
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
);
|
);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk initialization:\n";
|
std::cerr << "lsfg-vk: something went wrong during lsfg-vk initialization:\n";
|
||||||
|
|
@ -225,21 +223,57 @@ namespace {
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate function pointer override map
|
// destroy device
|
||||||
void populateProcAddrMap() {
|
void myvkDestroyDevice(VkDevice device, const VkAllocationCallbacks* alloc) {
|
||||||
#define VKPTR(name) reinterpret_cast<PFN_vkVoidFunction>(name)
|
// destroy layer instance
|
||||||
global->procAddrMap = {
|
auto it = instance_info->devices.find(device);
|
||||||
{ "vkCreateInstance", VKPTR(myvkCreateInstance) },
|
if (it != instance_info->devices.end()) {
|
||||||
{ "vkCreateDevice", VKPTR(myvkCreateDevice) },
|
delete it->second;
|
||||||
};
|
instance_info->devices.erase(it);
|
||||||
#undef VKPTR
|
}
|
||||||
|
|
||||||
|
// destroy device
|
||||||
|
auto vkDestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
|
||||||
|
instance_info->funcs.GetDeviceProcAddr(device, "vkDestroyDevice"));
|
||||||
|
if (!vkDestroyDevice) {
|
||||||
|
std::cerr << "lsfg-vk: failed to get next layer's vkDestroyDevice, "
|
||||||
|
"the previous layer does not follow spec\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyDevice(device, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy instance
|
||||||
|
void myvkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* alloc) {
|
||||||
|
// destroy instance info
|
||||||
|
delete instance_info;
|
||||||
|
instance_info = nullptr;
|
||||||
|
|
||||||
|
// destroy instance
|
||||||
|
auto vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
|
||||||
|
layer_info->GetInstanceProcAddr(instance, "vkDestroyInstance"));
|
||||||
|
if (!vkDestroyInstance) {
|
||||||
|
std::cerr << "lsfg-vk: failed to get next layer's vkDestroyInstance, "
|
||||||
|
"the previous layer does not follow spec\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyInstance(instance, alloc);
|
||||||
|
|
||||||
|
// destroy layer info
|
||||||
|
// NOTE: there's no real way of unloading the layer without a deconstructor.
|
||||||
|
// multiple instances just aren't common enough to worry about it.
|
||||||
|
// NOTE2: it doesn't really matter anyways, because the myvkDestroyDevice code
|
||||||
|
// freezes the entire thing anyways.
|
||||||
|
delete layer_info;
|
||||||
|
layer_info = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get optional function pointer override
|
// get optional function pointer override
|
||||||
PFN_vkVoidFunction getProcAddr(const std::string& name) {
|
PFN_vkVoidFunction getProcAddr(const std::string& name) {
|
||||||
if (!global) return nullptr;
|
auto it = layer_info->map.find(name);
|
||||||
auto it = global->procAddrMap.find(name);
|
if (it != layer_info->map.end())
|
||||||
if (it != global->procAddrMap.end())
|
|
||||||
return it->second;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -254,8 +288,8 @@ namespace {
|
||||||
auto func = getProcAddr(pName);
|
auto func = getProcAddr(pName);
|
||||||
if (func) return func;
|
if (func) return func;
|
||||||
|
|
||||||
if (!nxvkGetInstanceProcAddr) return nullptr;
|
if (!layer_info->GetInstanceProcAddr) return nullptr;
|
||||||
return nxvkGetInstanceProcAddr(instance, pName);
|
return layer_info->GetInstanceProcAddr(instance, pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get device-level function pointers
|
// get device-level function pointers
|
||||||
|
|
@ -265,8 +299,8 @@ namespace {
|
||||||
auto func = getProcAddr(pName);
|
auto func = getProcAddr(pName);
|
||||||
if (func) return func;
|
if (func) return func;
|
||||||
|
|
||||||
if (!nxvkGetDeviceProcAddr) return nullptr;
|
if (!instance_info->funcs.GetDeviceProcAddr) return nullptr;
|
||||||
return nxvkGetDeviceProcAddr(device, pName);
|
return instance_info->funcs.GetDeviceProcAddr(device, pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -280,6 +314,28 @@ VkResult vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVers
|
||||||
|| pVersionStruct->loaderLayerInterfaceVersion < 2)
|
|| pVersionStruct->loaderLayerInterfaceVersion < 2)
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
|
|
||||||
|
// load the layer configuration
|
||||||
|
try {
|
||||||
|
layer::Layer layer{};
|
||||||
|
if (!layer.active()) // skip inactive
|
||||||
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
|
|
||||||
|
layer_info = new LayerInfo{
|
||||||
|
.layer = std::move(layer),
|
||||||
|
.map = {
|
||||||
|
#define VKPTR(name) reinterpret_cast<PFN_vkVoidFunction>(name)
|
||||||
|
{ "vkCreateInstance", VKPTR(myvkCreateInstance) },
|
||||||
|
{ "vkCreateDevice", VKPTR(myvkCreateDevice) },
|
||||||
|
{ "vkDestroyDevice", VKPTR(myvkDestroyDevice) },
|
||||||
|
{ "vkDestroyInstance", VKPTR(myvkDestroyInstance) }
|
||||||
|
#undef VKPTR
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "lsfg-vk: something went wrong during lsfg-vk layer initialization:\n";
|
||||||
|
std::cerr << "- " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
// emplace function pointers/version
|
// emplace function pointers/version
|
||||||
pVersionStruct->loaderLayerInterfaceVersion = 2;
|
pVersionStruct->loaderLayerInterfaceVersion = 2;
|
||||||
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
|
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue