Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazily resolve Vulkan commands (actually all indirect commands) #1990

Merged
merged 2 commits into from
Jun 20, 2018
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
49 changes: 49 additions & 0 deletions gapir/cc/gfx_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename FuncPtr>
class LazyResolved {
public:
LazyResolved() : resolve_(nullptr), ptr_(nullptr) {}
LazyResolved(std::nullptr_t) : LazyResolved() {}
explicit LazyResolved(std::function<void*()> 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... Args>
typename std::result_of<FuncPtr(Args...)>::type operator()(Args&&... args) {
if (!ptr_) {
ptr_ = reinterpret_cast<FuncPtr>(resolve_());
}
return ptr_(std::forward<Args>(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<FuncPtr>(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<FuncPtr>(resolve_());
}
return ptr_ != nullptr;
}
private:
// The function resolving callback.
std::function<void*()> resolve_;
// The cached function pointer to the underlying function.
FuncPtr ptr_;
};

} // namespace gapir

#endif // GAPIR_GFX_API_H
12 changes: 12 additions & 0 deletions gapis/api/templates/cpp_common.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion gapis/api/templates/specific_gfx_api.h.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "core/cc/{{Global "API"}}_ptr_types.h"
#include <stdint.h>
#include <functional>
#include <string>
{{/* Forward declare structs used by the graphics API in the global namespace. */}}
Expand Down Expand Up @@ -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}}
};
Expand Down
12 changes: 6 additions & 6 deletions gapis/api/templates/vulkan_gfx_api_extras.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

std::vector<Vulkan::VkPhysicalDevice> getVkPhysicalDevices(§
Vulkan::PFNVKENUMERATEPHYSICALDEVICES vkEnumeratePhysicalDevices, Vulkan::VkInstance instance) {
LazyResolved<Vulkan::PFNVKENUMERATEPHYSICALDEVICES> vkEnumeratePhysicalDevices, Vulkan::VkInstance instance) {
uint32_t count = 0;
vkEnumeratePhysicalDevices(instance, &count, nullptr);
std::vector<Vulkan::VkPhysicalDevice> devices(count);
Expand All @@ -73,7 +73,7 @@
}
std::vector<Vulkan::VkQueue> getVkQueues(§
Vulkan::PFNVKGETDEVICEQUEUE vkGetDeviceQueue, Vulkan::VkDevice device, §
LazyResolved<Vulkan::PFNVKGETDEVICEQUEUE> vkGetDeviceQueue, Vulkan::VkDevice device, §
Vulkan::VkDeviceCreateInfo* createInfo) {
std::vector<Vulkan::VkQueue> queues;
for (uint32_t i = 0; i < createInfo->queueCreateInfoCount; ++i) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down