summaryrefslogtreecommitdiff
path: root/vulkan/scripts/api_generator.py
diff options
context:
space:
mode:
authorAdithya Srinivasan <adsrini@google.com>2019-07-02 17:17:25 -0700
committerAdithya Srinivasan <adsrini@google.com>2019-07-02 17:17:25 -0700
commit751a7dcc1f03d5704104d418387127c2f0843b1b (patch)
treefeeb5e1da1a10bcc7895b9e900cf4ae2a5c3ecdd /vulkan/scripts/api_generator.py
parent29d4e9ce5a5b909050c593c4124220e2b9d5f6e0 (diff)
Generate Vulkan framework from Vulkan registry
Instead of using the manually created vulkan.api file for generating the Vulkan framework, we generate it directly from the vulkan registry (vk.xml) Bug: 134711355 Test: Build and flash, dEQP tests Change-Id: I7e85cd4b64d13b8ed2c54678090f405171854a40
Diffstat (limited to 'vulkan/scripts/api_generator.py')
-rw-r--r--vulkan/scripts/api_generator.py344
1 files changed, 344 insertions, 0 deletions
diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py
new file mode 100644
index 0000000000..05dc9957b0
--- /dev/null
+++ b/vulkan/scripts/api_generator.py
@@ -0,0 +1,344 @@
+#!/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 required for generating the
+# vulkan api framework directly from the vulkan registry (vk.xml)
+
+import os
+import generator_common as gencom
+
+def isInstanceDispatchTableEntry(functionName):
+ if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
+ return False
+ if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName):
+ return True
+ return False
+
+def isDeviceDispatchTableEntry(functionName):
+ if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName):
+ return True
+ return False
+
+def api_genh():
+
+ header = """#ifndef LIBVULKAN_API_GEN_H
+#define LIBVULKAN_API_GEN_H
+
+#include <vulkan/vulkan.h>
+
+#include <bitset>
+
+#include "driver_gen.h"
+
+namespace vulkan {
+namespace api {
+
+"""
+
+ tail = """
+bool InitDispatchTable(
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
+bool InitDispatchTable(
+ VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
+
+} // namespace api
+} // namespace vulkan
+
+#endif // LIBVULKAN_API_GEN_H
+"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.h')
+ with open(genfile, 'w') as f:
+ instanceDispatchTableEntries = []
+ deviceDispatchTableEntries = []
+ for commands in gencom.allCommandsList:
+ if commands not in gencom.aliasDict:
+ if gencom.isInstanceDispatchTableEntry(commands):
+ instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
+ elif gencom.isDeviceDispatchTableEntry(commands):
+ deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
+
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ f.write ('struct InstanceDispatchTable {\n')
+ gencom.clang_off(f,1)
+ for functions in instanceDispatchTableEntries:
+ f.write(gencom.clang_off_spaces + functions + '\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n')
+
+ f.write ('struct DeviceDispatchTable {\n')
+ gencom.clang_off(f,1)
+ for functions in deviceDispatchTableEntries:
+ f.write(gencom.clang_off_spaces + functions + '\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n')
+
+ f.write (tail)
+ f.close()
+
+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 ('// Exported extension functions may be invoked even when their extensions\n')
+ f.write ('// are disabled. Dispatch to stubs when that happens.\n')
+ f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
+ do { \\
+ if (extensions[driver::ProcHook::ext]) \\
+ INIT_PROC(required, obj, proc); \\
+ else \\
+ data.dispatch.proc = disabled##proc; \\
+ } while (0)\n\n""")
+
+def defineExtensionStub(functionName, f):
+ if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName):
+ extname = gencom.extensionsDict[functionName]
+ base_name = functionName[2:]
+ pList = gencom.paramDict[functionName]
+ firstParam = pList[0][0] + pList[0][1]
+ tailParams = [x[0][:-1] for x in pList[1:]]
+ tailP = ', '.join(tailParams)
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n')
+ f.write (gencom.clang_off_spaces)
+ f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n')
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n')
+ f.write ('}\n\n')
+
+def isIntercepted(functionName):
+ if gencom.isFunctionSupported(functionName):
+ if gencom.isGloballyDispatched(functionName):
+ return True
+ elif functionName == 'vkCreateDevice':
+ return True
+ elif functionName == 'vkEnumerateDeviceLayerProperties':
+ return True
+ elif functionName == 'vkEnumerateDeviceExtensionProperties':
+ return True
+ elif functionName == 'vkDestroyInstance':
+ return True
+ elif functionName == 'vkDestroyDevice':
+ return True
+ return False
+
+def interceptInstanceProcAddr(functionName, f):
+ indent = 1
+ f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n')
+ indent = indent + 1
+ for cmds in gencom.allCommandsList:
+ if gencom.isGloballyDispatched(cmds):
+ f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
+
+ f.write ('\n')
+ f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
+ return nullptr;
+ }
+
+ static const struct Hook {
+ const char* name;
+ PFN_vkVoidFunction proc;
+ } hooks[] = {\n""")
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if gencom.isFunctionExported(cmds):
+ if gencom.isGloballyDispatched(cmds):
+ f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n')
+ elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds):
+ f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n')
+ f.write (gencom.clang_off_spaces + """};
+ // clang-format on
+ constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
+ auto hook = std::lower_bound(
+ hooks, hooks + count, pName,
+ [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
+ if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
+ if (!hook->proc) {
+ vulkan::driver::Logger(instance).Err(
+ instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
+ instance, pName);
+ }
+ return hook->proc;
+ }
+ // clang-format off\n\n""")
+
+def interceptDeviceProcAddr(functionName, f):
+ f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) {
+ ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
+ return nullptr;
+ }\n\n""")
+ f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n')
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if gencom.isFunctionSupported(cmds):
+ if not gencom.isDeviceDispatched(cmds):
+ f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n')
+ f.write(gencom.clang_off_spaces + '};\n')
+ f.write(gencom.clang_off_spaces + """// clang-format on
+ constexpr size_t count =
+ sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
+ if (!pName ||
+ std::binary_search(
+ known_non_device_names, known_non_device_names + count, pName,
+ [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
+ vulkan::driver::Logger(device).Err(
+ device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
+ (pName) ? pName : "(null)");
+ return nullptr;
+ }
+ // clang-format off\n\n""")
+ for cmds in gencom.allCommandsList:
+ if gencom.isDeviceDispatched(cmds):
+ if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr':
+ f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
+ f.write ('\n')
+
+def apiDispatch(functionName, f):
+ assert not isIntercepted(functionName)
+
+ f.write (gencom.clang_off_spaces)
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write ('return ')
+
+ paramList = gencom.paramDict[functionName]
+ p0 = paramList[0][1]
+ f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
+
+
+def api_gencpp():
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.cpp')
+ header = """#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+// to catch mismatches between vulkan.h and this file
+#undef VK_NO_PROTOTYPES
+#include "api.h"
+
+namespace vulkan {
+namespace api {
+
+"""
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write ("""#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+// to catch mismatches between vulkan.h and this file
+#undef VK_NO_PROTOTYPES
+#include "api.h"
+
+namespace vulkan {
+namespace api {\n\n""")
+ defineInitProc('dispatch',f)
+ defineInitProcExt(f)
+ f.write ('namespace {\n\n')
+ gencom.clang_off(f,0)
+ f.write ('\n')
+ for cmds in gencom.allCommandsList:
+ defineExtensionStub(cmds,f)
+ gencom.clang_on(f,0)
+ f.write ('\n} // namespace\n\n')
+ f.write ("""bool InitDispatchTable(
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(instance);
+ bool success = true;\n\n""")
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if gencom.isInstanceDispatchTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f,1)
+ f.write ('\n')
+ f.write (' return success;\n}\n\n')
+ f.write ("""bool InitDispatchTable(
+ VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(dev);
+ bool success = true;\n\n""")
+
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if gencom.isDeviceDispatchTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f,1)
+ f.write ('\n')
+ f.write (' return success;\n}\n\n')
+
+ gencom.clang_off(f,0)
+
+ f.write ('\nnamespace {\n\n')
+ f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n')
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n')
+
+ f.write ('\n')
+
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n')
+ if cmds == 'vkGetInstanceProcAddr':
+ interceptInstanceProcAddr(cmds, f)
+ elif cmds == 'vkGetDeviceProcAddr':
+ interceptDeviceProcAddr(cmds, f)
+ apiDispatch(cmds, f)
+ f.write('}\n\n')
+ f.write ("""\n} // anonymous namespace
+
+// clang-format on
+
+} // namespace api
+} // namespace vulkan
+
+// clang-format off\n\n""")
+
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('__attribute__((visibility("default")))\n')
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n')
+ f.write (gencom.clang_off_spaces)
+ if gencom.returnTypeDict[cmds] != 'void':
+ f.write ('return ')
+ paramList = gencom.paramDict[cmds]
+ f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
+ f.write ('}\n\n')
+
+ gencom.clang_on(f, 0)
+