1#!/usr/bin/python3
2#
3# Copyright (c) 2013-2017 The Khronos Group Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import argparse, cProfile, pdb, string, sys, time
18from reg import *
19from generator import write
20from cgenerator import CGeneratorOptions, COutputGenerator
21# LoaderAndValidationLayer Generator Modifications
22from threading_generator import  ThreadGeneratorOptions, ThreadOutputGenerator
23from parameter_validation_generator import ParameterValidationGeneratorOptions, ParameterValidationOutputGenerator
24from unique_objects_generator import UniqueObjectsGeneratorOptions, UniqueObjectsOutputGenerator
25from object_tracker_generator import ObjectTrackerGeneratorOptions, ObjectTrackerOutputGenerator
26from dispatch_table_helper_generator import DispatchTableHelperOutputGenerator, DispatchTableHelperOutputGeneratorOptions
27from helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
28from loader_extension_generator import LoaderExtensionOutputGenerator, LoaderExtensionGeneratorOptions
29from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator
30
31# Simple timer functions
32startTime = None
33
34def startTimer(timeit):
35    global startTime
36    startTime = time.clock()
37
38def endTimer(timeit, msg):
39    global startTime
40    endTime = time.clock()
41    if (timeit):
42        write(msg, endTime - startTime, file=sys.stderr)
43        startTime = None
44
45# Turn a list of strings into a regexp string matching exactly those strings
46def makeREstring(list):
47    return '^(' + '|'.join(list) + ')$'
48
49# Returns a directory of [ generator function, generator options ] indexed
50# by specified short names. The generator options incorporate the following
51# parameters:
52#
53# extensions - list of extension names to include.
54# protect - True if re-inclusion protection should be added to headers
55# directory - path to directory in which to generate the target(s)
56def makeGenOpts(extensions = [], removeExtensions = [], protect = True, directory = '.'):
57    global genOpts
58    genOpts = {}
59
60    # Descriptive names for various regexp patterns used to select
61    # versions and extensions
62    allVersions     = allExtensions = '.*'
63    noVersions      = noExtensions = None
64
65    addExtensions     = makeREstring(extensions)
66    removeExtensions  = makeREstring(removeExtensions)
67
68    # Copyright text prefixing all headers (list of strings).
69    prefixStrings = [
70        '/*',
71        '** Copyright (c) 2015-2017 The Khronos Group Inc.',
72        '**',
73        '** Licensed under the Apache License, Version 2.0 (the "License");',
74        '** you may not use this file except in compliance with the License.',
75        '** You may obtain a copy of the License at',
76        '**',
77        '**     http://www.apache.org/licenses/LICENSE-2.0',
78        '**',
79        '** Unless required by applicable law or agreed to in writing, software',
80        '** distributed under the License is distributed on an "AS IS" BASIS,',
81        '** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
82        '** See the License for the specific language governing permissions and',
83        '** limitations under the License.',
84        '*/',
85        ''
86    ]
87
88    # Text specific to Vulkan headers
89    vkPrefixStrings = [
90        '/*',
91        '** This header is generated from the Khronos Vulkan XML API Registry.',
92        '**',
93        '*/',
94        ''
95    ]
96
97    # Defaults for generating re-inclusion protection wrappers (or not)
98    protectFile = protect
99    protectFeature = protect
100    protectProto = protect
101
102
103        #
104    # LoaderAndValidationLayer Generators
105    # Options for threading layer
106    genOpts['thread_check.h'] = [
107          ThreadOutputGenerator,
108          ThreadGeneratorOptions(
109            filename          = 'thread_check.h',
110            directory         = directory,
111            apiname           = 'vulkan',
112            profile           = None,
113            versions          = allVersions,
114            emitversions      = allVersions,
115            defaultExtensions = 'vulkan',
116            addExtensions     = addExtensions,
117            removeExtensions  = removeExtensions,
118            prefixText        = prefixStrings + vkPrefixStrings,
119            protectFeature    = False,
120            apicall           = 'VKAPI_ATTR ',
121            apientry          = 'VKAPI_CALL ',
122            apientryp         = 'VKAPI_PTR *',
123            alignFuncParam    = 48)
124        ]
125
126    # Options for parameter validation layer
127    genOpts['parameter_validation.cpp'] = [
128          ParameterValidationOutputGenerator,
129          ParameterValidationGeneratorOptions(
130            filename          = 'parameter_validation.cpp',
131            directory         = directory,
132            apiname           = 'vulkan',
133            profile           = None,
134            versions          = allVersions,
135            emitversions      = allVersions,
136            defaultExtensions = 'vulkan',
137            addExtensions     = addExtensions,
138            removeExtensions  = removeExtensions,
139            prefixText        = prefixStrings + vkPrefixStrings,
140            protectFeature    = False,
141            apicall           = 'VKAPI_ATTR ',
142            apientry          = 'VKAPI_CALL ',
143            apientryp         = 'VKAPI_PTR *',
144            alignFuncParam    = 48)
145        ]
146
147    # Options for unique objects layer
148    genOpts['unique_objects_wrappers.h'] = [
149          UniqueObjectsOutputGenerator,
150          UniqueObjectsGeneratorOptions(
151            filename          = 'unique_objects_wrappers.h',
152            directory         = directory,
153            apiname           = 'vulkan',
154            profile           = None,
155            versions          = allVersions,
156            emitversions      = allVersions,
157            defaultExtensions = 'vulkan',
158            addExtensions     = addExtensions,
159            removeExtensions  = removeExtensions,
160            prefixText        = prefixStrings + vkPrefixStrings,
161            protectFeature    = False,
162            apicall           = 'VKAPI_ATTR ',
163            apientry          = 'VKAPI_CALL ',
164            apientryp         = 'VKAPI_PTR *',
165            alignFuncParam    = 48)
166        ]
167
168    # Options for object_tracker layer
169    genOpts['object_tracker.cpp'] = [
170          ObjectTrackerOutputGenerator,
171          ObjectTrackerGeneratorOptions(
172            filename          = 'object_tracker.cpp',
173            directory         = directory,
174            apiname           = 'vulkan',
175            profile           = None,
176            versions          = allVersions,
177            emitversions      = allVersions,
178            defaultExtensions = 'vulkan',
179            addExtensions     = addExtensions,
180            removeExtensions  = removeExtensions,
181            prefixText        = prefixStrings + vkPrefixStrings,
182            protectFeature    = False,
183            apicall           = 'VKAPI_ATTR ',
184            apientry          = 'VKAPI_CALL ',
185            apientryp         = 'VKAPI_PTR *',
186            alignFuncParam    = 48)
187        ]
188
189    # Options for dispatch table helper generator
190    genOpts['vk_dispatch_table_helper.h'] = [
191          DispatchTableHelperOutputGenerator,
192          DispatchTableHelperOutputGeneratorOptions(
193            filename          = 'vk_dispatch_table_helper.h',
194            directory         = directory,
195            apiname           = 'vulkan',
196            profile           = None,
197            versions          = allVersions,
198            emitversions      = allVersions,
199            defaultExtensions = 'vulkan',
200            addExtensions     = addExtensions,
201            removeExtensions  = removeExtensions,
202            prefixText        = prefixStrings + vkPrefixStrings,
203            protectFeature    = False,
204            apicall           = 'VKAPI_ATTR ',
205            apientry          = 'VKAPI_CALL ',
206            apientryp         = 'VKAPI_PTR *',
207            alignFuncParam    = 48)
208        ]
209
210    # Options for Layer dispatch table generator
211    genOpts['vk_layer_dispatch_table.h'] = [
212          LoaderExtensionOutputGenerator,
213          LoaderExtensionGeneratorOptions(
214            filename          = 'vk_layer_dispatch_table.h',
215            directory         = directory,
216            apiname           = 'vulkan',
217            profile           = None,
218            versions          = allVersions,
219            emitversions      = allVersions,
220            defaultExtensions = 'vulkan',
221            addExtensions     = addExtensions,
222            removeExtensions  = removeExtensions,
223            prefixText        = prefixStrings + vkPrefixStrings,
224            protectFeature    = False,
225            apicall           = 'VKAPI_ATTR ',
226            apientry          = 'VKAPI_CALL ',
227            apientryp         = 'VKAPI_PTR *',
228            alignFuncParam    = 48)
229        ]
230
231    # Options for loader extension source generator
232    genOpts['vk_loader_extensions.h'] = [
233          LoaderExtensionOutputGenerator,
234          LoaderExtensionGeneratorOptions(
235            filename          = 'vk_loader_extensions.h',
236            directory         = directory,
237            apiname           = 'vulkan',
238            profile           = None,
239            versions          = allVersions,
240            emitversions      = allVersions,
241            defaultExtensions = 'vulkan',
242            addExtensions     = addExtensions,
243            removeExtensions  = removeExtensions,
244            prefixText        = prefixStrings + vkPrefixStrings,
245            protectFeature    = False,
246            apicall           = 'VKAPI_ATTR ',
247            apientry          = 'VKAPI_CALL ',
248            apientryp         = 'VKAPI_PTR *',
249            alignFuncParam    = 48)
250        ]
251
252    # Options for loader extension source generator
253    genOpts['vk_loader_extensions.c'] = [
254          LoaderExtensionOutputGenerator,
255          LoaderExtensionGeneratorOptions(
256            filename          = 'vk_loader_extensions.c',
257            directory         = directory,
258            apiname           = 'vulkan',
259            profile           = None,
260            versions          = allVersions,
261            emitversions      = allVersions,
262            defaultExtensions = 'vulkan',
263            addExtensions     = addExtensions,
264            removeExtensions  = removeExtensions,
265            prefixText        = prefixStrings + vkPrefixStrings,
266            protectFeature    = False,
267            apicall           = 'VKAPI_ATTR ',
268            apientry          = 'VKAPI_CALL ',
269            apientryp         = 'VKAPI_PTR *',
270            alignFuncParam    = 48)
271        ]
272
273    # Helper file generator options for vk_enum_string_helper.h
274    genOpts['vk_enum_string_helper.h'] = [
275          HelperFileOutputGenerator,
276          HelperFileOutputGeneratorOptions(
277            filename          = 'vk_enum_string_helper.h',
278            directory         = directory,
279            apiname           = 'vulkan',
280            profile           = None,
281            versions          = allVersions,
282            emitversions      = allVersions,
283            defaultExtensions = 'vulkan',
284            addExtensions     = addExtensions,
285            removeExtensions  = removeExtensions,
286            prefixText        = prefixStrings + vkPrefixStrings,
287            protectFeature    = False,
288            apicall           = 'VKAPI_ATTR ',
289            apientry          = 'VKAPI_CALL ',
290            apientryp         = 'VKAPI_PTR *',
291            alignFuncParam    = 48,
292            helper_file_type  = 'enum_string_header')
293        ]
294
295    # Helper file generator options for vk_struct_size_helper.h
296    genOpts['vk_struct_size_helper.h'] = [
297          HelperFileOutputGenerator,
298          HelperFileOutputGeneratorOptions(
299            filename          = 'vk_struct_size_helper.h',
300            directory         = directory,
301            apiname           = 'vulkan',
302            profile           = None,
303            versions          = allVersions,
304            emitversions      = allVersions,
305            defaultExtensions = 'vulkan',
306            addExtensions     = addExtensions,
307            removeExtensions  = removeExtensions,
308            prefixText        = prefixStrings + vkPrefixStrings,
309            protectFeature    = False,
310            apicall           = 'VKAPI_ATTR ',
311            apientry          = 'VKAPI_CALL ',
312            apientryp         = 'VKAPI_PTR *',
313            alignFuncParam    = 48,
314            helper_file_type  = 'struct_size_header')
315        ]
316
317    # Helper file generator options for vk_struct_size_helper.c
318    genOpts['vk_struct_size_helper.c'] = [
319          HelperFileOutputGenerator,
320          HelperFileOutputGeneratorOptions(
321            filename          = 'vk_struct_size_helper.c',
322            directory         = directory,
323            apiname           = 'vulkan',
324            profile           = None,
325            versions          = allVersions,
326            emitversions      = allVersions,
327            defaultExtensions = 'vulkan',
328            addExtensions     = addExtensions,
329            removeExtensions  = removeExtensions,
330            prefixText        = prefixStrings + vkPrefixStrings,
331            protectFeature    = False,
332            apicall           = 'VKAPI_ATTR ',
333            apientry          = 'VKAPI_CALL ',
334            apientryp         = 'VKAPI_PTR *',
335            alignFuncParam    = 48,
336            helper_file_type  = 'struct_size_source')
337        ]
338
339    # Helper file generator options for vk_safe_struct.h
340    genOpts['vk_safe_struct.h'] = [
341          HelperFileOutputGenerator,
342          HelperFileOutputGeneratorOptions(
343            filename          = 'vk_safe_struct.h',
344            directory         = directory,
345            apiname           = 'vulkan',
346            profile           = None,
347            versions          = allVersions,
348            emitversions      = allVersions,
349            defaultExtensions = 'vulkan',
350            addExtensions     = addExtensions,
351            removeExtensions  = removeExtensions,
352            prefixText        = prefixStrings + vkPrefixStrings,
353            protectFeature    = False,
354            apicall           = 'VKAPI_ATTR ',
355            apientry          = 'VKAPI_CALL ',
356            apientryp         = 'VKAPI_PTR *',
357            alignFuncParam    = 48,
358            helper_file_type  = 'safe_struct_header')
359        ]
360
361    # Helper file generator options for vk_safe_struct.cpp
362    genOpts['vk_safe_struct.cpp'] = [
363          HelperFileOutputGenerator,
364          HelperFileOutputGeneratorOptions(
365            filename          = 'vk_safe_struct.cpp',
366            directory         = directory,
367            apiname           = 'vulkan',
368            profile           = None,
369            versions          = allVersions,
370            emitversions      = allVersions,
371            defaultExtensions = 'vulkan',
372            addExtensions     = addExtensions,
373            removeExtensions  = removeExtensions,
374            prefixText        = prefixStrings + vkPrefixStrings,
375            protectFeature    = False,
376            apicall           = 'VKAPI_ATTR ',
377            apientry          = 'VKAPI_CALL ',
378            apientryp         = 'VKAPI_PTR *',
379            alignFuncParam    = 48,
380            helper_file_type  = 'safe_struct_source')
381        ]
382
383    # Helper file generator options for vk_object_types.h
384    genOpts['vk_object_types.h'] = [
385          HelperFileOutputGenerator,
386          HelperFileOutputGeneratorOptions(
387            filename          = 'vk_object_types.h',
388            directory         = directory,
389            apiname           = 'vulkan',
390            profile           = None,
391            versions          = allVersions,
392            emitversions      = allVersions,
393            defaultExtensions = 'vulkan',
394            addExtensions     = addExtensions,
395            removeExtensions  = removeExtensions,
396            prefixText        = prefixStrings + vkPrefixStrings,
397            protectFeature    = False,
398            apicall           = 'VKAPI_ATTR ',
399            apientry          = 'VKAPI_CALL ',
400            apientryp         = 'VKAPI_PTR *',
401            alignFuncParam    = 48,
402            helper_file_type  = 'object_types_header')
403        ]
404
405    # Helper file generator options for extension_helper.h
406    genOpts['vk_extension_helper.h'] = [
407          HelperFileOutputGenerator,
408          HelperFileOutputGeneratorOptions(
409            filename          = 'vk_extension_helper.h',
410            directory         = directory,
411            apiname           = 'vulkan',
412            profile           = None,
413            versions          = allVersions,
414            emitversions      = allVersions,
415            defaultExtensions = 'vulkan',
416            addExtensions     = addExtensions,
417            removeExtensions  = removeExtensions,
418            prefixText        = prefixStrings + vkPrefixStrings,
419            protectFeature    = False,
420            apicall           = 'VKAPI_ATTR ',
421            apientry          = 'VKAPI_CALL ',
422            apientryp         = 'VKAPI_PTR *',
423            alignFuncParam    = 48,
424            helper_file_type  = 'extension_helper_header')
425        ]
426
427    # Helper file generator options for typemap_helper.h
428    genOpts['vk_typemap_helper.h'] = [
429          HelperFileOutputGenerator,
430          HelperFileOutputGeneratorOptions(
431            filename          = 'vk_typemap_helper.h',
432            directory         = directory,
433            apiname           = 'vulkan',
434            profile           = None,
435            versions          = allVersions,
436            emitversions      = allVersions,
437            defaultExtensions = 'vulkan',
438            addExtensions     = addExtensions,
439            removeExtensions  = removeExtensions,
440            prefixText        = prefixStrings + vkPrefixStrings,
441            protectFeature    = False,
442            apicall           = 'VKAPI_ATTR ',
443            apientry          = 'VKAPI_CALL ',
444            apientryp         = 'VKAPI_PTR *',
445            alignFuncParam    = 48,
446            helper_file_type  = 'typemap_helper_header')
447        ]
448
449    # Options for mock ICD header
450    genOpts['mock_icd.h'] = [
451          MockICDOutputGenerator,
452          MockICDGeneratorOptions(
453            filename          = 'mock_icd.h',
454            directory         = directory,
455            apiname           = 'vulkan',
456            profile           = None,
457            versions          = allVersions,
458            emitversions      = allVersions,
459            defaultExtensions = 'vulkan',
460            addExtensions     = addExtensions,
461            removeExtensions  = removeExtensions,
462            prefixText        = prefixStrings + vkPrefixStrings,
463            protectFeature    = False,
464            apicall           = 'VKAPI_ATTR ',
465            apientry          = 'VKAPI_CALL ',
466            apientryp         = 'VKAPI_PTR *',
467            alignFuncParam    = 48,
468            helper_file_type  = 'mock_icd_header')
469        ]
470
471    # Options for mock ICD cpp
472    genOpts['mock_icd.cpp'] = [
473          MockICDOutputGenerator,
474          MockICDGeneratorOptions(
475            filename          = 'mock_icd.cpp',
476            directory         = directory,
477            apiname           = 'vulkan',
478            profile           = None,
479            versions          = allVersions,
480            emitversions      = allVersions,
481            defaultExtensions = 'vulkan',
482            addExtensions     = addExtensions,
483            removeExtensions  = removeExtensions,
484            prefixText        = prefixStrings + vkPrefixStrings,
485            protectFeature    = False,
486            apicall           = 'VKAPI_ATTR ',
487            apientry          = 'VKAPI_CALL ',
488            apientryp         = 'VKAPI_PTR *',
489            alignFuncParam    = 48,
490            helper_file_type  = 'mock_icd_source')
491        ]
492
493# Generate a target based on the options in the matching genOpts{} object.
494# This is encapsulated in a function so it can be profiled and/or timed.
495# The args parameter is an parsed argument object containing the following
496# fields that are used:
497#   target - target to generate
498#   directory - directory to generate it in
499#   protect - True if re-inclusion wrappers should be created
500#   extensions - list of additional extensions to include in generated
501#   interfaces
502def genTarget(args):
503    global genOpts
504
505    # Create generator options with specified parameters
506    makeGenOpts(extensions = args.extension,
507                removeExtensions = args.removeExtension,
508                protect = args.protect,
509                directory = args.directory)
510
511    if (args.target in genOpts.keys()):
512        createGenerator = genOpts[args.target][0]
513        options = genOpts[args.target][1]
514
515        if not args.quiet:
516            write('* Building', options.filename, file=sys.stderr)
517
518        startTimer(args.time)
519        gen = createGenerator(errFile=errWarn,
520                              warnFile=errWarn,
521                              diagFile=diag)
522        reg.setGenerator(gen)
523        reg.apiGen(options)
524
525        if not args.quiet:
526            write('* Generated', options.filename, file=sys.stderr)
527        endTimer(args.time, '* Time to generate ' + options.filename + ' =')
528    else:
529        write('No generator options for unknown target:',
530              args.target, file=sys.stderr)
531
532# -extension name - may be a single extension name, a a space-separated list
533# of names, or a regular expression.
534if __name__ == '__main__':
535    parser = argparse.ArgumentParser()
536
537    parser.add_argument('-extension', action='append',
538                        default=[],
539                        help='Specify an extension or extensions to add to targets')
540    parser.add_argument('-removeExtension', action='append',
541                        default=[],
542                        help='Specify an extension or extensions to remove from targets')
543    parser.add_argument('-debug', action='store_true',
544                        help='Enable debugging')
545    parser.add_argument('-dump', action='store_true',
546                        help='Enable dump to stderr')
547    parser.add_argument('-diagfile', action='store',
548                        default=None,
549                        help='Write diagnostics to specified file')
550    parser.add_argument('-errfile', action='store',
551                        default=None,
552                        help='Write errors and warnings to specified file instead of stderr')
553    parser.add_argument('-noprotect', dest='protect', action='store_false',
554                        help='Disable inclusion protection in output headers')
555    parser.add_argument('-profile', action='store_true',
556                        help='Enable profiling')
557    parser.add_argument('-registry', action='store',
558                        default='vk.xml',
559                        help='Use specified registry file instead of vk.xml')
560    parser.add_argument('-time', action='store_true',
561                        help='Enable timing')
562    parser.add_argument('-validate', action='store_true',
563                        help='Enable group validation')
564    parser.add_argument('-o', action='store', dest='directory',
565                        default='.',
566                        help='Create target and related files in specified directory')
567    parser.add_argument('target', metavar='target', nargs='?',
568                        help='Specify target')
569    parser.add_argument('-quiet', action='store_true', default=False,
570                        help='Suppress script output during normal execution.')
571
572    args = parser.parse_args()
573
574    # This splits arguments which are space-separated lists
575    args.extension = [name for arg in args.extension for name in arg.split()]
576
577    # Load & parse registry
578    reg = Registry()
579
580    startTimer(args.time)
581    tree = etree.parse(args.registry)
582    endTimer(args.time, '* Time to make ElementTree =')
583
584    startTimer(args.time)
585    reg.loadElementTree(tree)
586    endTimer(args.time, '* Time to parse ElementTree =')
587
588    if (args.validate):
589        reg.validateGroups()
590
591    if (args.dump):
592        write('* Dumping registry to regdump.txt', file=sys.stderr)
593        reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
594
595    # create error/warning & diagnostic files
596    if (args.errfile):
597        errWarn = open(args.errfile, 'w', encoding='utf-8')
598    else:
599        errWarn = sys.stderr
600
601    if (args.diagfile):
602        diag = open(args.diagfile, 'w', encoding='utf-8')
603    else:
604        diag = None
605
606    if (args.debug):
607        pdb.run('genTarget(args)')
608    elif (args.profile):
609        import cProfile, pstats
610        cProfile.run('genTarget(args)', 'profile.txt')
611        p = pstats.Stats('profile.txt')
612        p.strip_dirs().sort_stats('time').print_stats(50)
613    else:
614        genTarget(args)
615