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