Add support for a full volk replacement by supporting a global DispatchLoaderDynamic. The global dynamic dispatcher will be available if either the define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is set to 1 or if VK_NO_PROTOTYPES is defined. In those cases it is required to add VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE; to any compilation unit of the project to allocate storage for the dispatcher. (#390)

This commit is contained in:
Markus Tavenrath 2019-09-25 11:59:39 +02:00 committed by Andreas Süßenbach
parent 9df0fac638
commit e26cb8113a
3 changed files with 2449 additions and 2075 deletions

View File

@ -1100,13 +1100,13 @@ void VulkanHppGenerator::appendDispatchLoaderDynamic(std::string & str)
#if !defined(VK_NO_PROTOTYPES) #if !defined(VK_NO_PROTOTYPES)
// This interface is designed to be used for per-device function pointers in combination with a linked vulkan library. // This interface is designed to be used for per-device function pointers in combination with a linked vulkan library.
DispatchLoaderDynamic(vk::Instance const& instance, vk::Device const& device = {}) DispatchLoaderDynamic(vk::Instance const& instance, vk::Device const& device)
{ {
init(instance, device); init(instance, device);
} }
// This interface is designed to be used for per-device function pointers in combination with a linked vulkan library. // This interface is designed to be used for per-device function pointers in combination with a linked vulkan library.
void init(vk::Instance const& instance, vk::Device const& device = {}) void init(vk::Instance const& instance, vk::Device const& device)
{ {
init(static_cast<VkInstance>(instance), ::vkGetInstanceProcAddr, static_cast<VkDevice>(device), device ? ::vkGetDeviceProcAddr : nullptr); init(static_cast<VkInstance>(instance), ::vkGetInstanceProcAddr, static_cast<VkDevice>(device), device ? ::vkGetDeviceProcAddr : nullptr);
} }
@ -1134,47 +1134,75 @@ void VulkanHppGenerator::appendDispatchLoaderDynamic(std::string & str)
} }
// This interface does not require a linked vulkan library. // This interface does not require a linked vulkan library.
void init( VkInstance instance, PFN_vkGetInstanceProcAddr getInstanceProcAddr, VkDevice device = VK_NULL_HANDLE, PFN_vkGetDeviceProcAddr getDeviceProcAddr = nullptr ) void init( VkInstance instance, PFN_vkGetInstanceProcAddr getInstanceProcAddr, VkDevice device = VK_NULL_HANDLE, PFN_vkGetDeviceProcAddr /*getDeviceProcAddr*/ = nullptr )
{ {
VULKAN_HPP_ASSERT(instance && getInstanceProcAddr); VULKAN_HPP_ASSERT(instance && getInstanceProcAddr);
vkGetInstanceProcAddr = getInstanceProcAddr; vkGetInstanceProcAddr = getInstanceProcAddr;
vkGetDeviceProcAddr = getDeviceProcAddr ? getDeviceProcAddr : PFN_vkGetDeviceProcAddr( vkGetInstanceProcAddr( instance, "vkGetDeviceProcAddr") ); init( vk::Instance(instance) );
if (device) {
init( vk::Device(device) );
}
}
void init( vk::Instance instance )
{
)"; )";
std::string strDeviceFunctions;
std::string strDeviceFunctionsInstance;
std::string strInstanceFunctions;
for (auto const& handle : m_handles) for (auto const& handle : m_handles)
{ {
for (auto const& command : handle.second.commands) for (auto const& command : handle.second.commands)
{ {
if ((command.first != "vkGetDeviceProcAddr") && (command.first != "vkGetInstanceProcAddr")) if ((command.first != "vkGetInstanceProcAddr"))
{ {
std::string enter, leave; std::string enter, leave;
appendPlatformEnter(enter, command.second.platform); appendPlatformEnter(enter, command.second.platform);
appendPlatformLeave(leave, command.second.platform); appendPlatformLeave(leave, command.second.platform);
str += enter;
if (!command.second.params.empty() if (!command.second.params.empty()
&& m_handles.find(command.second.params[0].type.type) != m_handles.end() && m_handles.find(command.second.params[0].type.type) != m_handles.end()
&& command.second.params[0].type.type != "VkInstance" && command.second.params[0].type.type != "VkInstance"
&& command.second.params[0].type.type != "VkPhysicalDevice") && command.second.params[0].type.type != "VkPhysicalDevice")
{ {
str += " " + command.first + " = PFN_" + command.first strDeviceFunctions += enter;
+ "( device ? vkGetDeviceProcAddr( device, \"" + command.first + "\" ) : vkGetInstanceProcAddr( instance, \"" + command.first + "\" ) );\n"; strDeviceFunctions += " " + command.first + " = PFN_" + command.first
+ "( vkGetDeviceProcAddr( device, \"" + command.first + "\" ) );\n";
strDeviceFunctions += leave;
strDeviceFunctionsInstance += enter;
strDeviceFunctionsInstance += " " + command.first + " = PFN_" + command.first
+ "( vkGetInstanceProcAddr( instance, \"" + command.first + "\" ) );\n";
strDeviceFunctionsInstance += leave;
} }
else else
{ {
str += " " + command.first + " = PFN_" + command.first + "( vkGetInstanceProcAddr( instance, \"" + command.first + "\" ) );\n"; strInstanceFunctions += enter;
strInstanceFunctions += " " + command.first + " = PFN_" + command.first + "( vkGetInstanceProcAddr( instance, \"" + command.first + "\" ) );\n";
strInstanceFunctions += leave;
} }
str += leave;
} }
} }
} }
str += " }\n"
" };\n"; str += strInstanceFunctions;
str += strDeviceFunctionsInstance;
str += " }\n\n";
str += " void init( vk::Device device )\n {\n";
str += strDeviceFunctions;
str += R"( }
};
#define VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE namespace vk { DispatchLoaderDynamic defaultDispatchLoaderDynamic; }
)";
} }
void VulkanHppGenerator::appendDispatchLoaderStatic(std::string & str) void VulkanHppGenerator::appendDispatchLoaderStatic(std::string & str)
{ {
str += R"( str += R"(
#if !defined(VK_NO_PROTOTYPES)
class DispatchLoaderStatic class DispatchLoaderStatic
{ {
public:)"; public:)";
@ -1211,19 +1239,35 @@ void VulkanHppGenerator::appendDispatchLoaderStatic(std::string & str)
appendPlatformLeave(str, command.second.platform); appendPlatformLeave(str, command.second.platform);
} }
} }
str += " };\n"; str += " };\n#endif\n";
} }
void VulkanHppGenerator::appendDispatchLoaderDefault(std::string & str) void VulkanHppGenerator::appendDispatchLoaderDefault(std::string & str)
{ {
str += "\n" str += "\n"
"#if !defined(VK_NO_PROTOTYPES)"; R"( class DispatchLoaderDynamic;
appendDispatchLoaderStatic(str); #if !defined(VULKAN_HPP_DISPATCH_LOADER_DYNAMIC)
str += R"( # if defined(VK_NO_PROTOTYPES)
typedef DispatchLoaderStatic DispatchLoaderDefault; # define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#else // !defined(VK_NO_PROTOTYPES) # else
class NeedExplicitDispatchLoader; # define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 0
typedef NeedExplicitDispatchLoader DispatchLoaderDefault; # endif
#endif
#if !defined(VULKAN_HPP_DEFAULT_DISPATCHER)
# if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
#define VULKAN_HPP_DEFAULT_DISPATCHER ::vk::defaultDispatchLoaderDynamic
# else
# define VULKAN_HPP_DEFAULT_DISPATCHER ::vk::DispatchLoaderStatic()
# endif
#endif
#if !defined(VULKAN_HPP_DEFAULT_DISPATCHER_TYPE)
# if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
#define VULKAN_HPP_DEFAULT_DISPATCHER_TYPE ::vk::DispatchLoaderDynamic
# else
# define VULKAN_HPP_DEFAULT_DISPATCHER_TYPE ::vk::DispatchLoaderStatic
# endif
#endif #endif
)"; )";
} }
@ -1950,7 +1994,7 @@ void VulkanHppGenerator::appendFunctionHeaderArgumentsEnhanced(std::string & str
str += "Dispatch const &d"; str += "Dispatch const &d";
if (withDefaults && !withAllocator) if (withDefaults && !withAllocator)
{ {
str += " = Dispatch()"; str += " = VULKAN_HPP_DEFAULT_DISPATCHER";
} }
str += " "; str += " ";
} }
@ -1977,7 +2021,7 @@ void VulkanHppGenerator::appendFunctionHeaderArgumentsStandard(std::string & str
str += "Dispatch const &d"; str += "Dispatch const &d";
if (withDefaults) if (withDefaults)
{ {
str += " = Dispatch() "; str += " = VULKAN_HPP_DEFAULT_DISPATCHER ";
} }
} }
@ -2087,7 +2131,7 @@ void VulkanHppGenerator::appendFunctionHeaderTemplate(std::string & str, std::st
str += ", "; str += ", ";
} }
} }
str += std::string("typename Dispatch") + (withDefault ? " = DispatchLoaderDefault" : "") + ">\n"; str += std::string("typename Dispatch") + (withDefault ? " = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE" : "") + ">\n";
} }
void VulkanHppGenerator::appendHandle(std::string & str, std::pair<std::string, HandleData> const& handleData, std::set<std::string> & listedHandles) const void VulkanHppGenerator::appendHandle(std::string & str, std::pair<std::string, HandleData> const& handleData, std::set<std::string> & listedHandles) const
@ -2908,7 +2952,7 @@ void VulkanHppGenerator::appendUniqueTypes(std::string & str, std::string const&
std::string deleterPool = handleIt->second.deletePool.empty() ? "" : ", " + stripPrefix(handleIt->second.deletePool, "Vk"); std::string deleterPool = handleIt->second.deletePool.empty() ? "" : ", " + stripPrefix(handleIt->second.deletePool, "Vk");
str += "\n" str += "\n"
" template <typename Dispatch> class UniqueHandleTraits<" + type + ", Dispatch> { public: using deleter = " + deleterType + deleterAction + "<" + deleterParent + deleterPool + ", Dispatch>; };\n" " template <typename Dispatch> class UniqueHandleTraits<" + type + ", Dispatch> { public: using deleter = " + deleterType + deleterAction + "<" + deleterParent + deleterPool + ", Dispatch>; };\n"
" using Unique" + type + " = UniqueHandle<" + type + ", DispatchLoaderDefault>;"; " using Unique" + type + " = UniqueHandle<" + type + ", VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>;";
} }
str += "\n" str += "\n"
"#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n"; "#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n";
@ -4501,7 +4545,7 @@ int main( int argc, char **argv )
class ObjectDestroy class ObjectDestroy
{ {
public: public:
ObjectDestroy( OwnerType owner = OwnerType(), Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = Dispatch() ) ObjectDestroy( OwnerType owner = OwnerType(), Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = VULKAN_HPP_DEFAULT_DISPATCHER )
: m_owner( owner ) : m_owner( owner )
, m_allocationCallbacks( allocationCallbacks ) , m_allocationCallbacks( allocationCallbacks )
, m_dispatch( &dispatch ) , m_dispatch( &dispatch )
@ -4529,7 +4573,7 @@ int main( int argc, char **argv )
class ObjectDestroy<NoParent,Dispatch> class ObjectDestroy<NoParent,Dispatch>
{ {
public: public:
ObjectDestroy( Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = Dispatch() ) ObjectDestroy( Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = VULKAN_HPP_DEFAULT_DISPATCHER )
: m_allocationCallbacks( allocationCallbacks ) : m_allocationCallbacks( allocationCallbacks )
, m_dispatch( &dispatch ) , m_dispatch( &dispatch )
{} {}
@ -4554,7 +4598,7 @@ int main( int argc, char **argv )
class ObjectFree class ObjectFree
{ {
public: public:
ObjectFree( OwnerType owner = OwnerType(), Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = Dispatch() ) ObjectFree( OwnerType owner = OwnerType(), Optional<const AllocationCallbacks> allocationCallbacks = nullptr, Dispatch const &dispatch = VULKAN_HPP_DEFAULT_DISPATCHER )
: m_owner( owner ) : m_owner( owner )
, m_allocationCallbacks( allocationCallbacks ) , m_allocationCallbacks( allocationCallbacks )
, m_dispatch( &dispatch ) , m_dispatch( &dispatch )
@ -4600,7 +4644,7 @@ int main( int argc, char **argv )
class PoolFree class PoolFree
{ {
public: public:
PoolFree( OwnerType owner = OwnerType(), PoolType pool = PoolType(), Dispatch const &dispatch = Dispatch() ) PoolFree( OwnerType owner = OwnerType(), PoolType pool = PoolType(), Dispatch const &dispatch = VULKAN_HPP_DEFAULT_DISPATCHER )
: m_owner( owner ) : m_owner( owner )
, m_pool( pool ) , m_pool( pool )
, m_dispatch( &dispatch ) , m_dispatch( &dispatch )
@ -5290,6 +5334,7 @@ namespace std
+ classOptional + classOptional
+ classStructureChain + classStructureChain
+ classUniqueHandle; + classUniqueHandle;
generator.appendDispatchLoaderStatic(str);
generator.appendDispatchLoaderDefault(str); generator.appendDispatchLoaderDefault(str);
str += classObjectDestroy str += classObjectDestroy
+ classObjectFree + classObjectFree

View File

@ -15,47 +15,41 @@
// VulkanHpp Samples : DispatchLoaderDynamic // VulkanHpp Samples : DispatchLoaderDynamic
// Compile test on DispatchLoaderDynamic functions // Compile test on DispatchLoaderDynamic functions
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#include <vulkan/vulkan.h>
#include "vulkan/vulkan.hpp" #include "vulkan/vulkan.hpp"
#include <iostream> #include <iostream>
#include <map> #include <map>
static char const* AppName = "DispatchLoaderDynamic"; static char const* AppName = "DispatchLoaderDynamic";
static char const* EngineName = "Vulkan.hpp"; static char const* EngineName = "Vulkan.hpp";
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE;
int main(int /*argc*/, char ** /*argv*/) int main(int /*argc*/, char ** /*argv*/)
{ {
try try
{ {
vk::DispatchLoaderDynamic dld0;
vk::DynamicLoader dl; vk::DynamicLoader dl;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
// empty DispatchLoaderDynamic, used for init calls later on vk::Instance instance = vk::createInstance({}, nullptr);
vk::DispatchLoaderDynamic dld_boot(vkGetInstanceProcAddr);
vk::Instance instance = vk::createInstance({}, nullptr, dld_boot);
vk::DispatchLoaderDynamic dld1(instance, vkGetInstanceProcAddr); // initialize function pointers for instance
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
// compare to the empty dispatcher, and init the empty dispatcher the same way
assert(memcmp(&dld0, &dld1, sizeof(vk::DispatchLoaderDynamic)) != 0);
dld0.init(instance, vkGetInstanceProcAddr);
assert(memcmp(&dld0, &dld1, sizeof(vk::DispatchLoaderDynamic)) == 0);
// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr // create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr
std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices(dld1); std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
assert(!physicalDevices.empty()); assert(!physicalDevices.empty());
vk::Device device = physicalDevices[0].createDevice({}, nullptr, dld1); vk::Device device = physicalDevices[0].createDevice({}, nullptr);
// device specialization functions // function pointer specialization for device
vk::DispatchLoaderDynamic dld2(instance, vkGetInstanceProcAddr, device); VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
// compare to "simpler" dispatcher and make them equal
assert(memcmp(&dld0, &dld2, sizeof(vk::DispatchLoaderDynamic)) != 0);
dld0.init(instance, vkGetInstanceProcAddr, device);
assert(memcmp(&dld0, &dld2, sizeof(vk::DispatchLoaderDynamic)) == 0);
} }
catch (vk::SystemError err) catch (vk::SystemError err)
{ {

File diff suppressed because it is too large Load Diff