1#!/usr/bin/env python3 2# 3# Copyright 2019 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Generates the driver_gen.h and driver_gen.cpp. 18""" 19 20import os 21import generator_common as gencom 22 23# Extensions intercepted at vulkan::driver level. 24_INTERCEPTED_EXTENSIONS = [ 25 'VK_ANDROID_native_buffer', 26 'VK_EXT_debug_report', 27 'VK_EXT_hdr_metadata', 28 'VK_EXT_swapchain_colorspace', 29 'VK_GOOGLE_display_timing', 30 'VK_KHR_android_surface', 31 'VK_KHR_get_surface_capabilities2', 32 'VK_KHR_incremental_present', 33 'VK_KHR_shared_presentable_image', 34 'VK_KHR_surface', 35 'VK_KHR_swapchain', 36] 37 38# Extensions known to vulkan::driver level. 39_KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 40 'VK_ANDROID_external_memory_android_hardware_buffer', 41 'VK_KHR_bind_memory2', 42 'VK_KHR_get_physical_device_properties2', 43] 44 45# Functions needed at vulkan::driver level. 46_NEEDED_COMMANDS = [ 47 # Create functions of dispatchable objects 48 'vkCreateDevice', 49 'vkGetDeviceQueue', 50 'vkGetDeviceQueue2', 51 'vkAllocateCommandBuffers', 52 53 # Destroy functions of dispatchable objects 54 'vkDestroyInstance', 55 'vkDestroyDevice', 56 57 # Enumeration of extensions 58 'vkEnumerateDeviceExtensionProperties', 59 60 # We cache physical devices in loader.cpp 61 'vkEnumeratePhysicalDevices', 62 'vkEnumeratePhysicalDeviceGroups', 63 64 'vkGetInstanceProcAddr', 65 'vkGetDeviceProcAddr', 66 67 'vkQueueSubmit', 68 69 # VK_KHR_swapchain->VK_ANDROID_native_buffer translation 70 'vkCreateImage', 71 'vkDestroyImage', 72 73 'vkGetPhysicalDeviceProperties', 74 'vkGetPhysicalDeviceProperties2', 75 'vkGetPhysicalDeviceProperties2KHR', 76 77 # VK_KHR_swapchain v69 requirement 78 'vkBindImageMemory2', 79 'vkBindImageMemory2KHR', 80] 81 82# Functions intercepted at vulkan::driver level. 83_INTERCEPTED_COMMANDS = [ 84 # Create functions of dispatchable objects 85 'vkCreateInstance', 86 'vkCreateDevice', 87 'vkEnumeratePhysicalDevices', 88 'vkEnumeratePhysicalDeviceGroups', 89 'vkGetDeviceQueue', 90 'vkGetDeviceQueue2', 91 'vkAllocateCommandBuffers', 92 93 # Destroy functions of dispatchable objects 94 'vkDestroyInstance', 95 'vkDestroyDevice', 96 97 # Enumeration of extensions 98 'vkEnumerateInstanceExtensionProperties', 99 'vkEnumerateDeviceExtensionProperties', 100 101 'vkGetInstanceProcAddr', 102 'vkGetDeviceProcAddr', 103 104 'vkQueueSubmit', 105 106 # VK_KHR_swapchain v69 requirement 107 'vkBindImageMemory2', 108 'vkBindImageMemory2KHR', 109] 110 111 112def _is_driver_table_entry(cmd): 113 """Returns true if a function is needed by vulkan::driver. 114 115 Args: 116 cmd: Vulkan function name. 117 """ 118 if gencom.is_function_supported(cmd): 119 if cmd in _NEEDED_COMMANDS: 120 return True 121 if cmd in gencom.extension_dict: 122 if (gencom.extension_dict[cmd] == 'VK_ANDROID_native_buffer' or 123 gencom.extension_dict[cmd] == 'VK_EXT_debug_report'): 124 return True 125 return False 126 127 128def _is_instance_driver_table_entry(cmd): 129 """Returns true if a instance-dispatched function is needed by vulkan::driver. 130 131 Args: 132 cmd: Vulkan function name. 133 """ 134 return (_is_driver_table_entry(cmd) and 135 gencom.is_instance_dispatched(cmd)) 136 137 138def _is_device_driver_table_entry(cmd): 139 """Returns true if a device-dispatched function is needed by vulkan::driver. 140 141 Args: 142 cmd: Vulkan function name. 143 """ 144 return (_is_driver_table_entry(cmd) and 145 gencom.is_device_dispatched(cmd)) 146 147 148def gen_h(): 149 """Generates the driver_gen.h file. 150 """ 151 genfile = os.path.join(os.path.dirname(__file__), 152 '..', 'libvulkan', 'driver_gen.h') 153 154 with open(genfile, 'w') as f: 155 f.write(gencom.copyright_and_warning(2016)) 156 157 f.write("""\ 158#ifndef LIBVULKAN_DRIVER_GEN_H 159#define LIBVULKAN_DRIVER_GEN_H 160 161#include <vulkan/vk_android_native_buffer.h> 162#include <vulkan/vulkan.h> 163 164#include <bitset> 165 166namespace vulkan { 167namespace driver { 168 169struct ProcHook { 170 enum Type { 171 GLOBAL, 172 INSTANCE, 173 DEVICE, 174 }; 175 enum Extension {\n""") 176 177 for ext in _KNOWN_EXTENSIONS: 178 f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n') 179 180 f.write('\n') 181 for version in gencom.version_code_list: 182 f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n') 183 184 # EXTENSION_COUNT must be the next enum after the highest API version. 185 f.write("""\ 186 EXTENSION_COUNT, 187 EXTENSION_UNKNOWN, 188 }; 189 190 const char* name; 191 Type type; 192 Extension extension; 193 194 PFN_vkVoidFunction proc; 195 PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks 196}; 197 198struct InstanceDriverTable { 199 // clang-format off\n""") 200 201 for cmd in gencom.command_list: 202 if _is_instance_driver_table_entry(cmd): 203 f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' + 204 gencom.base_name(cmd) + ';\n') 205 206 f.write("""\ 207 // clang-format on 208}; 209 210struct DeviceDriverTable { 211 // clang-format off\n""") 212 213 for cmd in gencom.command_list: 214 if _is_device_driver_table_entry(cmd): 215 f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' + 216 gencom.base_name(cmd) + ';\n') 217 218 f.write("""\ 219 // clang-format on 220}; 221 222const ProcHook* GetProcHook(const char* name); 223ProcHook::Extension GetProcHookExtension(const char* name); 224 225bool InitDriverTable(VkInstance instance, 226 PFN_vkGetInstanceProcAddr get_proc, 227 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); 228bool InitDriverTable(VkDevice dev, 229 PFN_vkGetDeviceProcAddr get_proc, 230 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); 231 232} // namespace driver 233} // namespace vulkan 234 235#endif // LIBVULKAN_DRIVER_TABLE_H\n""") 236 237 f.close() 238 gencom.run_clang_format(genfile) 239 240 241def _is_intercepted(cmd): 242 """Returns true if a function is intercepted by vulkan::driver. 243 244 Args: 245 cmd: Vulkan function name. 246 """ 247 if gencom.is_function_supported(cmd): 248 if cmd in _INTERCEPTED_COMMANDS: 249 return True 250 251 if cmd in gencom.extension_dict: 252 return gencom.extension_dict[cmd] in _INTERCEPTED_EXTENSIONS 253 return False 254 255 256def _get_proc_hook_enum(cmd): 257 """Returns the ProcHook enumeration for the corresponding core function. 258 259 Args: 260 cmd: Vulkan function name. 261 """ 262 assert cmd in gencom.version_dict 263 for version in gencom.version_code_list: 264 if gencom.version_dict[cmd] == 'VK_VERSION_' + version: 265 return 'ProcHook::EXTENSION_CORE_' + version 266 267 268def _need_proc_hook_stub(cmd): 269 """Returns true if a function needs a ProcHook stub. 270 271 Args: 272 cmd: Vulkan function name. 273 """ 274 if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd): 275 if cmd in gencom.extension_dict: 276 if not gencom.is_extension_internal(gencom.extension_dict[cmd]): 277 return True 278 elif gencom.version_dict[cmd] != 'VK_VERSION_1_0': 279 return True 280 return False 281 282 283def _define_proc_hook_stub(cmd, f): 284 """Emits a stub for ProcHook::checked_proc. 285 286 Args: 287 cmd: Vulkan function name. 288 f: Output file handle. 289 """ 290 if _need_proc_hook_stub(cmd): 291 return_type = gencom.return_type_dict[cmd] 292 293 ext_name = '' 294 ext_hook = '' 295 if cmd in gencom.extension_dict: 296 ext_name = gencom.extension_dict[cmd] 297 ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name) 298 else: 299 ext_name = gencom.version_dict[cmd] 300 ext_hook = _get_proc_hook_enum(cmd) 301 302 handle = gencom.param_dict[cmd][0][1] 303 param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]]) 304 param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]]) 305 306 f.write('VKAPI_ATTR ' + return_type + ' checked' + gencom.base_name(cmd) + 307 '(' + param_types + ') {\n') 308 f.write(gencom.indent(1) + 'if (GetData(' + handle + ').hook_extensions[' + 309 ext_hook + ']) {\n') 310 311 f.write(gencom.indent(2)) 312 if gencom.return_type_dict[cmd] != 'void': 313 f.write('return ') 314 f.write(gencom.base_name(cmd) + '(' + param_names + ');\n') 315 316 f.write(gencom.indent(1) + '} else {\n') 317 f.write(gencom.indent(2) + 'Logger(' + handle + ').Err(' + handle + ', \"' + 318 ext_name + ' not enabled. ' + cmd + ' not executed.\");\n') 319 if gencom.return_type_dict[cmd] != 'void': 320 f.write(gencom.indent(2) + 'return VK_SUCCESS;\n') 321 f.write(gencom.indent(1) + '}\n}\n\n') 322 323 324def _define_global_proc_hook(cmd, f): 325 """Emits definition of a global ProcHook. 326 327 Args: 328 cmd: Vulkan function name. 329 f: Output file handle. 330 """ 331 assert cmd not in gencom.extension_dict 332 333 f.write(gencom.indent(1) + '{\n') 334 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 335 f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n') 336 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 337 f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' + 338 gencom.base_name(cmd) + '),\n') 339 f.write(gencom.indent(2) + 'nullptr,\n') 340 f.write(gencom.indent(1) + '},\n') 341 342 343def _define_instance_proc_hook(cmd, f): 344 """Emits definition of a instance ProcHook. 345 346 Args: 347 cmd: Vulkan function name. 348 f: Output file handle. 349 """ 350 f.write(gencom.indent(1) + '{\n') 351 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 352 f.write(gencom.indent(2) + 'ProcHook::INSTANCE,\n') 353 354 if cmd in gencom.extension_dict: 355 ext_name = gencom.extension_dict[cmd] 356 f.write(gencom.indent(2) + 'ProcHook::' + 357 gencom.base_ext_name(ext_name) + ',\n') 358 359 if gencom.is_extension_internal(ext_name): 360 f.write("""\ 361 nullptr, 362 nullptr,\n""") 363 else: 364 f.write("""\ 365 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 366 nullptr,\n""") 367 else: 368 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 369 f.write("""\ 370 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 371 nullptr,\n""") 372 373 f.write(gencom.indent(1) + '},\n') 374 375 376def _define_device_proc_hook(cmd, f): 377 """Emits definition of a device ProcHook. 378 379 Args: 380 cmd: Vulkan function name. 381 f: Output file handle. 382 """ 383 f.write(gencom.indent(1) + '{\n') 384 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 385 f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n') 386 387 if (cmd in gencom.extension_dict or 388 gencom.version_dict[cmd] != 'VK_VERSION_1_0'): 389 ext_name = '' 390 ext_hook = '' 391 if cmd in gencom.extension_dict: 392 ext_name = gencom.extension_dict[cmd] 393 ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name) 394 else: 395 ext_name = gencom.version_dict[cmd] 396 ext_hook = _get_proc_hook_enum(cmd) 397 f.write(gencom.indent(2) + ext_hook + ',\n') 398 399 if gencom.is_extension_internal(ext_name): 400 f.write("""\ 401 nullptr, 402 nullptr,\n""") 403 else: 404 f.write("""\ 405 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 406 reinterpret_cast<PFN_vkVoidFunction>(checked""" + 407 gencom.base_name(cmd) + '),\n') 408 409 else: 410 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 411 f.write("""\ 412 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 413 nullptr,\n""") 414 415 f.write(gencom.indent(1) + '},\n') 416 417 418def gen_cpp(): 419 """Generates the driver_gen.cpp file. 420 """ 421 genfile = os.path.join(os.path.dirname(__file__), 422 '..', 'libvulkan', 'driver_gen.cpp') 423 424 with open(genfile, 'w') as f: 425 f.write(gencom.copyright_and_warning(2016)) 426 f.write("""\ 427#include <log/log.h> 428#include <string.h> 429 430#include <algorithm> 431 432#include "driver.h" 433 434namespace vulkan { 435namespace driver { 436 437namespace { 438 439// clang-format off\n\n""") 440 441 for cmd in gencom.command_list: 442 _define_proc_hook_stub(cmd, f) 443 444 f.write("""\ 445// clang-format on 446 447const ProcHook g_proc_hooks[] = { 448 // clang-format off\n""") 449 450 sorted_command_list = sorted(gencom.command_list) 451 for cmd in sorted_command_list: 452 if _is_intercepted(cmd): 453 if gencom.is_globally_dispatched(cmd): 454 _define_global_proc_hook(cmd, f) 455 elif gencom.is_instance_dispatched(cmd): 456 _define_instance_proc_hook(cmd, f) 457 elif gencom.is_device_dispatched(cmd): 458 _define_device_proc_hook(cmd, f) 459 460 f.write("""\ 461 // clang-format on 462}; 463 464} // namespace 465 466const ProcHook* GetProcHook(const char* name) { 467 const auto& begin = g_proc_hooks; 468 const auto& end = 469 g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); 470 const auto hook = std::lower_bound( 471 begin, end, name, 472 [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); 473 return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; 474} 475 476ProcHook::Extension GetProcHookExtension(const char* name) { 477 // clang-format off\n""") 478 479 for ext in _KNOWN_EXTENSIONS: 480 f.write(gencom.indent(1) + 'if (strcmp(name, \"' + ext + 481 '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n') 482 483 f.write("""\ 484 // clang-format on 485 return ProcHook::EXTENSION_UNKNOWN; 486} 487 488#define UNLIKELY(expr) __builtin_expect((expr), 0) 489 490#define INIT_PROC(required, obj, proc) \\ 491 do { \\ 492 data.driver.proc = \\ 493 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ 494 if (UNLIKELY(required && !data.driver.proc)) { \\ 495 ALOGE("missing " #obj " proc: vk" #proc); \\ 496 success = false; \\ 497 } \\ 498 } while (0) 499 500#define INIT_PROC_EXT(ext, required, obj, proc) \\ 501 do { \\ 502 if (extensions[ProcHook::ext]) \\ 503 INIT_PROC(required, obj, proc); \\ 504 } while (0) 505 506bool InitDriverTable(VkInstance instance, 507 PFN_vkGetInstanceProcAddr get_proc, 508 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { 509 auto& data = GetData(instance); 510 bool success = true; 511 512 // clang-format off\n""") 513 514 for cmd in gencom.command_list: 515 if _is_instance_driver_table_entry(cmd): 516 gencom.init_proc(cmd, f) 517 518 f.write("""\ 519 // clang-format on 520 521 return success; 522} 523 524bool InitDriverTable(VkDevice dev, 525 PFN_vkGetDeviceProcAddr get_proc, 526 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { 527 auto& data = GetData(dev); 528 bool success = true; 529 530 // clang-format off\n""") 531 532 for cmd in gencom.command_list: 533 if _is_device_driver_table_entry(cmd): 534 gencom.init_proc(cmd, f) 535 536 f.write("""\ 537 // clang-format on 538 539 return success; 540} 541 542} // namespace driver 543} // namespace vulkan\n""") 544 545 f.close() 546 gencom.run_clang_format(genfile) 547