vulkan: rework driver::Get*ProcAddr
Introduce driver::ProcHook which is a struct to describe an intercepted
function. Given a function name, GetProcHook returns a ProcHook if the
function is intercepted. NULL otherwise.
A ProcHook has three function pointers. ProcHook::proc points to the real
intercepting function. ProcHook::disabled_proc points to a no-op function
that logs an error. ProcHook::checked_proc points to a trampoline that
calls either ProcHook::proc or ProcHook::disabled_proc.
For core functions, driver::Get*ProcAddr simply return ProcHook::proc.
For extension functions, driver::Get*ProcAddr return ProcHook::proc when
the extension is known to be enabled. They return ProcHook::disabled_proc
when the extension is known to be disabled. Finally, they return
ProcHook::checked_proc when they do not know if the extension is enabled
or not.
All ProcHooks as well as their disabled_proc/checked_proc are generated in
driver_gen.cpp. This allows us to get rid of all hand-written "_Disabled"
functions, all no-op "_Bottom" functions, and special cases for
VK_ANDROID_native_buffer. The reworked driver::Get*ProcAddr also detects
more applications' errors and logs them.
Change-Id: I8e6f476f450688b5547fd75243c66cb603c516b5
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 7ebe983..f7083c3 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -21,6 +21,8 @@
{{Macro "DefineGlobals" $}}
{{$ | Macro "api_gen.h" | Format (Global "clang-format") | Write "api_gen.h" }}
{{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}}
+{{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}}
+{{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}}
{{/*
-------------------------------------------------------------------------------
@@ -147,6 +149,110 @@
{{/*
+-------------------------------------------------------------------------------
+ driver_gen.h
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.h"}}
+{{Macro "Copyright"}}
+¶
+// WARNING: This file is generated. See ../README.md for instructions.
+¶
+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+¶
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_android_native_buffer.h>
+¶
+namespace vulkan {«
+namespace driver {«
+¶
+{{Macro "driver.C++.DefineProcHookType"}}
+¶
+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+¶
+»} // namespace driver
+»} // namespace vulkan
+¶
+#endif // LIBVULKAN_DRIVER_TABLE_H
+¶{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ driver_gen.cpp
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.cpp"}}
+{{Macro "Copyright"}}
+¶
+// WARNING: This file is generated. See ../README.md for instructions.
+¶
+#include <string.h>
+#include <algorithm>
+#include <log/log.h>
+¶
+#include "driver.h"
+#include "loader.h"
+¶
+namespace vulkan {«
+namespace driver {«
+¶
+namespace {«
+¶
+// clang-format off
+¶
+{{range $f := AllCommands $}}
+ {{Macro "driver.C++.DefineProcHookStubs" $f}}
+{{end}}
+// clang-format on
+¶
+const ProcHook g_proc_hooks[] = {
+ // clang-format off
+ {{range $f := SortBy (AllCommands $) "FunctionName"}}
+ {{if (Macro "driver.IsIntercepted" $f)}}
+ {{ if (Macro "IsGloballyDispatched" $f)}}
+ {{Macro "driver.C++.DefineGlobalProcHook" $f}}
+ {{else if (Macro "IsInstanceDispatched" $f)}}
+ {{Macro "driver.C++.DefineInstanceProcHook" $f}}
+ {{else if (Macro "IsDeviceDispatched" $f)}}
+ {{Macro "driver.C++.DefineDeviceProcHook" $f}}
+ {{end}}
+ {{end}}
+ {{end}}
+ // clang-format on
+};
+¶
+»} // anonymous
+¶
+const ProcHook* GetProcHook(const char* name) {
+ const auto& begin = g_proc_hooks;
+ const auto& end = g_proc_hooks +
+ sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+ const auto hook = std::lower_bound(begin, end, name,
+ [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+ return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}
+¶
+ProcHook::Extension GetProcHookExtension(const char* name) {
+ {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+ // clang-format off
+ {{range $e := $exts}}
+ if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}};
+ {{end}}
+ // clang-format on
+ return ProcHook::EXTENSION_UNKNOWN;
+}
+¶
+»} // namespace driver
+»} // namespace vulkan
+¶
+// clang-format on
+¶{{end}}
+
+
+{{/*
------------------------------------------------------------------------------
Emits a declaration of a dispatch table entry.
------------------------------------------------------------------------------
@@ -386,6 +492,277 @@
{{/*
+------------------------------------------------------------------------------
+ Emits a list of extensions intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.InterceptedExtensions"}}
+VK_ANDROID_native_buffer
+VK_EXT_debug_report
+VK_KHR_android_surface
+VK_KHR_surface
+VK_KHR_swapchain
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+ Emits true if an extension is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsExtensionIntercepted"}}
+ {{$ext_name := index $.Arguments 0}}
+ {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+
+ {{range $f := $filters}}
+ {{if eq $ext_name $f}}true{{end}}
+ {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+ Emits true if a function is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsIntercepted"}}
+ {{AssertType $ "Function"}}
+
+ {{if (Macro "IsFunctionSupported" $)}}
+ {{/* Create functions of dispatchable objects */}}
+ {{ if eq $.Name "vkCreateInstance"}}true
+ {{else if eq $.Name "vkCreateDevice"}}true
+ {{else if eq $.Name "vkGetDeviceQueue"}}true
+ {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+ {{/* Destroy functions of dispatchable objects */}}
+ {{else if eq $.Name "vkDestroyInstance"}}true
+ {{else if eq $.Name "vkDestroyDevice"}}true
+
+ {{/* Enumeration of extensions */}}
+ {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true
+ {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
+
+ {{/* We cache physical devices in loader.cpp */}}
+ {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+
+ {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+ {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+ {{end}}
+
+ {{$ext := GetAnnotation $ "extension"}}
+ {{if $ext}}
+ {{Macro "driver.IsExtensionIntercepted" $ext}}
+ {{end}}
+
+ {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+ Emits true if a function needs ProcHook stubs.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.NeedProcHookStubs"}}
+ {{AssertType $ "Function"}}
+
+ {{if (Macro "driver.IsIntercepted" $)}}
+ {{$ext := GetAnnotation $ "extension"}}
+ {{if $ext}}
+ {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}}
+ {{end}}
+ {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ Emits definition of struct ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookType"}}
+ struct ProcHook {
+ enum Type {
+ GLOBAL,
+ INSTANCE,
+ DEVICE,
+ };
+
+ enum Extension {
+ {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+ {{range $e := $exts}}
+ {{TrimPrefix "VK_" $e}},
+ {{end}}
+ ¶
+ EXTENSION_CORE, // valid bit
+ EXTENSION_COUNT,
+ EXTENSION_UNKNOWN,
+ };
+ ¶
+ const char* name;
+ Type type;
+ Extension extension;
+ ¶
+ PFN_vkVoidFunction proc;
+ PFN_vkVoidFunction disabled_proc; // nullptr for global hooks
+ PFN_vkVoidFunction checked_proc; // nullptr for global/instance hooks
+ };
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ Emits definitions of stub functions for ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookStubs"}}
+ {{AssertType $ "Function"}}
+
+ {{if (Macro "driver.NeedProcHookStubs" $)}}
+ {{$ext := GetAnnotation $ "extension"}}
+ {{$ext_name := index $ext.Arguments 0}}
+
+ {{$base := (Macro "BaseName" $)}}
+ {{$unnamed_params := (ForEach $.CallParameters "ParameterType" | JoinWith ", ")}}
+
+ VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$unnamed_params}}) {
+ ALOGE("{{$ext_name}} not enabled. {{$.Name}} not executed.");
+ {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}}
+ }
+ {{if (Macro "IsDeviceDispatched" $)}}
+ ¶
+ VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) {
+ {{if not (IsVoid $.Return.Type)}}return §{{end}}
+
+ {{$p0 := index $.CallParameters 0}}
+ {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}}
+ (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) ? §
+ {{$base}}_Bottom({{Macro "Arguments" $}}) : §
+ disabled{{$base}}({{Macro "Arguments" $}});
+ }
+ {{end}}
+ ¶
+ {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ Emits definition of a global ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineGlobalProcHook"}}
+ {{AssertType $ "Function"}}
+
+ {{$base := (Macro "BaseName" $)}}
+
+ {{$ext := GetAnnotation $ "extension"}}
+ {{if $ext}}
+ {{Error "invalid global extension"}}
+ {{end}}
+
+ {
+ "{{$.Name}}",
+ ProcHook::GLOBAL,
+ ProcHook::EXTENSION_CORE,
+ {{if eq $.Name "vkEnumerateInstanceExtensionProperties"}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+ {{else}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+ {{end}}
+ nullptr,
+ nullptr,
+ },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ Emits definition of an instance ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineInstanceProcHook"}}
+ {{AssertType $ "Function"}}
+
+ {{$base := (Macro "BaseName" $)}}
+
+ {
+ "{{$.Name}}",
+ ProcHook::INSTANCE,
+
+ {{$ext := GetAnnotation $ "extension"}}
+ {{if $ext}}
+ ProcHook::{{Macro "BaseName" $ext}},
+
+ {{if (Macro "IsExtensionInternal" $ext)}}
+ nullptr,
+ nullptr,
+ nullptr,
+ {{else}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+ reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+ nullptr,
+ {{end}}
+ {{else}}
+ ProcHook::EXTENSION_CORE,
+
+ {{if eq $.Name "vkGetInstanceProcAddr"}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+ {{else}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+ {{end}}
+ nullptr,
+ nullptr,
+ {{end}}
+ },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+ Emits definition of a device ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineDeviceProcHook"}}
+ {{AssertType $ "Function"}}
+
+ {{$base := (Macro "BaseName" $)}}
+
+ {
+ "{{$.Name}}",
+ ProcHook::DEVICE,
+
+ {{$ext := GetAnnotation $ "extension"}}
+ {{if $ext}}
+ ProcHook::{{Macro "BaseName" $ext}},
+
+ {{if (Macro "IsExtensionInternal" $ext)}}
+ nullptr,
+ nullptr,
+ nullptr,
+ {{else}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+ reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+ reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
+ {{end}}
+ {{else}}
+ ProcHook::EXTENSION_CORE,
+
+ {{if eq $.Name "vkGetDeviceProcAddr"}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+ {{else}}
+ reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+ {{end}}
+ nullptr,
+ nullptr,
+ {{end}}
+ },
+{{end}}
+
+
+{{/*
-------------------------------------------------------------------------------
Emits a function/extension name without the "vk"/"VK_" prefix.
-------------------------------------------------------------------------------
@@ -517,3 +894,16 @@
{{else if eq $ext "VK_KHR_android_surface"}}true
{{end}}
{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+ Reports whether an extension is internal to the loader and drivers,
+ so the loader should not enumerate it.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsExtensionInternal"}}
+ {{$ext := index $.Arguments 0}}
+ {{ if eq $ext "VK_ANDROID_native_buffer"}}true
+ {{end}}
+{{end}}