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_GOOGLE_surfaceless_query', 31 'VK_KHR_android_surface', 32 'VK_KHR_get_surface_capabilities2', 33 'VK_KHR_incremental_present', 34 'VK_KHR_shared_presentable_image', 35 'VK_KHR_surface', 36 'VK_KHR_surface_protected_capabilities', 37 'VK_KHR_swapchain', 38 'VK_EXT_swapchain_maintenance1', 39 'VK_EXT_surface_maintenance1', 40] 41 42# Extensions known to vulkan::driver level. 43_KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ 44 'VK_ANDROID_external_memory_android_hardware_buffer', 45 'VK_KHR_bind_memory2', 46 'VK_KHR_get_physical_device_properties2', 47 'VK_KHR_device_group_creation', 48 'VK_KHR_external_memory_capabilities', 49 'VK_KHR_external_semaphore_capabilities', 50 'VK_KHR_external_fence_capabilities', 51 'VK_KHR_external_fence_fd', 52 'VK_KHR_swapchain_mutable_format', 53] 54 55# Functions needed at vulkan::driver level. 56_NEEDED_COMMANDS = [ 57 # Create functions of dispatchable objects 58 'vkCreateDevice', 59 'vkGetDeviceQueue', 60 'vkGetDeviceQueue2', 61 'vkAllocateCommandBuffers', 62 63 # Destroy functions of dispatchable objects 64 'vkDestroyInstance', 65 'vkDestroyDevice', 66 67 # Enumeration of extensions 68 'vkEnumerateDeviceExtensionProperties', 69 70 # We cache physical devices in loader.cpp 71 'vkEnumeratePhysicalDevices', 72 'vkEnumeratePhysicalDeviceGroups', 73 74 'vkGetInstanceProcAddr', 75 'vkGetDeviceProcAddr', 76 77 'vkQueueSubmit', 78 79 # VK_KHR_swapchain->VK_ANDROID_native_buffer translation 80 'vkCreateImage', 81 'vkDestroyImage', 82 83 'vkGetPhysicalDeviceProperties', 84 85 # VK_KHR_swapchain v69 requirement 86 'vkBindImageMemory2', 87 'vkBindImageMemory2KHR', 88 89 # For promoted VK_KHR_device_group_creation 90 'vkEnumeratePhysicalDeviceGroupsKHR', 91 92 # For promoted VK_KHR_get_physical_device_properties2 93 'vkGetPhysicalDeviceFeatures2', 94 'vkGetPhysicalDeviceFeatures2KHR', 95 'vkGetPhysicalDeviceProperties2', 96 'vkGetPhysicalDeviceProperties2KHR', 97 'vkGetPhysicalDeviceFormatProperties2', 98 'vkGetPhysicalDeviceFormatProperties2KHR', 99 'vkGetPhysicalDeviceImageFormatProperties2', 100 'vkGetPhysicalDeviceImageFormatProperties2KHR', 101 'vkGetPhysicalDeviceQueueFamilyProperties2', 102 'vkGetPhysicalDeviceQueueFamilyProperties2KHR', 103 'vkGetPhysicalDeviceMemoryProperties2', 104 'vkGetPhysicalDeviceMemoryProperties2KHR', 105 'vkGetPhysicalDeviceSparseImageFormatProperties2', 106 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR', 107 108 # For promoted VK_KHR_external_memory_capabilities 109 'vkGetPhysicalDeviceExternalBufferProperties', 110 'vkGetPhysicalDeviceExternalBufferPropertiesKHR', 111 112 # For promoted VK_KHR_external_semaphore_capabilities 113 'vkGetPhysicalDeviceExternalSemaphoreProperties', 114 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR', 115 116 # For promoted VK_KHR_external_fence_capabilities 117 'vkGetPhysicalDeviceExternalFenceProperties', 118 'vkGetPhysicalDeviceExternalFencePropertiesKHR', 119 120 # VK_KHR_swapchain_maintenance1 requirement 121 'vkImportFenceFdKHR', 122] 123 124# Functions intercepted at vulkan::driver level. 125_INTERCEPTED_COMMANDS = [ 126 # Create functions of dispatchable objects 127 'vkCreateInstance', 128 'vkCreateDevice', 129 'vkEnumeratePhysicalDevices', 130 'vkEnumeratePhysicalDeviceGroups', 131 'vkGetDeviceQueue', 132 'vkGetDeviceQueue2', 133 'vkAllocateCommandBuffers', 134 135 # Destroy functions of dispatchable objects 136 'vkDestroyInstance', 137 'vkDestroyDevice', 138 139 # Enumeration of extensions 140 'vkEnumerateInstanceExtensionProperties', 141 'vkEnumerateDeviceExtensionProperties', 142 143 'vkGetInstanceProcAddr', 144 'vkGetDeviceProcAddr', 145 146 'vkQueueSubmit', 147 148 # VK_KHR_swapchain v69 requirement 149 'vkBindImageMemory2', 150 'vkBindImageMemory2KHR', 151 152 # For promoted VK_KHR_get_physical_device_properties2 153 'vkGetPhysicalDeviceFeatures2', 154 'vkGetPhysicalDeviceProperties2', 155 'vkGetPhysicalDeviceFormatProperties2', 156 'vkGetPhysicalDeviceImageFormatProperties2', 157 'vkGetPhysicalDeviceQueueFamilyProperties2', 158 'vkGetPhysicalDeviceMemoryProperties2', 159 'vkGetPhysicalDeviceSparseImageFormatProperties2', 160 161 # For promoted VK_KHR_external_memory_capabilities 162 'vkGetPhysicalDeviceExternalBufferProperties', 163 164 # For promoted VK_KHR_external_semaphore_capabilities 165 'vkGetPhysicalDeviceExternalSemaphoreProperties', 166 167 # For promoted VK_KHR_external_fence_capabilities 168 'vkGetPhysicalDeviceExternalFenceProperties', 169] 170 171 172def _is_driver_table_entry(cmd): 173 """Returns true if a function is needed by vulkan::driver. 174 175 Args: 176 cmd: Vulkan function name. 177 """ 178 if gencom.is_function_supported(cmd): 179 if cmd in _NEEDED_COMMANDS: 180 return True 181 if cmd in gencom.extension_dict: 182 if (gencom.extension_dict[cmd] == 'VK_ANDROID_native_buffer' or 183 gencom.extension_dict[cmd] == 'VK_EXT_debug_report'): 184 return True 185 return False 186 187 188def _is_instance_driver_table_entry(cmd): 189 """Returns true if a instance-dispatched function is needed by vulkan::driver. 190 191 Args: 192 cmd: Vulkan function name. 193 """ 194 return (_is_driver_table_entry(cmd) and 195 gencom.is_instance_dispatched(cmd)) 196 197 198def _is_device_driver_table_entry(cmd): 199 """Returns true if a device-dispatched function is needed by vulkan::driver. 200 201 Args: 202 cmd: Vulkan function name. 203 """ 204 return (_is_driver_table_entry(cmd) and 205 gencom.is_device_dispatched(cmd)) 206 207 208def gen_h(): 209 """Generates the driver_gen.h file. 210 """ 211 genfile = os.path.join(os.path.dirname(__file__), 212 '..', 'libvulkan', 'driver_gen.h') 213 214 with open(genfile, 'w') as f: 215 f.write(gencom.copyright_and_warning(2016)) 216 217 f.write("""\ 218#ifndef LIBVULKAN_DRIVER_GEN_H 219#define LIBVULKAN_DRIVER_GEN_H 220 221#include <vulkan/vk_android_native_buffer.h> 222#include <vulkan/vulkan.h> 223 224#include <bitset> 225#include <optional> 226#include <vector> 227 228/* 229 * This file is autogenerated by driver_generator.py. Do not edit directly. 230 */ 231namespace vulkan { 232namespace driver { 233 234struct ProcHook { 235 enum Type { 236 GLOBAL, 237 INSTANCE, 238 DEVICE, 239 }; 240 enum Extension {\n""") 241 242 for ext in _KNOWN_EXTENSIONS: 243 f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n') 244 245 f.write('\n') 246 # EXTENSION_CORE_xxx API list must be the last set of enums after the extensions. 247 # This allows to easily identify "a" core function hook 248 for version in gencom.version_code_list: 249 f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n') 250 251 # EXTENSION_COUNT must be the next enum after the highest API version. 252 f.write("""\ 253 EXTENSION_COUNT, 254 EXTENSION_UNKNOWN, 255 }; 256 257 const char* name; 258 Type type; 259 Extension extension; 260 261 PFN_vkVoidFunction proc; 262 PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks 263}; 264 265struct InstanceDriverTable { 266 // clang-format off\n""") 267 268 for cmd in gencom.command_list: 269 if _is_instance_driver_table_entry(cmd): 270 f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' + 271 gencom.base_name(cmd) + ';\n') 272 273 f.write("""\ 274 // clang-format on 275}; 276 277struct DeviceDriverTable { 278 // clang-format off\n""") 279 280 for cmd in gencom.command_list: 281 if _is_device_driver_table_entry(cmd): 282 f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' + 283 gencom.base_name(cmd) + ';\n') 284 285 f.write("""\ 286 // clang-format on 287}; 288 289const ProcHook* GetProcHook(const char* name); 290ProcHook::Extension GetProcHookExtension(const char* name); 291 292bool InitDriverTable(VkInstance instance, 293 PFN_vkGetInstanceProcAddr get_proc, 294 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); 295bool InitDriverTable(VkDevice dev, 296 PFN_vkGetDeviceProcAddr get_proc, 297 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); 298 299std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name); 300uint32_t CountPromotedInstanceExtensions(uint32_t begin_version, 301 uint32_t end_version); 302std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version, 303 uint32_t end_version); 304 305} // namespace driver 306} // namespace vulkan 307 308#endif // LIBVULKAN_DRIVER_TABLE_H\n""") 309 310 f.close() 311 gencom.run_clang_format(genfile) 312 313 314def _is_intercepted(cmd): 315 """Returns true if a function is intercepted by vulkan::driver. 316 317 Args: 318 cmd: Vulkan function name. 319 """ 320 if gencom.is_function_supported(cmd): 321 if cmd in _INTERCEPTED_COMMANDS: 322 return True 323 324 if cmd in gencom.extension_dict: 325 return gencom.extension_dict[cmd] in _INTERCEPTED_EXTENSIONS 326 return False 327 328 329def _get_proc_hook_enum(cmd): 330 """Returns the ProcHook enumeration for the corresponding core function. 331 332 Args: 333 cmd: Vulkan function name. 334 """ 335 assert cmd in gencom.version_dict 336 for version in gencom.version_code_list: 337 if gencom.version_dict[cmd] == 'VK_VERSION_' + version: 338 return 'ProcHook::EXTENSION_CORE_' + version 339 340 341def _need_proc_hook_stub(cmd): 342 """Returns true if a function needs a ProcHook stub. 343 344 Args: 345 cmd: Vulkan function name. 346 """ 347 if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd): 348 if cmd in gencom.extension_dict: 349 if not gencom.is_extension_internal(gencom.extension_dict[cmd]): 350 return True 351 elif gencom.version_dict[cmd] != 'VK_VERSION_1_0': 352 return True 353 return False 354 355 356def _define_proc_hook_stub(cmd, f): 357 """Emits a stub for ProcHook::checked_proc. 358 359 Args: 360 cmd: Vulkan function name. 361 f: Output file handle. 362 """ 363 if _need_proc_hook_stub(cmd): 364 return_type = gencom.return_type_dict[cmd] 365 366 ext_name = '' 367 ext_hook = '' 368 if cmd in gencom.extension_dict: 369 ext_name = gencom.extension_dict[cmd] 370 ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name) 371 else: 372 ext_name = gencom.version_dict[cmd] 373 ext_hook = _get_proc_hook_enum(cmd) 374 375 handle = gencom.param_dict[cmd][0][1] 376 param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]]) 377 param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]]) 378 379 f.write('VKAPI_ATTR ' + return_type + ' checked' + gencom.base_name(cmd) + 380 '(' + param_types + ') {\n') 381 f.write(gencom.indent(1) + 'if (GetData(' + handle + ').hook_extensions[' + 382 ext_hook + ']) {\n') 383 384 f.write(gencom.indent(2)) 385 if gencom.return_type_dict[cmd] != 'void': 386 f.write('return ') 387 f.write(gencom.base_name(cmd) + '(' + param_names + ');\n') 388 389 f.write(gencom.indent(1) + '} else {\n') 390 f.write(gencom.indent(2) + 'Logger(' + handle + ').Err(' + handle + ', \"' + 391 ext_name + ' not enabled. ' + cmd + ' not executed.\");\n') 392 if gencom.return_type_dict[cmd] != 'void': 393 f.write(gencom.indent(2) + 'return VK_SUCCESS;\n') 394 f.write(gencom.indent(1) + '}\n}\n\n') 395 396 397def _define_global_proc_hook(cmd, f): 398 """Emits definition of a global ProcHook. 399 400 Args: 401 cmd: Vulkan function name. 402 f: Output file handle. 403 """ 404 assert cmd not in gencom.extension_dict 405 406 f.write(gencom.indent(1) + '{\n') 407 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 408 f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n') 409 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 410 f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' + 411 gencom.base_name(cmd) + '),\n') 412 f.write(gencom.indent(2) + 'nullptr,\n') 413 f.write(gencom.indent(1) + '},\n') 414 415 416def _define_instance_proc_hook(cmd, f): 417 """Emits definition of a instance ProcHook. 418 419 Args: 420 cmd: Vulkan function name. 421 f: Output file handle. 422 """ 423 f.write(gencom.indent(1) + '{\n') 424 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 425 f.write(gencom.indent(2) + 'ProcHook::INSTANCE,\n') 426 427 if cmd in gencom.extension_dict: 428 ext_name = gencom.extension_dict[cmd] 429 f.write(gencom.indent(2) + 'ProcHook::' + 430 gencom.base_ext_name(ext_name) + ',\n') 431 432 if gencom.is_extension_internal(ext_name): 433 f.write("""\ 434 nullptr, 435 nullptr,\n""") 436 else: 437 f.write("""\ 438 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 439 nullptr,\n""") 440 else: 441 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 442 f.write("""\ 443 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 444 nullptr,\n""") 445 446 f.write(gencom.indent(1) + '},\n') 447 448 449def _define_device_proc_hook(cmd, f): 450 """Emits definition of a device ProcHook. 451 452 Args: 453 cmd: Vulkan function name. 454 f: Output file handle. 455 """ 456 f.write(gencom.indent(1) + '{\n') 457 f.write(gencom.indent(2) + '\"' + cmd + '\",\n') 458 f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n') 459 460 if (cmd in gencom.extension_dict or 461 gencom.version_dict[cmd] != 'VK_VERSION_1_0'): 462 ext_name = '' 463 ext_hook = '' 464 if cmd in gencom.extension_dict: 465 ext_name = gencom.extension_dict[cmd] 466 ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name) 467 else: 468 ext_name = gencom.version_dict[cmd] 469 ext_hook = _get_proc_hook_enum(cmd) 470 f.write(gencom.indent(2) + ext_hook + ',\n') 471 472 if gencom.is_extension_internal(ext_name): 473 f.write("""\ 474 nullptr, 475 nullptr,\n""") 476 else: 477 f.write("""\ 478 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 479 reinterpret_cast<PFN_vkVoidFunction>(checked""" + 480 gencom.base_name(cmd) + '),\n') 481 482 else: 483 f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n') 484 f.write("""\ 485 reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """), 486 nullptr,\n""") 487 488 f.write(gencom.indent(1) + '},\n') 489 490 491def gen_cpp(): 492 """Generates the driver_gen.cpp file. 493 """ 494 genfile = os.path.join(os.path.dirname(__file__), 495 '..', 'libvulkan', 'driver_gen.cpp') 496 497 with open(genfile, 'w') as f: 498 f.write(gencom.copyright_and_warning(2016)) 499 f.write("""\ 500#include <log/log.h> 501#include <string.h> 502 503#include <algorithm> 504 505#include "driver.h" 506 507namespace vulkan { 508namespace driver { 509 510/* 511 * This file is autogenerated by driver_generator.py. Do not edit directly. 512 */ 513namespace { 514 515// clang-format off\n\n""") 516 517 for cmd in gencom.command_list: 518 _define_proc_hook_stub(cmd, f) 519 520 f.write("""\ 521// clang-format on 522 523const ProcHook g_proc_hooks[] = { 524 // clang-format off\n""") 525 526 sorted_command_list = sorted(gencom.command_list) 527 for cmd in sorted_command_list: 528 if _is_intercepted(cmd): 529 if gencom.is_globally_dispatched(cmd): 530 _define_global_proc_hook(cmd, f) 531 elif gencom.is_instance_dispatched(cmd): 532 _define_instance_proc_hook(cmd, f) 533 elif gencom.is_device_dispatched(cmd): 534 _define_device_proc_hook(cmd, f) 535 536 f.write("""\ 537 // clang-format on 538}; 539 540} // namespace 541 542const ProcHook* GetProcHook(const char* name) { 543 auto begin = std::cbegin(g_proc_hooks); 544 auto end = std::cend(g_proc_hooks); 545 auto hook = std::lower_bound( 546 begin, end, name, 547 [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); 548 return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; 549} 550 551ProcHook::Extension GetProcHookExtension(const char* name) { 552 // clang-format off\n""") 553 554 for ext in _KNOWN_EXTENSIONS: 555 f.write(gencom.indent(1) + 'if (strcmp(name, \"' + ext + 556 '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n') 557 558 f.write("""\ 559 // clang-format on 560 return ProcHook::EXTENSION_UNKNOWN; 561} 562 563#define UNLIKELY(expr) __builtin_expect((expr), 0) 564 565#define INIT_PROC(required, obj, proc) \\ 566 do { \\ 567 data.driver.proc = \\ 568 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ 569 if (UNLIKELY(required && !data.driver.proc)) { \\ 570 ALOGE("missing " #obj " proc: vk" #proc); \\ 571 success = false; \\ 572 } \\ 573 } while (0) 574 575#define INIT_PROC_EXT(ext, required, obj, proc) \\ 576 do { \\ 577 if (extensions[ProcHook::ext]) \\ 578 INIT_PROC(required, obj, proc); \\ 579 } while (0) 580 581bool InitDriverTable(VkInstance instance, 582 PFN_vkGetInstanceProcAddr get_proc, 583 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { 584 auto& data = GetData(instance); 585 bool success = true; 586 587 // clang-format off\n""") 588 589 for cmd in gencom.command_list: 590 if _is_instance_driver_table_entry(cmd): 591 gencom.init_proc(cmd, f) 592 593 f.write("""\ 594 // clang-format on 595 596 return success; 597} 598 599bool InitDriverTable(VkDevice dev, 600 PFN_vkGetDeviceProcAddr get_proc, 601 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { 602 auto& data = GetData(dev); 603 bool success = true; 604 605 // clang-format off\n""") 606 607 for cmd in gencom.command_list: 608 if _is_device_driver_table_entry(cmd): 609 gencom.init_proc(cmd, f) 610 611 f.write("""\ 612 // clang-format on 613 614 return success; 615} 616 617const std::pair<const char*, uint32_t> g_promoted_instance_extensions[] = { 618 // clang-format off\n""") 619 620 for key, value in sorted(gencom.promoted_inst_ext_dict.items()): 621 f.write(gencom.indent(1) + 'std::make_pair("' + key + '", ' + value + '),\n') 622 623 f.write("""\ 624 // clang-format on 625}; 626 627std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name) { 628 auto begin = std::cbegin(g_promoted_instance_extensions); 629 auto end = std::cend(g_promoted_instance_extensions); 630 auto iter = 631 std::lower_bound(begin, end, name, 632 [](const std::pair<const char*, uint32_t>& e, 633 const char* n) { return strcmp(e.first, n) < 0; }); 634 return (iter < end && strcmp(iter->first, name) == 0) 635 ? std::optional<uint32_t>(iter->second) 636 : std::nullopt; 637} 638 639uint32_t CountPromotedInstanceExtensions(uint32_t begin_version, 640 uint32_t end_version) { 641 auto begin = std::cbegin(g_promoted_instance_extensions); 642 auto end = std::cend(g_promoted_instance_extensions); 643 uint32_t count = 0; 644 645 for (auto iter = begin; iter != end; iter++) 646 if (iter->second > begin_version && iter->second <= end_version) 647 count++; 648 649 return count; 650} 651 652std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version, 653 uint32_t end_version) { 654 auto begin = std::cbegin(g_promoted_instance_extensions); 655 auto end = std::cend(g_promoted_instance_extensions); 656 std::vector<const char*> extensions; 657 658 for (auto iter = begin; iter != end; iter++) 659 if (iter->second > begin_version && iter->second <= end_version) 660 extensions.emplace_back(iter->first); 661 662 return extensions; 663} 664 665} // namespace driver 666} // namespace vulkan\n""") 667 668 f.close() 669 gencom.run_clang_format(genfile) 670