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