You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
12 KiB
413 lines
12 KiB
#!/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.
|
|
|
|
"""Generates the api_gen.h and api_gen.cpp.
|
|
"""
|
|
|
|
import os
|
|
import generator_common as gencom
|
|
|
|
# Functions intercepted at vulkan::api level.
|
|
_INTERCEPTED_COMMANDS = [
|
|
'vkCreateDevice',
|
|
'vkDestroyDevice',
|
|
'vkDestroyInstance',
|
|
'vkEnumerateDeviceExtensionProperties',
|
|
'vkEnumerateDeviceLayerProperties',
|
|
]
|
|
|
|
|
|
def gen_h():
|
|
"""Generates the api_gen.h file.
|
|
"""
|
|
genfile = os.path.join(os.path.dirname(__file__),
|
|
'..', 'libvulkan', 'api_gen.h')
|
|
|
|
with open(genfile, 'w') as f:
|
|
instance_dispatch_table_entries = []
|
|
device_dispatch_table_entries = []
|
|
|
|
for cmd in gencom.command_list:
|
|
if cmd not in gencom.alias_dict:
|
|
if gencom.is_instance_dispatch_table_entry(cmd):
|
|
instance_dispatch_table_entries.append(
|
|
'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
|
|
elif gencom.is_device_dispatch_table_entry(cmd):
|
|
device_dispatch_table_entries.append(
|
|
'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
|
|
|
|
f.write(gencom.copyright_and_warning(2016))
|
|
|
|
f.write("""\
|
|
#ifndef LIBVULKAN_API_GEN_H
|
|
#define LIBVULKAN_API_GEN_H
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include <bitset>
|
|
|
|
#include "driver_gen.h"
|
|
|
|
namespace vulkan {
|
|
namespace api {
|
|
|
|
struct InstanceDispatchTable {
|
|
// clang-format off\n""")
|
|
|
|
for entry in instance_dispatch_table_entries:
|
|
f.write(gencom.indent(1) + entry + '\n')
|
|
|
|
f.write("""\
|
|
// clang-format on
|
|
};
|
|
|
|
struct DeviceDispatchTable {
|
|
// clang-format off\n""")
|
|
|
|
for entry in device_dispatch_table_entries:
|
|
f.write(gencom.indent(1) + entry + '\n')
|
|
|
|
f.write("""\
|
|
// clang-format on
|
|
};
|
|
|
|
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\n""")
|
|
|
|
f.close()
|
|
gencom.run_clang_format(genfile)
|
|
|
|
|
|
def _define_extension_stub(cmd, f):
|
|
"""Emits a stub for an exported extension function.
|
|
|
|
Args:
|
|
cmd: Vulkan function name.
|
|
f: Output file handle.
|
|
"""
|
|
if (cmd in gencom.extension_dict and gencom.is_function_exported(cmd)):
|
|
ext_name = gencom.extension_dict[cmd]
|
|
ret = gencom.return_type_dict[cmd]
|
|
params = gencom.param_dict[cmd]
|
|
first_param = params[0][0] + params[0][1]
|
|
tail_params = ', '.join([i[0][:-1] for i in params[1:]])
|
|
|
|
f.write('VKAPI_ATTR ' + ret + ' disabled' + gencom.base_name(cmd) +
|
|
'(' + first_param + ', ' + tail_params + ') {\n')
|
|
|
|
f.write(gencom.indent(1) + 'driver::Logger(' + params[0][1] +
|
|
').Err(' + params[0][1] + ', \"' + ext_name +
|
|
' not enabled. Exported ' + cmd + ' not executed.\");\n')
|
|
|
|
if gencom.return_type_dict[cmd] != 'void':
|
|
f.write(gencom.indent(1) + 'return VK_SUCCESS;\n')
|
|
|
|
f.write('}\n\n')
|
|
|
|
|
|
def _is_intercepted(cmd):
|
|
"""Returns true if a function is intercepted by vulkan::api.
|
|
|
|
Args:
|
|
cmd: Vulkan function name.
|
|
"""
|
|
if gencom.is_function_supported(cmd):
|
|
if gencom.is_globally_dispatched(cmd) or cmd in _INTERCEPTED_COMMANDS:
|
|
return True
|
|
return False
|
|
|
|
|
|
def _intercept_instance_proc_addr(f):
|
|
"""Emits code for vkGetInstanceProcAddr for function interception.
|
|
|
|
Args:
|
|
f: Output file handle.
|
|
"""
|
|
f.write("""\
|
|
// global functions
|
|
if (instance == VK_NULL_HANDLE) {\n""")
|
|
|
|
for cmd in gencom.command_list:
|
|
# vkGetInstanceProcAddr(nullptr, "vkGetInstanceProcAddr") is effectively
|
|
# globally dispatched
|
|
if gencom.is_globally_dispatched(cmd) or cmd == 'vkGetInstanceProcAddr':
|
|
f.write(gencom.indent(2) +
|
|
'if (strcmp(pName, \"' + cmd +
|
|
'\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
|
|
gencom.base_name(cmd) + ');\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""")
|
|
|
|
sorted_command_list = sorted(gencom.command_list)
|
|
for cmd in sorted_command_list:
|
|
if gencom.is_function_exported(cmd):
|
|
if gencom.is_globally_dispatched(cmd):
|
|
f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
|
|
elif (_is_intercepted(cmd) or
|
|
cmd == 'vkGetInstanceProcAddr' or
|
|
gencom.is_device_dispatched(cmd)):
|
|
f.write(gencom.indent(2) + '{ \"' + cmd +
|
|
'\", reinterpret_cast<PFN_vkVoidFunction>(' +
|
|
gencom.base_name(cmd) + ') },\n')
|
|
|
|
f.write("""\
|
|
};
|
|
// 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 _intercept_device_proc_addr(f):
|
|
"""Emits code for vkGetDeviceProcAddr for function interception.
|
|
|
|
Args:
|
|
f: Output file handle.
|
|
"""
|
|
f.write("""\
|
|
if (device == VK_NULL_HANDLE) {
|
|
ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
|
|
return nullptr;
|
|
}
|
|
|
|
static const char* const known_non_device_names[] = {\n""")
|
|
|
|
sorted_command_list = sorted(gencom.command_list)
|
|
for cmd in sorted_command_list:
|
|
if gencom.is_function_supported(cmd):
|
|
if not gencom.is_device_dispatched(cmd):
|
|
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
|
|
|
|
f.write("""\
|
|
};
|
|
// 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 cmd in gencom.command_list:
|
|
if gencom.is_device_dispatched(cmd):
|
|
if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
|
|
f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
|
|
'") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
|
|
gencom.base_name(cmd) + ');\n')
|
|
f.write('\n')
|
|
|
|
|
|
def _api_dispatch(cmd, f):
|
|
"""Emits code to dispatch a function.
|
|
|
|
Args:
|
|
cmd: Vulkan function name.
|
|
f: Output file handle.
|
|
"""
|
|
assert not _is_intercepted(cmd)
|
|
|
|
f.write(gencom.indent(1))
|
|
if gencom.return_type_dict[cmd] != 'void':
|
|
f.write('return ')
|
|
|
|
param_list = gencom.param_dict[cmd]
|
|
handle = param_list[0][1]
|
|
f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
|
|
'(' + ', '.join(i[1] for i in param_list) + ');\n')
|
|
|
|
|
|
def gen_cpp():
|
|
"""Generates the api_gen.cpp file.
|
|
"""
|
|
genfile = os.path.join(os.path.dirname(__file__),
|
|
'..', 'libvulkan', 'api_gen.cpp')
|
|
|
|
with open(genfile, 'w') as f:
|
|
f.write(gencom.copyright_and_warning(2016))
|
|
|
|
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 {
|
|
|
|
#define UNLIKELY(expr) __builtin_expect((expr), 0)
|
|
|
|
#define INIT_PROC(required, obj, proc) \\
|
|
do { \\
|
|
data.dispatch.proc = \\
|
|
reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
|
|
if (UNLIKELY(required && !data.dispatch.proc)) { \\
|
|
ALOGE("missing " #obj " proc: vk" #proc); \\
|
|
success = false; \\
|
|
} \\
|
|
} while (0)
|
|
|
|
// Exported extension functions may be invoked even when their extensions
|
|
// are disabled. Dispatch to stubs when that happens.
|
|
#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)
|
|
|
|
namespace {
|
|
|
|
// clang-format off\n\n""")
|
|
|
|
for cmd in gencom.command_list:
|
|
_define_extension_stub(cmd, f)
|
|
|
|
f.write("""\
|
|
// clang-format on
|
|
|
|
} // namespace
|
|
|
|
bool InitDispatchTable(
|
|
VkInstance instance,
|
|
PFN_vkGetInstanceProcAddr get_proc,
|
|
const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
|
|
auto& data = GetData(instance);
|
|
bool success = true;
|
|
|
|
// clang-format off\n""")
|
|
|
|
for cmd in gencom.command_list:
|
|
if gencom.is_instance_dispatch_table_entry(cmd):
|
|
gencom.init_proc(cmd, f)
|
|
|
|
f.write("""\
|
|
// clang-format on
|
|
|
|
return success;
|
|
}
|
|
|
|
bool InitDispatchTable(
|
|
VkDevice dev,
|
|
PFN_vkGetDeviceProcAddr get_proc,
|
|
const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
|
|
auto& data = GetData(dev);
|
|
bool success = true;
|
|
|
|
// clang-format off\n""")
|
|
|
|
for cmd in gencom.command_list:
|
|
if gencom.is_device_dispatch_table_entry(cmd):
|
|
gencom.init_proc(cmd, f)
|
|
|
|
f.write("""\
|
|
// clang-format on
|
|
|
|
return success;
|
|
}
|
|
|
|
// clang-format off
|
|
|
|
namespace {
|
|
|
|
// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
|
|
""")
|
|
|
|
for cmd in gencom.command_list:
|
|
if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
|
|
param_list = [''.join(i) for i in gencom.param_dict[cmd]]
|
|
f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
|
|
gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
|
|
|
|
f.write('\n')
|
|
for cmd in gencom.command_list:
|
|
if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
|
|
param_list = [''.join(i) for i in gencom.param_dict[cmd]]
|
|
f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
|
|
gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
|
|
if cmd == 'vkGetInstanceProcAddr':
|
|
_intercept_instance_proc_addr(f)
|
|
elif cmd == 'vkGetDeviceProcAddr':
|
|
_intercept_device_proc_addr(f)
|
|
_api_dispatch(cmd, f)
|
|
f.write('}\n\n')
|
|
|
|
f.write("""
|
|
} // anonymous namespace
|
|
|
|
// clang-format on
|
|
|
|
} // namespace api
|
|
} // namespace vulkan
|
|
|
|
// clang-format off\n\n""")
|
|
|
|
for cmd in gencom.command_list:
|
|
if gencom.is_function_exported(cmd):
|
|
param_list = [''.join(i) for i in gencom.param_dict[cmd]]
|
|
f.write('__attribute__((visibility("default")))\n')
|
|
f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
|
|
cmd + '(' + ', '.join(param_list) + ') {\n')
|
|
f.write(gencom.indent(1))
|
|
if gencom.return_type_dict[cmd] != 'void':
|
|
f.write('return ')
|
|
param_list = gencom.param_dict[cmd]
|
|
f.write('vulkan::api::' + gencom.base_name(cmd) +
|
|
'(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
|
|
|
|
f.write('// clang-format on\n')
|
|
f.close()
|
|
gencom.run_clang_format(genfile)
|