def _is_device_driver_table_entry(cmd): """Returns true if a device-dispatched function is needed by vulkan::driver. Args: cmd: Vulkan function name. """ return (_is_driver_table_entry(cmd) and gencom.is_device_dispatched(cmd))
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 _need_proc_hook_stub(cmd): """Returns true if a function needs a ProcHook stub. Args: cmd: Vulkan function name. """ if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd): if cmd in gencom.extension_dict: if not gencom.is_extension_internal(gencom.extension_dict[cmd]): return True elif gencom.version_dict[cmd] != 'VK_VERSION_1_0': return True return False
def gen_cpp(): """Generates the driver_gen.cpp file. """ genfile = os.path.join(os.path.dirname(__file__), '..', 'libvulkan', 'driver_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> #include "driver.h" namespace vulkan { namespace driver { namespace { // clang-format off\n\n""") for cmd in gencom.command_list: _define_proc_hook_stub(cmd, f) f.write("""\ // clang-format on const ProcHook g_proc_hooks[] = { // clang-format off\n""") sorted_command_list = sorted(gencom.command_list) for cmd in sorted_command_list: if _is_intercepted(cmd): if gencom.is_globally_dispatched(cmd): _define_global_proc_hook(cmd, f) elif gencom.is_instance_dispatched(cmd): _define_instance_proc_hook(cmd, f) elif gencom.is_device_dispatched(cmd): _define_device_proc_hook(cmd, f) f.write("""\ // clang-format on }; } // namespace 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) { // clang-format off\n""") for ext in _KNOWN_EXTENSIONS: f.write( gencom.indent(1) + 'if (strcmp(name, \"' + ext + '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n') f.write("""\ // clang-format on return ProcHook::EXTENSION_UNKNOWN; } #define UNLIKELY(expr) __builtin_expect((expr), 0) #define INIT_PROC(required, obj, proc) \\ do { \\ data.driver.proc = \\ reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ if (UNLIKELY(required && !data.driver.proc)) { \\ ALOGE("missing " #obj " proc: vk" #proc); \\ success = false; \\ } \\ } while (0) #define INIT_PROC_EXT(ext, required, obj, proc) \\ do { \\ if (extensions[ProcHook::ext]) \\ INIT_PROC(required, obj, proc); \\ } while (0) bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { auto& data = GetData(instance); bool success = true; // clang-format off\n""") for cmd in gencom.command_list: if _is_instance_driver_table_entry(cmd): gencom.init_proc(cmd, f) f.write("""\ // clang-format on return success; } bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { auto& data = GetData(dev); bool success = true; // clang-format off\n""") for cmd in gencom.command_list: if _is_device_driver_table_entry(cmd): gencom.init_proc(cmd, f) f.write("""\ // clang-format on return success; } } // namespace driver } // namespace vulkan\n""") f.close() gencom.run_clang_format(genfile)
def gen_cpp(): """Generates the driver_gen.cpp file. """ genfile = os.path.join(os.path.dirname(__file__), '..', 'libvulkan', 'driver_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> #include "driver.h" namespace vulkan { namespace driver { namespace { // clang-format off\n\n""") for cmd in gencom.command_list: _define_proc_hook_stub(cmd, f) f.write("""\ // clang-format on const ProcHook g_proc_hooks[] = { // clang-format off\n""") sorted_command_list = sorted(gencom.command_list) for cmd in sorted_command_list: if _is_intercepted(cmd): if gencom.is_globally_dispatched(cmd): _define_global_proc_hook(cmd, f) elif gencom.is_instance_dispatched(cmd): _define_instance_proc_hook(cmd, f) elif gencom.is_device_dispatched(cmd): _define_device_proc_hook(cmd, f) f.write("""\ // clang-format on }; } // namespace const ProcHook* GetProcHook(const char* name) { auto begin = std::cbegin(g_proc_hooks); auto end = std::cend(g_proc_hooks); 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) { // clang-format off\n""") for ext in _KNOWN_EXTENSIONS: f.write( gencom.indent(1) + 'if (strcmp(name, \"' + ext + '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n') f.write("""\ // clang-format on return ProcHook::EXTENSION_UNKNOWN; } #define UNLIKELY(expr) __builtin_expect((expr), 0) #define INIT_PROC(required, obj, proc) \\ do { \\ data.driver.proc = \\ reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ if (UNLIKELY(required && !data.driver.proc)) { \\ ALOGE("missing " #obj " proc: vk" #proc); \\ success = false; \\ } \\ } while (0) #define INIT_PROC_EXT(ext, required, obj, proc) \\ do { \\ if (extensions[ProcHook::ext]) \\ INIT_PROC(required, obj, proc); \\ } while (0) bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { auto& data = GetData(instance); bool success = true; // clang-format off\n""") for cmd in gencom.command_list: if _is_instance_driver_table_entry(cmd): gencom.init_proc(cmd, f) f.write("""\ // clang-format on return success; } bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { auto& data = GetData(dev); bool success = true; // clang-format off\n""") for cmd in gencom.command_list: if _is_device_driver_table_entry(cmd): gencom.init_proc(cmd, f) f.write("""\ // clang-format on return success; } const std::pair<const char*, uint32_t> g_promoted_instance_extensions[] = { // clang-format off\n""") for key, value in sorted(gencom.promoted_inst_ext_dict.items()): f.write( gencom.indent(1) + 'std::make_pair("' + key + '", ' + value + '),\n') f.write("""\ // clang-format on }; std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name) { auto begin = std::cbegin(g_promoted_instance_extensions); auto end = std::cend(g_promoted_instance_extensions); auto iter = std::lower_bound(begin, end, name, [](const std::pair<const char*, uint32_t>& e, const char* n) { return strcmp(e.first, n) < 0; }); return (iter < end && strcmp(iter->first, name) == 0) ? std::optional<uint32_t>(iter->second) : std::nullopt; } uint32_t CountPromotedInstanceExtensions(uint32_t begin_version, uint32_t end_version) { auto begin = std::cbegin(g_promoted_instance_extensions); auto end = std::cend(g_promoted_instance_extensions); uint32_t count = 0; for (auto iter = begin; iter != end; iter++) if (iter->second > begin_version && iter->second <= end_version) count++; return count; } std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version, uint32_t end_version) { auto begin = std::cbegin(g_promoted_instance_extensions); auto end = std::cend(g_promoted_instance_extensions); std::vector<const char*> extensions; for (auto iter = begin; iter != end; iter++) if (iter->second > begin_version && iter->second <= end_version) extensions.emplace_back(iter->first); return extensions; } } // namespace driver } // namespace vulkan\n""") f.close() gencom.run_clang_format(genfile)