1#!/usr/bin/python3 2# 3# Copyright 2013-2023 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import argparse 8import os 9import pdb 10import re 11import sys 12import copy 13import time 14import xml.etree.ElementTree as etree 15 16sys.path.append(os.path.abspath(os.path.dirname(__file__))) 17 18from cgenerator import CGeneratorOptions, COutputGenerator 19# Vulkan SC modules 20from json_parser import JSONParserGenerator, JSONParserOptions 21from schema_generator import SchemaGeneratorOptions, SchemaOutputGenerator 22from json_generator import JSONGeneratorOptions, JSONOutputGenerator 23from json_h_generator import JSONHeaderOutputGenerator, JSONHeaderGeneratorOptions 24from json_c_generator import JSONCOutputGenerator, JSONCGeneratorOptions 25 26from docgenerator import DocGeneratorOptions, DocOutputGenerator 27from extensionmetadocgenerator import (ExtensionMetaDocGeneratorOptions, 28 ExtensionMetaDocOutputGenerator) 29from interfacedocgenerator import InterfaceDocGenerator 30from generator import write 31from spirvcapgenerator import SpirvCapabilityOutputGenerator 32from hostsyncgenerator import HostSynchronizationOutputGenerator 33from formatsgenerator import FormatsOutputGenerator 34from syncgenerator import SyncOutputGenerator 35from jsgenerator import JSOutputGenerator 36from pygenerator import PyOutputGenerator 37from rubygenerator import RubyOutputGenerator 38from reflib import logDiag, logWarn, logErr, setLogFile 39from reg import Registry 40from validitygenerator import ValidityOutputGenerator 41from apiconventions import APIConventions 42 43# gfxstream + cereal modules 44from cerealgenerator import CerealGenerator 45 46# Simple timer functions 47startTime = None 48from typing import Optional 49 50def startTimer(timeit): 51 global startTime 52 if timeit: 53 startTime = time.process_time() 54 55 56def endTimer(timeit, msg): 57 global startTime 58 if timeit and startTime is not None: 59 endTime = time.process_time() 60 logDiag(msg, endTime - startTime) 61 startTime = None 62 63 64def makeREstring(strings, default=None, strings_are_regex=False): 65 """Turn a list of strings into a regexp string matching exactly those strings.""" 66 if strings or default is None: 67 if not strings_are_regex: 68 strings = (re.escape(s) for s in strings) 69 return '^(' + '|'.join(strings) + ')$' 70 return default 71 72 73def makeGenOpts(args): 74 """Returns a directory of [ generator function, generator options ] indexed 75 by specified short names. The generator options incorporate the following 76 parameters: 77 78 args is an parsed argument object; see below for the fields that are used.""" 79 global genOpts 80 genOpts = {} 81 82 # Default class of extensions to include, or None 83 defaultExtensions = args.defaultExtensions 84 85 # Additional extensions to include (list of extensions) 86 extensions = args.extension 87 88 # Extensions to remove (list of extensions) 89 removeExtensions = args.removeExtensions 90 91 # Extensions to emit (list of extensions) 92 emitExtensions = args.emitExtensions 93 94 # SPIR-V capabilities / features to emit (list of extensions & capabilities) 95 emitSpirv = args.emitSpirv 96 97 # Vulkan Formats to emit 98 emitFormats = args.emitFormats 99 100 # Features to include (list of features) 101 features = args.feature 102 103 # Whether to disable inclusion protect in headers 104 protect = args.protect 105 106 # Output target directory 107 directory = args.directory 108 109 # Path to generated files, particularly apimap.py 110 genpath = args.genpath 111 112 # Generate MISRA C-friendly headers 113 misracstyle = args.misracstyle; 114 115 # Generate MISRA C++-friendly headers 116 misracppstyle = args.misracppstyle; 117 118 # Descriptive names for various regexp patterns used to select 119 # versions and extensions 120 allFormats = allSpirv = allFeatures = allExtensions = r'.*' 121 122 # Turn lists of names/patterns into matching regular expressions 123 addExtensionsPat = makeREstring(extensions, None) 124 removeExtensionsPat = makeREstring(removeExtensions, None) 125 emitExtensionsPat = makeREstring(emitExtensions, allExtensions) 126 emitSpirvPat = makeREstring(emitSpirv, allSpirv) 127 emitFormatsPat = makeREstring(emitFormats, allFormats) 128 featuresPat = makeREstring(features, allFeatures) 129 130 # Copyright text prefixing all headers (list of strings). 131 # The SPDX formatting below works around constraints of the 'reuse' tool 132 prefixStrings = [ 133 '/*', 134 '** Copyright 2015-2023 The Khronos Group Inc.', 135 '**', 136 '** SPDX-License-Identifier' + ': Apache-2.0', 137 '*/', 138 '' 139 ] 140 141 # Text specific to Vulkan headers 142 vkPrefixStrings = [ 143 '/*', 144 '** This header is generated from the Khronos Vulkan XML API Registry.', 145 '**', 146 '*/', 147 '' 148 ] 149 150 vulkanLayer = args.vulkanLayer 151 152 # Defaults for generating re-inclusion protection wrappers (or not) 153 protectFile = protect 154 155 # An API style conventions object 156 conventions = APIConventions() 157 158 if args.apiname is not None: 159 defaultAPIName = args.apiname 160 else: 161 defaultAPIName = conventions.xml_api_name 162 163 # APIs to merge 164 mergeApiNames = args.mergeApiNames 165 166 isCTS = args.isCTS 167 168 # API include files for spec and ref pages 169 # Overwrites include subdirectories in spec source tree 170 # The generated include files do not include the calling convention 171 # macros (apientry etc.), unlike the header files. 172 # Because the 1.0 core branch includes ref pages for extensions, 173 # all the extension interfaces need to be generated, even though 174 # none are used by the core spec itself. 175 genOpts['apiinc'] = [ 176 DocOutputGenerator, 177 DocGeneratorOptions( 178 conventions = conventions, 179 filename = 'timeMarker', 180 directory = directory, 181 genpath = genpath, 182 apiname = defaultAPIName, 183 profile = None, 184 versions = featuresPat, 185 emitversions = featuresPat, 186 defaultExtensions = None, 187 addExtensions = addExtensionsPat, 188 removeExtensions = removeExtensionsPat, 189 emitExtensions = emitExtensionsPat, 190 prefixText = prefixStrings + vkPrefixStrings, 191 apicall = '', 192 apientry = '', 193 apientryp = '*', 194 alignFuncParam = 48, 195 expandEnumerants = False) 196 ] 197 198 # JavaScript, Python, and Ruby representations of API information, used 199 # by scripts that do not need to load the full XML. 200 genOpts['apimap.cjs'] = [ 201 JSOutputGenerator, 202 DocGeneratorOptions( 203 conventions = conventions, 204 filename = 'apimap.cjs', 205 directory = directory, 206 genpath = None, 207 apiname = defaultAPIName, 208 profile = None, 209 versions = featuresPat, 210 emitversions = featuresPat, 211 defaultExtensions = None, 212 addExtensions = addExtensionsPat, 213 removeExtensions = removeExtensionsPat, 214 emitExtensions = emitExtensionsPat, 215 reparentEnums = False) 216 ] 217 218 genOpts['apimap.py'] = [ 219 PyOutputGenerator, 220 DocGeneratorOptions( 221 conventions = conventions, 222 filename = 'apimap.py', 223 directory = directory, 224 genpath = None, 225 apiname = defaultAPIName, 226 profile = None, 227 versions = featuresPat, 228 emitversions = featuresPat, 229 defaultExtensions = None, 230 addExtensions = addExtensionsPat, 231 removeExtensions = removeExtensionsPat, 232 emitExtensions = emitExtensionsPat, 233 reparentEnums = False) 234 ] 235 236 genOpts['apimap.rb'] = [ 237 RubyOutputGenerator, 238 DocGeneratorOptions( 239 conventions = conventions, 240 filename = 'apimap.rb', 241 directory = directory, 242 genpath = None, 243 apiname = defaultAPIName, 244 profile = None, 245 versions = featuresPat, 246 emitversions = featuresPat, 247 defaultExtensions = None, 248 addExtensions = addExtensionsPat, 249 removeExtensions = removeExtensionsPat, 250 emitExtensions = emitExtensionsPat, 251 reparentEnums = False) 252 ] 253 254 255 # API validity files for spec 256 # 257 # requireCommandAliases is set to True because we need validity files 258 # for the command something is promoted to even when the promoted-to 259 # feature is not included. This avoids wordy includes of validity files. 260 genOpts['validinc'] = [ 261 ValidityOutputGenerator, 262 DocGeneratorOptions( 263 conventions = conventions, 264 filename = 'timeMarker', 265 directory = directory, 266 genpath = None, 267 apiname = defaultAPIName, 268 profile = None, 269 versions = featuresPat, 270 emitversions = featuresPat, 271 defaultExtensions = None, 272 addExtensions = addExtensionsPat, 273 removeExtensions = removeExtensionsPat, 274 emitExtensions = emitExtensionsPat, 275 requireCommandAliases = True, 276 ) 277 ] 278 279 # API host sync table files for spec 280 genOpts['hostsyncinc'] = [ 281 HostSynchronizationOutputGenerator, 282 DocGeneratorOptions( 283 conventions = conventions, 284 filename = 'timeMarker', 285 directory = directory, 286 genpath = None, 287 apiname = defaultAPIName, 288 profile = None, 289 versions = featuresPat, 290 emitversions = featuresPat, 291 defaultExtensions = None, 292 addExtensions = addExtensionsPat, 293 removeExtensions = removeExtensionsPat, 294 emitExtensions = emitExtensionsPat, 295 reparentEnums = False) 296 ] 297 298 # Extension metainformation for spec extension appendices 299 # Includes all extensions by default, but only so that the generated 300 # 'promoted_extensions_*' files refer to all extensions that were 301 # promoted to a core version. 302 genOpts['extinc'] = [ 303 ExtensionMetaDocOutputGenerator, 304 ExtensionMetaDocGeneratorOptions( 305 conventions = conventions, 306 filename = 'timeMarker', 307 directory = directory, 308 genpath = None, 309 apiname = defaultAPIName, 310 profile = None, 311 versions = featuresPat, 312 emitversions = None, 313 defaultExtensions = defaultExtensions, 314 addExtensions = addExtensionsPat, 315 removeExtensions = None, 316 emitExtensions = emitExtensionsPat) 317 ] 318 319 # Version and extension interface docs for version/extension appendices 320 # Includes all extensions by default. 321 genOpts['interfaceinc'] = [ 322 InterfaceDocGenerator, 323 DocGeneratorOptions( 324 conventions = conventions, 325 filename = 'timeMarker', 326 directory = directory, 327 genpath = None, 328 apiname = defaultAPIName, 329 profile = None, 330 versions = featuresPat, 331 emitversions = featuresPat, 332 defaultExtensions = None, 333 addExtensions = addExtensionsPat, 334 removeExtensions = removeExtensionsPat, 335 emitExtensions = emitExtensionsPat, 336 reparentEnums = False) 337 ] 338 339 genOpts['spirvcapinc'] = [ 340 SpirvCapabilityOutputGenerator, 341 DocGeneratorOptions( 342 conventions = conventions, 343 filename = 'timeMarker', 344 directory = directory, 345 genpath = None, 346 apiname = defaultAPIName, 347 profile = None, 348 versions = featuresPat, 349 emitversions = featuresPat, 350 defaultExtensions = None, 351 addExtensions = addExtensionsPat, 352 removeExtensions = removeExtensionsPat, 353 emitExtensions = emitExtensionsPat, 354 emitSpirv = emitSpirvPat, 355 reparentEnums = False) 356 ] 357 358 # Used to generate various format chapter tables 359 genOpts['formatsinc'] = [ 360 FormatsOutputGenerator, 361 DocGeneratorOptions( 362 conventions = conventions, 363 filename = 'timeMarker', 364 directory = directory, 365 genpath = None, 366 apiname = defaultAPIName, 367 profile = None, 368 versions = featuresPat, 369 emitversions = featuresPat, 370 defaultExtensions = None, 371 addExtensions = addExtensionsPat, 372 removeExtensions = removeExtensionsPat, 373 emitExtensions = emitExtensionsPat, 374 emitFormats = emitFormatsPat, 375 reparentEnums = False) 376 ] 377 378 # Used to generate various synchronization chapter tables 379 genOpts['syncinc'] = [ 380 SyncOutputGenerator, 381 DocGeneratorOptions( 382 conventions = conventions, 383 filename = 'timeMarker', 384 directory = directory, 385 genpath = None, 386 apiname = defaultAPIName, 387 profile = None, 388 versions = featuresPat, 389 emitversions = featuresPat, 390 defaultExtensions = None, 391 addExtensions = addExtensionsPat, 392 removeExtensions = removeExtensionsPat, 393 emitExtensions = emitExtensionsPat, 394 reparentEnums = False) 395 ] 396 397 # Platform extensions, in their own header files 398 # Each element of the platforms[] array defines information for 399 # generating a single platform: 400 # [0] is the generated header file name 401 # [1] is the set of platform extensions to generate 402 # [2] is additional extensions whose interfaces should be considered, 403 # but suppressed in the output, to avoid duplicate definitions of 404 # dependent types like VkDisplayKHR and VkSurfaceKHR which come from 405 # non-platform extensions. 406 407 # Track all platform extensions, for exclusion from vulkan_core.h 408 allPlatformExtensions = [] 409 410 # Extensions suppressed for all WSI platforms (WSI extensions required 411 # by all platforms) 412 commonSuppressExtensions = [ 'VK_KHR_display', 'VK_KHR_swapchain' ] 413 414 # Extensions required and suppressed for beta "platform". This can 415 # probably eventually be derived from the requires= attributes of 416 # the extension blocks. 417 betaRequireExtensions = [ 418 'VK_KHR_portability_subset', 419 'VK_KHR_video_encode_queue', 420 'VK_EXT_video_encode_h264', 421 'VK_EXT_video_encode_h265', 422 'VK_NV_displacement_micromap', 423 'VK_AMDX_shader_enqueue', 424 ] 425 426 betaSuppressExtensions = [ 427 'VK_KHR_video_queue', 428 'VK_EXT_opacity_micromap', 429 'VK_KHR_pipeline_library', 430 ] 431 432 platforms = [ 433 [ 'vulkan_android.h', [ 'VK_KHR_android_surface', 434 'VK_ANDROID_external_memory_android_hardware_buffer', 435 'VK_ANDROID_external_format_resolve' 436 ], commonSuppressExtensions + 437 [ 'VK_KHR_format_feature_flags2', 438 ] ], 439 [ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface', 440 'VK_FUCHSIA_external_memory', 441 'VK_FUCHSIA_external_semaphore', 442 'VK_FUCHSIA_buffer_collection' ], commonSuppressExtensions ], 443 [ 'vulkan_ggp.h', [ 'VK_GGP_stream_descriptor_surface', 444 'VK_GGP_frame_token' ], commonSuppressExtensions ], 445 [ 'vulkan_ios.h', [ 'VK_MVK_ios_surface' ], commonSuppressExtensions ], 446 [ 'vulkan_macos.h', [ 'VK_MVK_macos_surface' ], commonSuppressExtensions ], 447 [ 'vulkan_vi.h', [ 'VK_NN_vi_surface' ], commonSuppressExtensions ], 448 [ 'vulkan_wayland.h', [ 'VK_KHR_wayland_surface' ], commonSuppressExtensions ], 449 [ 'vulkan_win32.h', [ 'VK_.*_win32(|_.*)', 'VK_.*_winrt(|_.*)', 'VK_EXT_full_screen_exclusive' ], 450 commonSuppressExtensions + 451 [ 'VK_KHR_external_semaphore', 452 'VK_KHR_external_memory_capabilities', 453 'VK_KHR_external_fence', 454 'VK_KHR_external_fence_capabilities', 455 'VK_KHR_get_surface_capabilities2', 456 'VK_NV_external_memory_capabilities', 457 ] ], 458 [ 'vulkan_xcb.h', [ 'VK_KHR_xcb_surface' ], commonSuppressExtensions ], 459 [ 'vulkan_xlib.h', [ 'VK_KHR_xlib_surface' ], commonSuppressExtensions ], 460 [ 'vulkan_directfb.h', [ 'VK_EXT_directfb_surface' ], commonSuppressExtensions ], 461 [ 'vulkan_xlib_xrandr.h', [ 'VK_EXT_acquire_xlib_display' ], commonSuppressExtensions ], 462 [ 'vulkan_metal.h', [ 'VK_EXT_metal_surface', 463 'VK_EXT_metal_objects' ], commonSuppressExtensions ], 464 [ 'vulkan_screen.h', [ 'VK_QNX_screen_surface', 465 'VK_QNX_external_memory_screen_buffer' ], commonSuppressExtensions ], 466 [ 'vulkan_sci.h', [ 'VK_NV_external_sci_sync', 467 'VK_NV_external_sci_sync2', 468 'VK_NV_external_memory_sci_buf'], commonSuppressExtensions ], 469 [ 'vulkan_beta.h', betaRequireExtensions, betaSuppressExtensions ], 470 ] 471 472 for platform in platforms: 473 headername = platform[0] 474 475 allPlatformExtensions += platform[1] 476 477 addPlatformExtensionsRE = makeREstring( 478 platform[1] + platform[2], strings_are_regex=True) 479 emitPlatformExtensionsRE = makeREstring( 480 platform[1], strings_are_regex=True) 481 482 opts = CGeneratorOptions( 483 conventions = conventions, 484 filename = headername, 485 directory = directory, 486 genpath = None, 487 apiname = defaultAPIName, 488 mergeApiNames = mergeApiNames, 489 profile = None, 490 versions = featuresPat, 491 emitversions = None, 492 defaultExtensions = None, 493 addExtensions = addPlatformExtensionsRE, 494 removeExtensions = None, 495 emitExtensions = emitPlatformExtensionsRE, 496 prefixText = prefixStrings + vkPrefixStrings, 497 genFuncPointers = True, 498 protectFile = protectFile, 499 protectFeature = False, 500 protectProto = '#ifndef', 501 protectProtoStr = 'VK_NO_PROTOTYPES', 502 apicall = 'VKAPI_ATTR ', 503 apientry = 'VKAPI_CALL ', 504 apientryp = 'VKAPI_PTR *', 505 alignFuncParam = 48, 506 misracstyle = misracstyle, 507 misracppstyle = misracppstyle) 508 509 genOpts[headername] = [ COutputGenerator, opts ] 510 511 # Header for core API + extensions. 512 # To generate just the core API, 513 # change to 'defaultExtensions = None' below. 514 # 515 # By default this adds all enabled, non-platform extensions. 516 # It removes all platform extensions (from the platform headers options 517 # constructed above) as well as any explicitly specified removals. 518 519 removeExtensionsPat = makeREstring( 520 allPlatformExtensions + removeExtensions, None, strings_are_regex=True) 521 522 genOpts['vulkan_core.h'] = [ 523 COutputGenerator, 524 CGeneratorOptions( 525 conventions = conventions, 526 filename = 'vulkan_core.h', 527 directory = directory, 528 genpath = None, 529 apiname = defaultAPIName, 530 mergeApiNames = mergeApiNames, 531 profile = None, 532 versions = featuresPat, 533 emitversions = featuresPat, 534 defaultExtensions = defaultExtensions, 535 addExtensions = addExtensionsPat, 536 removeExtensions = removeExtensionsPat, 537 emitExtensions = emitExtensionsPat, 538 prefixText = prefixStrings + vkPrefixStrings, 539 genFuncPointers = True, 540 protectFile = protectFile, 541 protectFeature = False, 542 protectProto = '#ifndef', 543 protectProtoStr = 'VK_NO_PROTOTYPES', 544 apicall = 'VKAPI_ATTR ', 545 apientry = 'VKAPI_CALL ', 546 apientryp = 'VKAPI_PTR *', 547 alignFuncParam = 48, 548 misracstyle = misracstyle, 549 misracppstyle = misracppstyle) 550 ] 551 552 # Vulkan versions to include for SC header - SC *removes* features from 1.0/1.1/1.2 553 scVersions = makeREstring(['VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2', 'VKSC_VERSION_1_0']) 554 555 genOpts['vulkan_sc_core.h'] = [ 556 COutputGenerator, 557 CGeneratorOptions( 558 conventions = conventions, 559 filename = 'vulkan_sc_core.h', 560 directory = directory, 561 apiname = 'vulkansc', 562 profile = None, 563 versions = scVersions, 564 emitversions = scVersions, 565 defaultExtensions = 'vulkansc', 566 addExtensions = addExtensionsPat, 567 removeExtensions = removeExtensionsPat, 568 emitExtensions = emitExtensionsPat, 569 prefixText = prefixStrings + vkPrefixStrings, 570 genFuncPointers = True, 571 protectFile = protectFile, 572 protectFeature = False, 573 protectProto = '#ifndef', 574 protectProtoStr = 'VK_NO_PROTOTYPES', 575 apicall = 'VKAPI_ATTR ', 576 apientry = 'VKAPI_CALL ', 577 apientryp = 'VKAPI_PTR *', 578 alignFuncParam = 48, 579 misracstyle = misracstyle, 580 misracppstyle = misracppstyle) 581 ] 582 583 genOpts['vulkan_sc_core.hpp'] = [ 584 COutputGenerator, 585 CGeneratorOptions( 586 conventions = conventions, 587 filename = 'vulkan_sc_core.hpp', 588 directory = directory, 589 apiname = 'vulkansc', 590 profile = None, 591 versions = scVersions, 592 emitversions = scVersions, 593 defaultExtensions = 'vulkansc', 594 addExtensions = addExtensionsPat, 595 removeExtensions = removeExtensionsPat, 596 emitExtensions = emitExtensionsPat, 597 prefixText = prefixStrings + vkPrefixStrings, 598 genFuncPointers = True, 599 protectFile = protectFile, 600 protectFeature = False, 601 protectProto = '#ifndef', 602 protectProtoStr = 'VK_NO_PROTOTYPES', 603 apicall = 'VKAPI_ATTR ', 604 apientry = 'VKAPI_CALL ', 605 apientryp = 'VKAPI_PTR *', 606 alignFuncParam = 48, 607 misracstyle = misracstyle, 608 misracppstyle = misracppstyle) 609 ] 610 611 genOpts['vk.json'] = [ 612 SchemaOutputGenerator, 613 SchemaGeneratorOptions( 614 conventions = conventions, 615 filename = 'vk.json', 616 directory = directory, 617 apiname = 'vulkansc', 618 profile = None, 619 versions = scVersions, 620 emitversions = scVersions, 621 defaultExtensions = 'vulkansc', 622 addExtensions = addExtensionsPat, 623 removeExtensions = removeExtensionsPat, 624 emitExtensions = emitExtensionsPat, 625 prefixText = prefixStrings + vkPrefixStrings, 626 genFuncPointers = True, 627 protectFile = protectFile, 628 protectFeature = False, 629 protectProto = '#ifndef', 630 protectProtoStr = 'VK_NO_PROTOTYPES', 631 apicall = 'VKAPI_ATTR ', 632 apientry = 'VKAPI_CALL ', 633 apientryp = 'VKAPI_PTR *', 634 alignFuncParam = 48) 635 ] 636 637 if vulkanLayer: 638 genOpts['vulkan_json_data.hpp'] = [ 639 JSONOutputGenerator, 640 JSONGeneratorOptions( 641 conventions = conventions, 642 filename = 'vulkan_json_data.hpp', 643 directory = directory, 644 apiname = 'vulkan', 645 profile = None, 646 versions = featuresPat, 647 emitversions = featuresPat, 648 defaultExtensions = None, 649 addExtensions = addExtensionsPat, 650 removeExtensions = None, 651 emitExtensions = None, 652 vulkanLayer = vulkanLayer, 653 prefixText = prefixStrings + vkPrefixStrings, 654 genFuncPointers = True, 655 protectFile = protectFile, 656 protectFeature = False, 657 protectProto = '#ifndef', 658 protectProtoStr = 'VK_NO_PROTOTYPES', 659 apicall = 'VKAPI_ATTR ', 660 apientry = 'VKAPI_CALL ', 661 apientryp = 'VKAPI_PTR *', 662 alignFuncParam = 48) 663 ] 664 else: 665 genOpts['vulkan_json_data.hpp'] = [ 666 JSONOutputGenerator, 667 JSONGeneratorOptions( 668 conventions = conventions, 669 filename = 'vulkan_json_data.hpp', 670 directory = directory, 671 apiname = 'vulkansc', 672 profile = None, 673 versions = scVersions, 674 emitversions = scVersions, 675 defaultExtensions = 'vulkansc', 676 addExtensions = addExtensionsPat, 677 removeExtensions = removeExtensionsPat, 678 emitExtensions = emitExtensionsPat, 679 vulkanLayer = vulkanLayer, 680 prefixText = prefixStrings + vkPrefixStrings, 681 genFuncPointers = True, 682 protectFile = protectFile, 683 protectFeature = False, 684 protectProto = '#ifndef', 685 protectProtoStr = 'VK_NO_PROTOTYPES', 686 apicall = 'VKAPI_ATTR ', 687 apientry = 'VKAPI_CALL ', 688 apientryp = 'VKAPI_PTR *', 689 isCTS = isCTS, 690 alignFuncParam = 48) 691 ] 692 693 # keep any relevant platform extensions for the following generators 694 # (needed for e.g. the vulkan_sci extensions) 695 explicitRemoveExtensionsPat = makeREstring( 696 removeExtensions, None, strings_are_regex=True) 697 698 # Raw C header file generator. 699 genOpts['vulkan_json_gen.h'] = [ 700 JSONHeaderOutputGenerator, 701 JSONHeaderGeneratorOptions( 702 conventions = conventions, 703 filename = 'vulkan_json_gen.h', 704 directory = directory, 705 apiname = 'vulkansc', 706 profile = None, 707 versions = scVersions, 708 emitversions = scVersions, 709 defaultExtensions = 'vulkansc', 710 addExtensions = addExtensionsPat, 711 removeExtensions = explicitRemoveExtensionsPat, 712 emitExtensions = emitExtensionsPat, 713 prefixText = prefixStrings + vkPrefixStrings, 714 genFuncPointers = True, 715 protectFile = protectFile, 716 protectFeature = False, 717 protectProto = '#ifndef', 718 protectProtoStr = 'VK_NO_PROTOTYPES', 719 apicall = 'VKAPI_ATTR ', 720 apientry = 'VKAPI_CALL ', 721 apientryp = 'VKAPI_PTR *', 722 alignFuncParam = 48) 723 ] 724 725 # Raw C source file generator. 726 genOpts['vulkan_json_gen.c'] = [ 727 JSONCOutputGenerator, 728 JSONCGeneratorOptions( 729 conventions = conventions, 730 filename = 'vulkan_json_gen.c', 731 directory = directory, 732 apiname = 'vulkansc', 733 profile = None, 734 versions = scVersions, 735 emitversions = scVersions, 736 defaultExtensions = 'vulkansc', 737 addExtensions = addExtensionsPat, 738 removeExtensions = explicitRemoveExtensionsPat, 739 emitExtensions = emitExtensionsPat, 740 prefixText = prefixStrings + vkPrefixStrings, 741 genFuncPointers = True, 742 protectFile = protectFile, 743 protectFeature = False, 744 protectProto = '#ifndef', 745 protectProtoStr = 'VK_NO_PROTOTYPES', 746 apicall = 'VKAPI_ATTR ', 747 apientry = 'VKAPI_CALL ', 748 apientryp = 'VKAPI_PTR *', 749 alignFuncParam = 48) 750 ] 751 752 genOpts['vulkan_json_parser.hpp'] = [ 753 JSONParserGenerator, 754 JSONParserOptions( 755 conventions = conventions, 756 filename = 'vulkan_json_parser.hpp', 757 directory = directory, 758 apiname = 'vulkansc', 759 profile = None, 760 versions = scVersions, 761 emitversions = scVersions, 762 defaultExtensions = 'vulkansc', 763 addExtensions = addExtensionsPat, 764 removeExtensions = explicitRemoveExtensionsPat, 765 emitExtensions = emitExtensionsPat, 766 prefixText = prefixStrings + vkPrefixStrings, 767 genFuncPointers = True, 768 protectFile = protectFile, 769 protectFeature = False, 770 protectProto = '#ifndef', 771 protectProtoStr = 'VK_NO_PROTOTYPES', 772 apicall = 'VKAPI_ATTR ', 773 apientry = 'VKAPI_CALL ', 774 apientryp = 'VKAPI_PTR *', 775 isCTS = isCTS, 776 alignFuncParam = 48) 777 ] 778 779 # Unused - vulkan10.h target. 780 # It is possible to generate a header with just the Vulkan 1.0 + 781 # extension interfaces defined, but since the promoted KHR extensions 782 # are now defined in terms of the 1.1 interfaces, such a header is very 783 # similar to vulkan_core.h. 784 genOpts['vulkan10.h'] = [ 785 COutputGenerator, 786 CGeneratorOptions( 787 conventions = conventions, 788 filename = 'vulkan10.h', 789 directory = directory, 790 genpath = None, 791 apiname = defaultAPIName, 792 profile = None, 793 versions = 'VK_VERSION_1_0', 794 emitversions = 'VK_VERSION_1_0', 795 defaultExtensions = None, 796 addExtensions = None, 797 removeExtensions = None, 798 emitExtensions = None, 799 prefixText = prefixStrings + vkPrefixStrings, 800 genFuncPointers = True, 801 protectFile = protectFile, 802 protectFeature = False, 803 protectProto = '#ifndef', 804 protectProtoStr = 'VK_NO_PROTOTYPES', 805 apicall = 'VKAPI_ATTR ', 806 apientry = 'VKAPI_CALL ', 807 apientryp = 'VKAPI_PTR *', 808 alignFuncParam = 48, 809 misracstyle = misracstyle, 810 misracppstyle = misracppstyle) 811 ] 812 813 # Video header target - combines all video extension dependencies into a 814 # single header, at present. 815 genOpts['vk_video.h'] = [ 816 COutputGenerator, 817 CGeneratorOptions( 818 conventions = conventions, 819 filename = 'vk_video.h', 820 directory = directory, 821 genpath = None, 822 apiname = 'vulkan', 823 profile = None, 824 versions = None, 825 emitversions = None, 826 defaultExtensions = defaultExtensions, 827 addExtensions = addExtensionsPat, 828 removeExtensions = removeExtensionsPat, 829 emitExtensions = emitExtensionsPat, 830 prefixText = prefixStrings + vkPrefixStrings, 831 genFuncPointers = True, 832 protectFile = protectFile, 833 protectFeature = False, 834 protectProto = '#ifndef', 835 protectProtoStr = 'VK_NO_PROTOTYPES', 836 apicall = '', 837 apientry = '', 838 apientryp = '', 839 alignFuncParam = 48, 840 misracstyle = misracstyle, 841 misracppstyle = misracppstyle) 842 ] 843 844 # Video extension 'Std' interfaces, each in its own header files 845 # These are not Vulkan extensions, or a part of the Vulkan API at all. 846 # They are treated in a similar fashion for generation purposes, but 847 # all required APIs for each interface must be explicitly required. 848 # 849 # Each element of the videoStd[] array is an extension name defining an 850 # interface, and is also the basis for the generated header file name. 851 852 videoStd = [ 853 'vulkan_video_codecs_common', 854 'vulkan_video_codec_h264std', 855 'vulkan_video_codec_h264std_decode', 856 'vulkan_video_codec_h264std_encode', 857 'vulkan_video_codec_h265std', 858 'vulkan_video_codec_h265std_decode', 859 'vulkan_video_codec_h265std_encode', 860 ] 861 862 # Unused at present 863 # addExtensionRE = makeREstring(videoStd) 864 for codec in videoStd: 865 headername = f'{codec}.h' 866 867 # Consider all of the codecs 'extensions', but only emit this one 868 emitExtensionRE = makeREstring([codec]) 869 870 opts = CGeneratorOptions( 871 conventions = conventions, 872 filename = headername, 873 directory = directory, 874 genpath = None, 875 apiname = defaultAPIName, 876 mergeApiNames = mergeApiNames, 877 profile = None, 878 versions = None, 879 emitversions = None, 880 defaultExtensions = None, 881 addExtensions = emitExtensionRE, 882 removeExtensions = None, 883 emitExtensions = emitExtensionRE, 884 requireDepends = False, 885 prefixText = prefixStrings + vkPrefixStrings, 886 genFuncPointers = False, 887 protectFile = protectFile, 888 protectFeature = False, 889 alignFuncParam = 48, 890 ) 891 892 genOpts[headername] = [ COutputGenerator, opts ] 893 894 # Unused - vulkan11.h target. 895 # It is possible to generate a header with just the Vulkan 1.0 + 896 # extension interfaces defined, but since the promoted KHR extensions 897 # are now defined in terms of the 1.1 interfaces, such a header is very 898 # similar to vulkan_core.h. 899 genOpts['vulkan11.h'] = [ 900 COutputGenerator, 901 CGeneratorOptions( 902 conventions = conventions, 903 filename = 'vulkan11.h', 904 directory = directory, 905 genpath = None, 906 apiname = defaultAPIName, 907 profile = None, 908 versions = '^VK_VERSION_1_[01]$', 909 emitversions = '^VK_VERSION_1_[01]$', 910 defaultExtensions = None, 911 addExtensions = None, 912 removeExtensions = None, 913 emitExtensions = None, 914 prefixText = prefixStrings + vkPrefixStrings, 915 genFuncPointers = True, 916 protectFile = protectFile, 917 protectFeature = False, 918 protectProto = '#ifndef', 919 protectProtoStr = 'VK_NO_PROTOTYPES', 920 apicall = 'VKAPI_ATTR ', 921 apientry = 'VKAPI_CALL ', 922 apientryp = 'VKAPI_PTR *', 923 alignFuncParam = 48, 924 misracstyle = misracstyle, 925 misracppstyle = misracppstyle) 926 ] 927 928 genOpts['alias.h'] = [ 929 COutputGenerator, 930 CGeneratorOptions( 931 conventions = conventions, 932 filename = 'alias.h', 933 directory = directory, 934 genpath = None, 935 apiname = defaultAPIName, 936 profile = None, 937 versions = featuresPat, 938 emitversions = featuresPat, 939 defaultExtensions = defaultExtensions, 940 addExtensions = None, 941 removeExtensions = removeExtensionsPat, 942 emitExtensions = emitExtensionsPat, 943 prefixText = None, 944 genFuncPointers = False, 945 protectFile = False, 946 protectFeature = False, 947 protectProto = '', 948 protectProtoStr = '', 949 apicall = '', 950 apientry = '', 951 apientryp = '', 952 alignFuncParam = 36) 953 ] 954 955 # Serializer for spec 956 genOpts['cereal'] = [ 957 CerealGenerator, 958 CGeneratorOptions( 959 conventions = conventions, 960 directory = directory, 961 apiname = 'vulkan', 962 profile = None, 963 versions = featuresPat, 964 emitversions = featuresPat, 965 defaultExtensions = defaultExtensions, 966 addExtensions = None, 967 removeExtensions = None, 968 emitExtensions = emitExtensionsPat, 969 prefixText = prefixStrings + vkPrefixStrings, 970 genFuncPointers = True, 971 protectFile = protectFile, 972 protectFeature = False, 973 protectProto = '#ifndef', 974 protectProtoStr = 'VK_NO_PROTOTYPES', 975 apicall = 'VKAPI_ATTR ', 976 apientry = 'VKAPI_CALL ', 977 apientryp = 'VKAPI_PTR *', 978 alignFuncParam = 48) 979 ] 980 981 gfxstreamPrefixStrings = [ 982 '#pragma once', 983 '#ifdef VK_GFXSTREAM_STRUCTURE_TYPE_EXT', 984 '#include "vulkan_gfxstream_structure_type.h"', 985 '#endif', 986 ] 987 988 # gfxstream specific header 989 genOpts['vulkan_gfxstream.h'] = [ 990 COutputGenerator, 991 CGeneratorOptions( 992 conventions = conventions, 993 filename = 'vulkan_gfxstream.h', 994 directory = directory, 995 genpath = None, 996 apiname = 'vulkan', 997 profile = None, 998 versions = featuresPat, 999 emitversions = None, 1000 defaultExtensions = None, 1001 addExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None), 1002 removeExtensions = None, 1003 emitExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None), 1004 prefixText = prefixStrings + vkPrefixStrings + gfxstreamPrefixStrings, 1005 genFuncPointers = True, 1006 # Use #pragma once in the prefixText instead, so that we can put the copyright comments 1007 # at the beginning of the file. 1008 protectFile = False, 1009 protectFeature = False, 1010 protectProto = '#ifndef', 1011 protectProtoStr = 'VK_NO_PROTOTYPES', 1012 apicall = 'VKAPI_ATTR ', 1013 apientry = 'VKAPI_CALL ', 1014 apientryp = 'VKAPI_PTR *', 1015 alignFuncParam = 48, 1016 misracstyle = misracstyle, 1017 misracppstyle = misracppstyle) 1018 ] 1019 1020def genTarget(args): 1021 """Create an API generator and corresponding generator options based on 1022 the requested target and command line options. 1023 1024 This is encapsulated in a function so it can be profiled and/or timed. 1025 The args parameter is an parsed argument object containing the following 1026 fields that are used: 1027 1028 - target - target to generate 1029 - directory - directory to generate it in 1030 - protect - True if re-inclusion wrappers should be created 1031 - extensions - list of additional extensions to include in generated interfaces""" 1032 1033 # Create generator options with parameters specified on command line 1034 makeGenOpts(args) 1035 1036 # Select a generator matching the requested target 1037 if args.target in genOpts: 1038 createGenerator = genOpts[args.target][0] 1039 options = genOpts[args.target][1] 1040 1041 logDiag('* Building', args.target) 1042 logDiag('* options.versions =', options.versions) 1043 logDiag('* options.emitversions =', options.emitversions) 1044 logDiag('* options.defaultExtensions =', options.defaultExtensions) 1045 logDiag('* options.addExtensions =', options.addExtensions) 1046 logDiag('* options.removeExtensions =', options.removeExtensions) 1047 logDiag('* options.emitExtensions =', options.emitExtensions) 1048 logDiag('* options.emitSpirv =', options.emitSpirv) 1049 logDiag('* options.emitFormats =', options.emitFormats) 1050 1051 gen = createGenerator(errFile=errWarn, 1052 warnFile=errWarn, 1053 diagFile=diag) 1054 return (gen, options) 1055 else: 1056 logErr('No generator options for unknown target:', args.target) 1057 return None 1058 1059 1060# -feature name 1061# -extension name 1062# For both, "name" may be a single name, or a space-separated list 1063# of names, or a regular expression. 1064if __name__ == '__main__': 1065 parser = argparse.ArgumentParser() 1066 1067 parser.add_argument('-apiname', action='store', 1068 default=None, 1069 help='Specify API to generate (defaults to repository-specific conventions object value)') 1070 parser.add_argument('-mergeApiNames', action='store', 1071 default=None, 1072 help='Specify a comma separated list of APIs to merge into the target API') 1073 parser.add_argument('-defaultExtensions', action='store', 1074 default=APIConventions().xml_api_name, 1075 help='Specify a single class of extensions to add to targets') 1076 parser.add_argument('-extension', action='append', 1077 default=[], 1078 help='Specify an extension or extensions to add to targets') 1079 parser.add_argument('-removeExtensions', action='append', 1080 default=[], 1081 help='Specify an extension or extensions to remove from targets') 1082 parser.add_argument('-emitExtensions', action='append', 1083 default=[], 1084 help='Specify an extension or extensions to emit in targets') 1085 parser.add_argument('-emitSpirv', action='append', 1086 default=[], 1087 help='Specify a SPIR-V extension or capability to emit in targets') 1088 parser.add_argument('-emitFormats', action='append', 1089 default=[], 1090 help='Specify Vulkan Formats to emit in targets') 1091 parser.add_argument('-feature', action='append', 1092 default=[], 1093 help='Specify a core API feature name or names to add to targets') 1094 parser.add_argument('-debug', action='store_true', 1095 help='Enable debugging') 1096 parser.add_argument('-dump', action='store_true', 1097 help='Enable dump to stderr') 1098 parser.add_argument('-diagfile', action='store', 1099 default=None, 1100 help='Write diagnostics to specified file') 1101 parser.add_argument('-errfile', action='store', 1102 default=None, 1103 help='Write errors and warnings to specified file instead of stderr') 1104 parser.add_argument('-noprotect', dest='protect', action='store_false', 1105 help='Disable inclusion protection in output headers') 1106 parser.add_argument('-profile', action='store_true', 1107 help='Enable profiling') 1108 parser.add_argument('-registry', action='store', 1109 default='vk.xml', 1110 help='Use specified registry file instead of vk.xml') 1111 parser.add_argument('-registryGfxstream', action='store', 1112 default=None, 1113 help='Use specified gfxstream registry file') 1114 parser.add_argument('-time', action='store_true', 1115 help='Enable timing') 1116 parser.add_argument('-genpath', action='store', default='gen', 1117 help='Path to generated files') 1118 parser.add_argument('-o', action='store', dest='directory', 1119 default='.', 1120 help='Create target and related files in specified directory') 1121 parser.add_argument('target', metavar='target', nargs='?', 1122 help='Specify target') 1123 parser.add_argument('-quiet', action='store_true', default=True, 1124 help='Suppress script output during normal execution.') 1125 parser.add_argument('-verbose', action='store_false', dest='quiet', default=True, 1126 help='Enable script output during normal execution.') 1127 parser.add_argument('--vulkanLayer', action='store_true', dest='vulkanLayer', 1128 help='Enable scripts to generate VK specific vulkan_json_data.hpp for json_gen_layer.') 1129 parser.add_argument('-misracstyle', dest='misracstyle', action='store_true', 1130 help='generate MISRA C-friendly headers') 1131 parser.add_argument('-misracppstyle', dest='misracppstyle', action='store_true', 1132 help='generate MISRA C++-friendly headers') 1133 parser.add_argument('--iscts', action='store_true', dest='isCTS', 1134 help='Specify if this should generate CTS compatible code') 1135 1136 args = parser.parse_args() 1137 1138 # This splits arguments which are space-separated lists 1139 args.feature = [name for arg in args.feature for name in arg.split()] 1140 args.extension = [name for arg in args.extension for name in arg.split()] 1141 1142 # create error/warning & diagnostic files 1143 if args.errfile: 1144 errWarn = open(args.errfile, 'w', encoding='utf-8') 1145 else: 1146 errWarn = sys.stderr 1147 1148 if args.diagfile: 1149 diag = open(args.diagfile, 'w', encoding='utf-8') 1150 else: 1151 diag = None 1152 1153 if args.time: 1154 # Log diagnostics and warnings 1155 setLogFile(setDiag = True, setWarn = True, filename = '-') 1156 1157 # Create the API generator & generator options 1158 (gen, options) = genTarget(args) 1159 1160 # Create the registry object with the specified generator and generator 1161 # options. The options are set before XML loading as they may affect it. 1162 reg = Registry(gen, options) 1163 1164 # Parse the specified registry XML into an ElementTree object 1165 startTimer(args.time) 1166 tree = etree.parse(args.registry) 1167 endTimer(args.time, '* Time to make ElementTree =') 1168 1169 # Merge the gfxstream registry with the official Vulkan registry if the 1170 # target is the cereal generator 1171 if args.registryGfxstream is not None and args.target == 'cereal': 1172 treeGfxstream = etree.parse(args.registryGfxstream) 1173 treeRoot = tree.getroot() 1174 treeGfxstreamRoot = treeGfxstream.getroot() 1175 1176 def getEntryName(entry) -> Optional[str]: 1177 name = entry.get("name") 1178 if name is not None: 1179 return name 1180 try: 1181 return entry.find("proto").find("name").text 1182 except AttributeError: 1183 return None 1184 1185 for entriesName in ['types', 'commands', 'extensions']: 1186 treeEntries = treeRoot.find(entriesName) 1187 1188 originalEntryDict = {} 1189 for entry in treeEntries: 1190 name = getEntryName(entry) 1191 if name is not None: 1192 originalEntryDict[name] = entry 1193 1194 for entry in treeGfxstreamRoot.find(entriesName): 1195 name = getEntryName(entry) 1196 # New entry, just append to entry list 1197 if name not in originalEntryDict.keys(): 1198 treeEntries.append(entry) 1199 continue 1200 print(f'Entry {entriesName}:{name}') 1201 1202 originalEntry = originalEntryDict[name] 1203 1204 # Extending an existing entry. This happens for MVK. 1205 if entriesName == "extensions": 1206 for key, value in entry.attrib.items(): 1207 originalEntry.set(key, value) 1208 require = entry.find("require") 1209 if require is not None: 1210 for child in require: 1211 originalEntry.find("require").append(child) 1212 continue 1213 1214 # Overwriting an existing entry. This happen for 1215 # VkNativeBufferANDROID 1216 if entriesName == "types" or entriesName == "commands": 1217 originalEntry.clear() 1218 originalEntry.attrib = entry.attrib 1219 for child in entry: 1220 originalEntry.append(child) 1221 1222 # Load the XML tree into the registry object 1223 startTimer(args.time) 1224 reg.loadElementTree(tree) 1225 endTimer(args.time, '* Time to parse ElementTree =') 1226 1227 if args.dump: 1228 logDiag('* Dumping registry to regdump.txt') 1229 reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8')) 1230 1231 # Finally, use the output generator to create the requested target 1232 if args.debug: 1233 pdb.run('reg.apiGen()') 1234 else: 1235 startTimer(args.time) 1236 reg.apiGen() 1237 endTimer(args.time, '* Time to generate ' + args.target + ' =') 1238 1239 if not args.quiet: 1240 logDiag('* Generated', args.target) 1241