diff --git a/gapir/cc/gfx_api.h b/gapir/cc/gfx_api.h index 14393a3bff..3b87d2374b 100644 --- a/gapir/cc/gfx_api.h +++ b/gapir/cc/gfx_api.h @@ -37,6 +37,55 @@ class Api { FunctionTable mFunctions; }; +// LazyResolved is for resolving indirect commands only when the commands are +// going to be called. It takes a resolver callback, which will be used for +// command resolving for the first time the command is to be called. And caches +// the resolved pointer. +template +class LazyResolved { + public: + LazyResolved() : resolve_(nullptr), ptr_(nullptr) {} + LazyResolved(std::nullptr_t) : LazyResolved() {} + explicit LazyResolved(std::function resolver) + : resolve_(resolver), ptr_(nullptr) {} + // Pass forward the arguments to the command, if the function has never been + // resolved before, resolve it first. + template + typename std::result_of::type operator()(Args&&... args) { + if (!ptr_) { + ptr_ = reinterpret_cast(resolve_()); + } + return ptr_(std::forward(args)...); + } + // Overloaded not-equal nullptr comparison. Returns true if the underlying + // function can be resolved and is not nullptr. + bool operator!=(std::nullptr_t) { + if (!resolve_) { + return true; + } + if (!ptr_) { + ptr_ = reinterpret_cast(resolve_()); + } + return ptr_ != nullptr; + } + // Overloaded boolean comparison. Returns true if the underlying function can + // be resolved and is not nullptr. + operator bool() { + if (!resolve_) { + return false; + } + if (!ptr_) { + ptr_ = reinterpret_cast(resolve_()); + } + return ptr_ != nullptr; + } + private: + // The function resolving callback. + std::function resolve_; + // The cached function pointer to the underlying function. + FuncPtr ptr_; +}; + } // namespace gapir #endif // GAPIR_GFX_API_H diff --git a/gapis/api/templates/cpp_common.tmpl b/gapis/api/templates/cpp_common.tmpl index cc54ad0026..6fe2219a3b 100644 --- a/gapis/api/templates/cpp_common.tmpl +++ b/gapis/api/templates/cpp_common.tmpl @@ -1119,6 +1119,18 @@ {{end}} +{{/* +------------------------------------------------------------------------------- + Emits the C++ lazy resolved function variable extern for a given command. +------------------------------------------------------------------------------- +*/}} +{{define "C++.LazyResolvedFunctionDecl"}} + {{AssertType $ "Function"}} + + LazyResolved<{{Template "C++.FunctionPtrType" $}}> {{Template "CmdName" $}} +{{end}} + + {{/* ------------------------------------------------------------------------------- Emits the method name for the given command or subroutine. diff --git a/gapis/api/templates/specific_gfx_api.h.tmpl b/gapis/api/templates/specific_gfx_api.h.tmpl index 03ec85bf11..dbaa667a80 100644 --- a/gapis/api/templates/specific_gfx_api.h.tmpl +++ b/gapis/api/templates/specific_gfx_api.h.tmpl @@ -40,6 +40,7 @@ #include "core/cc/{{Global "API"}}_ptr_types.h" ¶ #include +#include #include ¶ {{/* Forward declare structs used by the graphics API in the global namespace. */}} @@ -88,7 +89,11 @@ class {{Title (Global "API")}} : public Api { struct {{$table}}FunctionStubs { {{range $f := $p}} {{if and (not (GetAnnotation $f "synthetic")) (not (GetAnnotation $f "pfn"))}} - {{Template "C++.FunctionPtrDecl" $f}} = nullptr; + {{if not (GetAnnotation $f "indirect")}} + {{Template "C++.FunctionPtrDecl" $f}} = nullptr; + {{else}} + {{Template "C++.LazyResolvedFunctionDecl" $f}} = nullptr; + {{end}} {{end}} {{end}} }; diff --git a/gapis/api/templates/vulkan_gfx_api_extras.tmpl b/gapis/api/templates/vulkan_gfx_api_extras.tmpl index 63f2e72958..dabb0c49f8 100644 --- a/gapis/api/templates/vulkan_gfx_api_extras.tmpl +++ b/gapis/api/templates/vulkan_gfx_api_extras.tmpl @@ -64,7 +64,7 @@ ¶ std::vector getVkPhysicalDevices(§ - Vulkan::PFNVKENUMERATEPHYSICALDEVICES vkEnumeratePhysicalDevices, Vulkan::VkInstance instance) { + LazyResolved vkEnumeratePhysicalDevices, Vulkan::VkInstance instance) { uint32_t count = 0; vkEnumeratePhysicalDevices(instance, &count, nullptr); std::vector devices(count); @@ -73,7 +73,7 @@ } ¶ std::vector getVkQueues(§ - Vulkan::PFNVKGETDEVICEQUEUE vkGetDeviceQueue, Vulkan::VkDevice device, § + LazyResolved vkGetDeviceQueue, Vulkan::VkDevice device, § Vulkan::VkDeviceCreateInfo* createInfo) { std::vector queues; for (uint32_t i = 0; i < createInfo->queueCreateInfoCount; ++i) { @@ -204,8 +204,8 @@ bool Vulkan::replayCreateVkDeviceImpl(Stack* stack, size_val physicalDevice, {{range $c := AllCommands $}} {{if (Macro "IsIndirected" "Command" $c "IndirectOn" "VkInstance")}} {{$name := Macro "CmdName" $c}} - stubs.{{$name}} = reinterpret_cast<{{Template "C++.FunctionPtrType" $c}}>(§ - core::GetVulkanInstanceProcAddress(instance, "{{$name}}", false)); + stubs.{{$name}} = LazyResolved<{{Template "C++.FunctionPtrType" $c}}>( + [instance]() -> void* { return core::GetVulkanInstanceProcAddress(instance, "{{$name}}", false); }); {{end}} {{end}} // Get all physical devices for this instance and bind them. @@ -255,8 +255,8 @@ bool Vulkan::replayCreateVkDeviceImpl(Stack* stack, size_val physicalDevice, {{range $c := AllCommands $}} {{if (Macro "IsIndirected" "Command" $c "IndirectOn" "VkDevice")}} {{$name := Macro "CmdName" $c}} - stubs.{{$name}} = reinterpret_cast<{{Template "C++.FunctionPtrType" $c}}>(§ - core::GetVulkanDeviceProcAddress(instance, device, "{{$name}}", false)); + stubs.{{$name}} = LazyResolved<{{Template "C++.FunctionPtrType" $c}}>( + [instance, device]() -> void* { return core::GetVulkanDeviceProcAddress(instance, device, "{{$name}}", false); }); {{end}} {{end}} // Get all queues for this device and bind them.