Home | History | Annotate | Download | only in vulkan-validation-layers
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (c) 2013-2016 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 
     17 import argparse, cProfile, pdb, string, sys, time
     18 from reg import *
     19 from generator import write
     20 
     21 #
     22 # LoaderAndValidationLayer Generator Additions
     23 from threading_generator import  ThreadGeneratorOptions, ThreadOutputGenerator
     24 from parameter_validation_generator import ParamCheckerGeneratorOptions, ParamCheckerOutputGenerator
     25 from unique_objects_generator import UniqueObjectsGeneratorOptions, UniqueObjectsOutputGenerator
     26 
     27 # Simple timer functions
     28 startTime = None
     29 
     30 def startTimer(timeit):
     31     global startTime
     32     startTime = time.clock()
     33 
     34 def endTimer(timeit, msg):
     35     global startTime
     36     endTime = time.clock()
     37     if (timeit):
     38         write(msg, endTime - startTime, file=sys.stderr)
     39         startTime = None
     40 
     41 # Turn a list of strings into a regexp string matching exactly those strings
     42 def makeREstring(list):
     43     return '^(' + '|'.join(list) + ')$'
     44 
     45 # Returns a directory of [ generator function, generator options ] indexed
     46 # by specified short names. The generator options incorporate the following
     47 # parameters:
     48 #
     49 # extensions - list of extension names to include.
     50 # protect - True if re-inclusion protection should be added to headers
     51 # directory - path to directory in which to generate the target(s)
     52 def makeGenOpts(extensions = [], protect = True, directory = '.'):
     53     global genOpts
     54     genOpts = {}
     55 
     56     # Descriptive names for various regexp patterns used to select
     57     # versions and extensions
     58     allVersions     = allExtensions = '.*'
     59     noVersions      = noExtensions = None
     60 
     61     addExtensions     = makeREstring(extensions)
     62     removeExtensions  = makeREstring([])
     63 
     64     # Copyright text prefixing all headers (list of strings).
     65     prefixStrings = [
     66         '/*',
     67         '** Copyright (c) 2015-2016 The Khronos Group Inc.',
     68         '**',
     69         '** Licensed under the Apache License, Version 2.0 (the "License");',
     70         '** you may not use this file except in compliance with the License.',
     71         '** You may obtain a copy of the License at',
     72         '**',
     73         '**     http://www.apache.org/licenses/LICENSE-2.0',
     74         '**',
     75         '** Unless required by applicable law or agreed to in writing, software',
     76         '** distributed under the License is distributed on an "AS IS" BASIS,',
     77         '** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
     78         '** See the License for the specific language governing permissions and',
     79         '** limitations under the License.',
     80         '*/',
     81         ''
     82     ]
     83 
     84     # Text specific to Vulkan headers
     85     vkPrefixStrings = [
     86         '/*',
     87         '** This header is generated from the Khronos Vulkan XML API Registry.',
     88         '**',
     89         '*/',
     90         ''
     91     ]
     92 
     93     # Defaults for generating re-inclusion protection wrappers (or not)
     94     protectFile = protect
     95     protectFeature = protect
     96     protectProto = protect
     97 
     98     #
     99     # LoaderAndValidationLayer Generators
    100     # Options for threading layer
    101     genOpts['thread_check.h'] = [
    102           ThreadOutputGenerator,
    103           ThreadGeneratorOptions(
    104             filename          = 'thread_check.h',
    105             directory         = directory,
    106             apiname           = 'vulkan',
    107             profile           = None,
    108             versions          = allVersions,
    109             emitversions      = allVersions,
    110             defaultExtensions = 'vulkan',
    111             addExtensions     = addExtensions,
    112             removeExtensions  = removeExtensions,
    113             prefixText        = prefixStrings + vkPrefixStrings,
    114             protectFeature    = False,
    115             apicall           = 'VKAPI_ATTR ',
    116             apientry          = 'VKAPI_CALL ',
    117             apientryp         = 'VKAPI_PTR *',
    118             alignFuncParam    = 48)
    119         ]
    120 
    121     # Options for parameter validation layer
    122     genOpts['parameter_validation.h'] = [
    123           ParamCheckerOutputGenerator,
    124           ParamCheckerGeneratorOptions(
    125             filename          = 'parameter_validation.h',
    126             directory         = directory,
    127             apiname           = 'vulkan',
    128             profile           = None,
    129             versions          = allVersions,
    130             emitversions      = allVersions,
    131             defaultExtensions = 'vulkan',
    132             addExtensions     = addExtensions,
    133             removeExtensions  = removeExtensions,
    134             prefixText        = prefixStrings + vkPrefixStrings,
    135             protectFeature    = False,
    136             apicall           = 'VKAPI_ATTR ',
    137             apientry          = 'VKAPI_CALL ',
    138             apientryp         = 'VKAPI_PTR *',
    139             alignFuncParam    = 48)
    140         ]
    141 
    142     # Options for unique objects layer
    143     genOpts['unique_objects_wrappers.h'] = [
    144           UniqueObjectsOutputGenerator,
    145           UniqueObjectsGeneratorOptions(
    146             filename          = 'unique_objects_wrappers.h',
    147             directory         = directory,
    148             apiname           = 'vulkan',
    149             profile           = None,
    150             versions          = allVersions,
    151             emitversions      = allVersions,
    152             defaultExtensions = 'vulkan',
    153             addExtensions     = addExtensions,
    154             removeExtensions  = removeExtensions,
    155             prefixText        = prefixStrings + vkPrefixStrings,
    156             protectFeature    = False,
    157             apicall           = 'VKAPI_ATTR ',
    158             apientry          = 'VKAPI_CALL ',
    159             apientryp         = 'VKAPI_PTR *',
    160             alignFuncParam    = 48)
    161         ]
    162 
    163 # Generate a target based on the options in the matching genOpts{} object.
    164 # This is encapsulated in a function so it can be profiled and/or timed.
    165 # The args parameter is an parsed argument object containing the following
    166 # fields that are used:
    167 #   target - target to generate
    168 #   directory - directory to generate it in
    169 #   protect - True if re-inclusion wrappers should be created
    170 #   extensions - list of additional extensions to include in generated
    171 #   interfaces
    172 def genTarget(args):
    173     global genOpts
    174 
    175     # Create generator options with specified parameters
    176     makeGenOpts(extensions = args.extension,
    177                 protect = args.protect,
    178                 directory = args.directory)
    179 
    180     if (args.target in genOpts.keys()):
    181         createGenerator = genOpts[args.target][0]
    182         options = genOpts[args.target][1]
    183 
    184         write('* Building', options.filename, file=sys.stderr)
    185 
    186         startTimer(args.time)
    187         gen = createGenerator(errFile=errWarn,
    188                               warnFile=errWarn,
    189                               diagFile=diag)
    190         reg.setGenerator(gen)
    191         reg.apiGen(options)
    192         write('* Generated', options.filename, file=sys.stderr)
    193         endTimer(args.time, '* Time to generate ' + options.filename + ' =')
    194     else:
    195         write('No generator options for unknown target:',
    196               args.target, file=sys.stderr)
    197 
    198 # -extension name - may be a single extension name, a a space-separated list
    199 # of names, or a regular expression.
    200 if __name__ == '__main__':
    201     parser = argparse.ArgumentParser()
    202 
    203     parser.add_argument('-extension', action='append',
    204                         default=[],
    205                         help='Specify an extension or extensions to add to targets')
    206     parser.add_argument('-debug', action='store_true',
    207                         help='Enable debugging')
    208     parser.add_argument('-dump', action='store_true',
    209                         help='Enable dump to stderr')
    210     parser.add_argument('-diagfile', action='store',
    211                         default=None,
    212                         help='Write diagnostics to specified file')
    213     parser.add_argument('-errfile', action='store',
    214                         default=None,
    215                         help='Write errors and warnings to specified file instead of stderr')
    216     parser.add_argument('-noprotect', dest='protect', action='store_false',
    217                         help='Disable inclusion protection in output headers')
    218     parser.add_argument('-profile', action='store_true',
    219                         help='Enable profiling')
    220     parser.add_argument('-registry', action='store',
    221                         default='vk.xml',
    222                         help='Use specified registry file instead of vk.xml')
    223     parser.add_argument('-time', action='store_true',
    224                         help='Enable timing')
    225     parser.add_argument('-validate', action='store_true',
    226                         help='Enable group validation')
    227     parser.add_argument('-o', action='store', dest='directory',
    228                         default='.',
    229                         help='Create target and related files in specified directory')
    230     parser.add_argument('target', metavar='target', nargs='?',
    231                         help='Specify target')
    232 
    233     args = parser.parse_args()
    234 
    235     # This splits arguments which are space-separated lists
    236     args.extension = [name for arg in args.extension for name in arg.split()]
    237 
    238     # Load & parse registry
    239     reg = Registry()
    240 
    241     startTimer(args.time)
    242     tree = etree.parse(args.registry)
    243     endTimer(args.time, '* Time to make ElementTree =')
    244 
    245     startTimer(args.time)
    246     reg.loadElementTree(tree)
    247     endTimer(args.time, '* Time to parse ElementTree =')
    248 
    249     if (args.validate):
    250         reg.validateGroups()
    251 
    252     if (args.dump):
    253         write('* Dumping registry to regdump.txt', file=sys.stderr)
    254         reg.dumpReg(filehandle = open('regdump.txt','w'))
    255 
    256     # create error/warning & diagnostic files
    257     if (args.errfile):
    258         errWarn = open(args.errfile, 'w')
    259     else:
    260         errWarn = sys.stderr
    261 
    262     if (args.diagfile):
    263         diag = open(args.diagfile, 'w')
    264     else:
    265         diag = None
    266 
    267     if (args.debug):
    268         pdb.run('genTarget(args)')
    269     elif (args.profile):
    270         import cProfile, pstats
    271         cProfile.run('genTarget(args)', 'profile.txt')
    272         p = pstats.Stats('profile.txt')
    273         p.strip_dirs().sort_stats('time').print_stats(50)
    274     else:
    275         genTarget(args)
    276