Merge "Generate Vulkan framework from Vulkan registry (Part 2)"
diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py
index 91c0d30..9e14b28 100644
--- a/vulkan/scripts/code_generator.py
+++ b/vulkan/scripts/code_generator.py
@@ -19,8 +19,11 @@
import generator_common as gencom
import api_generator as apigen
+import driver_generator as drivergen
if __name__ == '__main__':
gencom.parseVulkanRegistry()
apigen.api_genh()
apigen.api_gencpp()
+ drivergen.driver_genh()
+ drivergen.driver_gencpp()
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)
+
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 313357d..51ad6f5 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -61,7 +61,11 @@
'VK_NV_win32_keyed_mutex',
'VK_EXT_metal_surface', #not present in vulkan.api
'VK_NVX_image_view_handle', #not present in vulkan.api
- 'VK_NV_cooperative_matrix' #not present in vulkan.api
+ 'VK_NV_cooperative_matrix', #not present in vulkan.api
+ 'VK_EXT_headless_surface', #not present in vulkan.api
+ 'VK_GGP_stream_descriptor_surface', #not present in vulkan.api
+ 'VK_NV_coverage_reduction_mode', #not present in vulkan.api
+ 'VK_EXT_full_screen_exclusive' #not present in vulkan.api
]
exportedExtensions = [
@@ -71,6 +75,11 @@
'VK_ANDROID_external_memory_android_hardware_buffer'
]
+def isExtensionInternal(extensionName):
+ if extensionName == 'VK_ANDROID_native_buffer':
+ return True
+ return False
+
def isFunctionSupported(functionName):
if functionName not in extensionsDict:
return True
@@ -167,6 +176,7 @@
aliasDict[fnName] = alias
allCommandsList.append(fnName)
paramDict[fnName] = paramDict[alias].copy()
+ returnTypeDict[fnName] = returnTypeDict[alias]
for params in command:
if(params.tag == 'param'):
paramtype = ""
@@ -208,6 +218,19 @@
if apiversion != "":
versionDict[commandname] = apiversion
+ # TODO(adsrini): http://b/136570819
+ extensionsDict['vkGetSwapchainGrallocUsage2ANDROID'] = 'VK_ANDROID_native_buffer'
+ allCommandsList.append('vkGetSwapchainGrallocUsage2ANDROID')
+ returnTypeDict['vkGetSwapchainGrallocUsage2ANDROID'] = 'VkResult'
+ paramDict['vkGetSwapchainGrallocUsage2ANDROID'] = [
+ ('VkDevice ', 'device', None),
+ ('VkFormat ', 'format', None),
+ ('VkImageUsageFlags', 'imageUsage', None),
+ ('VkSwapchainImageUsageFlagsANDROID ', 'swapchainImageUsage', None),
+ ('u64* ', 'grallocConsumerUsage', None),
+ ('u64* ', 'grallocProducerUsage', None)
+ ]
+
for feature in root.iter('feature'):
apiversion = feature.get('name')
for req in feature:
@@ -226,6 +249,8 @@
if name in versionDict and versionDict[name] == 'VK_VERSION_1_1':
f.write('false, ')
+ elif name == 'vkGetSwapchainGrallocUsageANDROID' or name == 'vkGetSwapchainGrallocUsage2ANDROID': # optional in vulkan.api
+ f.write('false, ')
else:
f.write('true, ')