Generate Vulkan framework from Vulkan registry (Part 2)
Instead of using the manually created vulkan.api file for generating the
Vulkan driver framework, we generate it directly from the vulkan registry
(vk.xml)
Bug : 134711355
Test: Build and flash, dEQP tests
Change-Id: I7a7c04a05d9eea5a03b4651fcff75948d3353933
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
new file mode 100644
index 0000000..92326ca
--- /dev/null
+++ b/vulkan/scripts/driver_generator.py
@@ -0,0 +1,393 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the functions for generating the
+# vulkan driver framework directly from the vulkan registry (vk.xml).
+
+import generator_common as gencom
+import os
+
+interceptedExtensions = [
+ 'VK_ANDROID_native_buffer',
+ 'VK_EXT_debug_report',
+ 'VK_EXT_hdr_metadata',
+ 'VK_EXT_swapchain_colorspace',
+ 'VK_GOOGLE_display_timing',
+ 'VK_KHR_android_surface',
+ 'VK_KHR_incremental_present',
+ 'VK_KHR_shared_presentable_image',
+ 'VK_KHR_surface',
+ 'VK_KHR_swapchain',
+ 'VK_KHR_get_surface_capabilities2'
+]
+
+knownExtensions = interceptedExtensions + [
+ 'VK_KHR_get_physical_device_properties2',
+ 'VK_ANDROID_external_memory_android_hardware_buffer',
+ 'VK_KHR_bind_memory2'
+]
+
+def defineProcHookType(f):
+ f.write ("""struct ProcHook {
+ enum Type {
+ GLOBAL,
+ INSTANCE,
+ DEVICE,
+ };
+ enum Extension {\n""")
+ for exts in knownExtensions:
+ f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n')
+ f.write ('\n')
+ f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE, // valid bit
+ EXTENSION_COUNT,
+ EXTENSION_UNKNOWN,
+ };
+
+ const char* name;
+ Type type;
+ Extension extension;
+
+ PFN_vkVoidFunction proc;
+ PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks
+};\n\n""")
+
+def isExtensionIntercepted(extensionName):
+ if extensionName in interceptedExtensions:
+ return True
+ return False
+
+def isDriverTableEntry(functionName):
+ switchCase = {
+ # Create functions of dispatchable objects
+ 'vkCreateDevice' : True,
+ 'vkGetDeviceQueue' : True,
+ 'vkGetDeviceQueue2' : True,
+ 'vkAllocateCommandBuffers' : True,
+
+ # Destroy functions of dispatchable objects
+ 'vkDestroyInstance' : True,
+ 'vkDestroyDevice' : True,
+
+ # Enumeration of extensions
+ 'vkEnumerateDeviceExtensionProperties' : True,
+
+ # We cache physical devices in loader.cpp
+ 'vkEnumeratePhysicalDevices' : True,
+ 'vkEnumeratePhysicalDeviceGroups' : True,
+
+ 'vkGetInstanceProcAddr' : True,
+ 'vkGetDeviceProcAddr' : True,
+
+ # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
+ 'vkCreateImage' : True,
+ 'vkDestroyImage' : True,
+
+ 'vkGetPhysicalDeviceProperties' : True,
+ 'vkGetPhysicalDeviceProperties2' : True,
+ 'vkGetPhysicalDeviceProperties2KHR' : True,
+
+ # VK_KHR_swapchain v69 requirement
+ 'vkBindImageMemory2' : True,
+ 'vkBindImageMemory2KHR' : True
+ }
+ if gencom.isFunctionSupported(functionName):
+ if functionName in switchCase:
+ return True
+ if functionName in gencom.extensionsDict:
+ if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report':
+ return True
+ return False
+
+def isInstanceDriverTableEntry(functionName):
+ if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName):
+ return True
+ return False
+
+def isDeviceDriverTableEntry(functionName):
+ if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName):
+ return True
+ return False
+
+def driver_genh():
+ header = """#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+
+#include <bitset>
+
+namespace vulkan {
+namespace driver {\n\n"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.h')
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ defineProcHookType(f)
+ f.write ('struct InstanceDriverTable {\n')
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isInstanceDriverTableEntry(cmds):
+ f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
+ gencom.clang_on(f, 1)
+ f.write ('};\n\n')
+ f.write ('struct DeviceDriverTable {\n')
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if isDeviceDriverTableEntry(cmds):
+ f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n')
+ f.write ("""const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+
+bool InitDriverTable(VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+bool InitDriverTable(VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+
+} // namespace driver
+} // namespace vulkan
+
+#endif // LIBVULKAN_DRIVER_TABLE_H\n""")
+
+def isIntercepted(functionName):
+ switchCase = {
+ # Create functions of dispatchable objects
+ 'vkCreateInstance' : True,
+ 'vkCreateDevice' : True,
+ 'vkEnumeratePhysicalDevices' : True,
+ 'vkEnumeratePhysicalDeviceGroups' : True,
+ 'vkGetDeviceQueue' : True,
+ 'vkGetDeviceQueue2' : True,
+ 'vkAllocateCommandBuffers' : True,
+
+ # Destroy functions of dispatchable objects
+ 'vkDestroyInstance' : True,
+ 'vkDestroyDevice' : True,
+
+ # Enumeration of extensions
+ 'vkEnumerateInstanceExtensionProperties' : True,
+ 'vkEnumerateDeviceExtensionProperties' : True,
+
+ 'vkGetInstanceProcAddr' : True,
+ 'vkGetDeviceProcAddr' : True,
+
+ # VK_KHR_swapchain v69 requirement
+ 'vkBindImageMemory2' : True,
+ 'vkBindImageMemory2KHR' : True
+ }
+ if gencom.isFunctionSupported(functionName):
+ if functionName in switchCase:
+ return switchCase[functionName]
+
+ if functionName in gencom.extensionsDict:
+ return isExtensionIntercepted(gencom.extensionsDict[functionName])
+ return False
+
+def needProcHookStub(functionName):
+ if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName):
+ if functionName in gencom.extensionsDict:
+ if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]):
+ return True
+ return False
+
+def defineInitProc(name, f):
+ f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
+ f.write ('\n')
+ f.write ("""#define INIT_PROC(required, obj, proc) \\
+ do { \\
+ data.""" + name + """.proc = \\
+ reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
+ if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
+ ALOGE("missing " #obj " proc: vk" #proc); \\
+ success = false; \\
+ } \\
+ } while (0)\n\n""")
+
+def defineInitProcExt(f):
+ f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
+ do { \\
+ if (extensions[ProcHook::ext]) \\
+ INIT_PROC(required, obj, proc); \\
+ } while (0)\n\n""")
+
+def defineProcHookStub(functionName, f):
+ if needProcHookStub(functionName):
+ ext_name = gencom.extensionsDict[functionName]
+ base_name = functionName[2:]
+ paramList = [''.join(i) for i in gencom.paramDict[functionName]]
+ p0 = gencom.paramDict[functionName][0][1]
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n')
+ ext_hook = 'ProcHook::' + ext_name[3:]
+
+ f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n')
+ f.write (gencom.clang_off_spaces *2)
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write ('return ')
+ paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]]
+ f.write (base_name + '(' + ', '.join(paramNames) + ');\n')
+ f.write (gencom.clang_off_spaces + '} else {\n')
+ f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n')
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n')
+ f.write (gencom.clang_off_spaces + '}\n')
+ f.write ('}\n\n')
+
+def defineGlobalProcHook(functionName, f):
+ base_name = functionName[2:]
+ assert (functionName not in gencom.extensionsDict)
+ f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2)
+ f.write ("""ProcHook::GLOBAL,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,
+ },\n""")
+
+def defineInstanceProcHook(functionName, f):
+ base_name = functionName[2:]
+ f.write (gencom.clang_off_spaces + '{\n')
+ f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n')
+
+ if functionName in gencom.extensionsDict:
+ ext_name = gencom.extensionsDict[functionName]
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
+ if gencom.isExtensionInternal(ext_name):
+ f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+ else:
+ f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+
+ else:
+ f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,\n""")
+
+ f.write (gencom.clang_off_spaces + '},\n')
+
+def defineDeviceProcHook(functionName, f):
+ base_name = functionName[2:]
+ f.write (gencom.clang_off_spaces + '{\n')
+ f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n')
+
+ if functionName in gencom.extensionsDict:
+ ext_name = gencom.extensionsDict[functionName]
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
+ if gencom.isExtensionInternal(ext_name):
+ f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+ else:
+ f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(checked' + base_name + '),\n')
+
+ else:
+ f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,\n""")
+
+ f.write (gencom.clang_off_spaces + '},\n')
+
+def driver_gencpp():
+ header = """#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "driver.h"
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+// clang-format off\n\n"""
+
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.cpp')
+
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+
+ for cmds in gencom.allCommandsList:
+ defineProcHookStub(cmds, f)
+ gencom.clang_on(f, 0)
+ f.write ('\n')
+
+ f.write ('const ProcHook g_proc_hooks[] = {\n')
+ gencom.clang_off(f, 1)
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if isIntercepted(cmds):
+ if gencom.isGloballyDispatched(cmds):
+ defineGlobalProcHook(cmds, f)
+ elif gencom.isInstanceDispatched(cmds):
+ defineInstanceProcHook(cmds, f)
+ elif gencom.isDeviceDispatched(cmds):
+ defineDeviceProcHook(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('};\n\n} // namespace\n\n')
+
+ f.write ("""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;
+}\n\n""")
+
+ f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n')
+ gencom.clang_off(f, 1)
+ for exts in knownExtensions:
+ f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n')
+ gencom.clang_on(f, 1)
+ f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n')
+ f.write ('}\n\n')
+
+ defineInitProc('driver', f)
+ defineInitProcExt(f)
+
+ f.write ("""bool InitDriverTable(VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(instance);
+ bool success = true;\n\n""")
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isInstanceDriverTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
+ f.write ('}\n\n')
+
+ f.write ("""bool InitDriverTable(VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(dev);
+ bool success = true;\n\n""")
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isDeviceDriverTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
+ f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n')
+ gencom.clang_on(f, 0)
+