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