• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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