Home | History | Annotate | Download | only in src
      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 sys, time, pdb, string, cProfile
     18 from reg import *
     19 from generator import write, CGeneratorOptions, COutputGenerator, DocGeneratorOptions, DocOutputGenerator, PyOutputGenerator, ValidityOutputGenerator, HostSynchronizationOutputGenerator, ThreadGeneratorOptions, ThreadOutputGenerator
     20 from generator import ParamCheckerGeneratorOptions, ParamCheckerOutputGenerator
     21 
     22 # debug - start header generation in debugger
     23 # dump - dump registry after loading
     24 # profile - enable Python profiling
     25 # protect - whether to use #ifndef protections
     26 # registry <filename> - use specified XML registry instead of gl.xml
     27 # target - string name of target header, or all targets if None
     28 # timeit - time length of registry loading & header generation
     29 # validate - validate return & parameter group tags against <group>
     30 debug   = False
     31 dump    = False
     32 profile = False
     33 protect = True
     34 target  = None
     35 timeit  = False
     36 validate= False
     37 # Default input / log files
     38 errFilename = None
     39 diagFilename = 'diag.txt'
     40 regFilename = 'vk.xml'
     41 outDir = '.'
     42 
     43 if __name__ == '__main__':
     44     i = 1
     45     while (i < len(sys.argv)):
     46         arg = sys.argv[i]
     47         i = i + 1
     48         if (arg == '-debug'):
     49             write('Enabling debug (-debug)', file=sys.stderr)
     50             debug = True
     51         elif (arg == '-dump'):
     52             write('Enabling dump (-dump)', file=sys.stderr)
     53             dump = True
     54         elif (arg == '-noprotect'):
     55             write('Disabling inclusion protection in output headers', file=sys.stderr)
     56             protect = False
     57         elif (arg == '-profile'):
     58             write('Enabling profiling (-profile)', file=sys.stderr)
     59             profile = True
     60         elif (arg == '-registry'):
     61             regFilename = sys.argv[i]
     62             i = i+1
     63             write('Using registry ', regFilename, file=sys.stderr)
     64         elif (arg == '-time'):
     65             write('Enabling timing (-time)', file=sys.stderr)
     66             timeit = True
     67         elif (arg == '-validate'):
     68             write('Enabling group validation (-validate)', file=sys.stderr)
     69             validate = True
     70         elif (arg == '-outdir'):
     71             outDir = sys.argv[i]
     72             i = i+1
     73             write('Using output directory ', outDir, file=sys.stderr)
     74         elif (arg[0:1] == '-'):
     75             write('Unrecognized argument:', arg, file=sys.stderr)
     76             exit(1)
     77         else:
     78             target = arg
     79             write('Using target', target, file=sys.stderr)
     80 
     81 # Simple timer functions
     82 startTime = None
     83 def startTimer():
     84     global startTime
     85     startTime = time.clock()
     86 def endTimer(msg):
     87     global startTime
     88     endTime = time.clock()
     89     if (timeit):
     90         write(msg, endTime - startTime)
     91         startTime = None
     92 
     93 # Load & parse registry
     94 reg = Registry()
     95 
     96 startTimer()
     97 tree = etree.parse(regFilename)
     98 endTimer('Time to make ElementTree =')
     99 
    100 startTimer()
    101 reg.loadElementTree(tree)
    102 endTimer('Time to parse ElementTree =')
    103 
    104 if (validate):
    105     reg.validateGroups()
    106 
    107 if (dump):
    108     write('***************************************')
    109     write('Performing Registry dump to regdump.txt')
    110     write('***************************************')
    111     reg.dumpReg(filehandle = open('regdump.txt','w'))
    112 
    113 # Turn a list of strings into a regexp string matching exactly those strings
    114 def makeREstring(list):
    115     return '^(' + '|'.join(list) + ')$'
    116 
    117 # Descriptive names for various regexp patterns used to select
    118 # versions and extensions
    119 allVersions     = allExtensions = '.*'
    120 noVersions      = noExtensions = None
    121 
    122 # Copyright text prefixing all headers (list of strings).
    123 prefixStrings = [
    124     '/*',
    125     '** Copyright (c) 2015-2016 The Khronos Group Inc.',
    126     '**',
    127     '** Licensed under the Apache License, Version 2.0 (the "License");',
    128     '** you may not use this file except in compliance with the License.',
    129     '** You may obtain a copy of the License at',
    130     '**',
    131     '**     http://www.apache.org/licenses/LICENSE-2.0',
    132     '**',
    133     '** Unless required by applicable law or agreed to in writing, software',
    134     '** distributed under the License is distributed on an "AS IS" BASIS,',
    135     '** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
    136     '** See the License for the specific language governing permissions and',
    137     '** limitations under the License.',
    138     '*/',
    139     ''
    140 ]
    141 
    142 # Text specific to Vulkan headers
    143 vkPrefixStrings = [
    144     '/*',
    145     '** This header is generated from the Khronos Vulkan XML API Registry.',
    146     '**',
    147     '*/',
    148     ''
    149 ]
    150 
    151 # Defaults for generating re-inclusion protection wrappers (or not)
    152 protectFile = protect
    153 protectFeature = protect
    154 protectProto = protect
    155 
    156 buildList = [
    157     # Vulkan 1.0 - header for core API + extensions.
    158     # To generate just the core API,
    159     # change to 'defaultExtensions = None' below.
    160     [ COutputGenerator,
    161       CGeneratorOptions(
    162         filename          = 'include/vulkan/vulkan.h',
    163         apiname           = 'vulkan',
    164         profile           = None,
    165         versions          = allVersions,
    166         emitversions      = allVersions,
    167         defaultExtensions = 'vulkan',
    168         addExtensions     = None,
    169         removeExtensions  = None,
    170         prefixText        = prefixStrings + vkPrefixStrings,
    171         genFuncPointers   = True,
    172         protectFile       = protectFile,
    173         protectFeature    = False,
    174         protectProto      = '#ifndef',
    175         protectProtoStr   = 'VK_NO_PROTOTYPES',
    176         apicall           = 'VKAPI_ATTR ',
    177         apientry          = 'VKAPI_CALL ',
    178         apientryp         = 'VKAPI_PTR *',
    179         alignFuncParam    = 48)
    180     ],
    181     # Vulkan 1.0 draft - API include files for spec and ref pages
    182     # Overwrites include subdirectories in spec source tree
    183     # The generated include files do not include the calling convention
    184     # macros (apientry etc.), unlike the header files.
    185     # Because the 1.0 core branch includes ref pages for extensions,
    186     # all the extension interfaces need to be generated, even though
    187     # none are used by the core spec itself.
    188     [ DocOutputGenerator,
    189       DocGeneratorOptions(
    190         filename          = 'vulkan-docs',
    191         apiname           = 'vulkan',
    192         profile           = None,
    193         versions          = allVersions,
    194         emitversions      = allVersions,
    195         defaultExtensions = None,
    196         addExtensions     =
    197             makeREstring([
    198                 'VK_KHR_sampler_mirror_clamp_to_edge',
    199             ]),
    200         removeExtensions  =
    201             makeREstring([
    202             ]),
    203         prefixText        = prefixStrings + vkPrefixStrings,
    204         apicall           = '',
    205         apientry          = '',
    206         apientryp         = '*',
    207         genDirectory      = '../../doc/specs/vulkan',
    208         alignFuncParam    = 48,
    209         expandEnumerants  = False)
    210     ],
    211     # Vulkan 1.0 draft - API names to validate man/api spec includes & links
    212     [ PyOutputGenerator,
    213       DocGeneratorOptions(
    214         filename          = '../../doc/specs/vulkan/vkapi.py',
    215         apiname           = 'vulkan',
    216         profile           = None,
    217         versions          = allVersions,
    218         emitversions      = allVersions,
    219         defaultExtensions = None,
    220         addExtensions     =
    221             makeREstring([
    222                 'VK_KHR_sampler_mirror_clamp_to_edge',
    223             ]),
    224         removeExtensions  =
    225             makeREstring([
    226             ]))
    227     ],
    228     # Vulkan 1.0 draft - core API validity files for spec
    229     # Overwrites validity subdirectories in spec source tree
    230     [ ValidityOutputGenerator,
    231       DocGeneratorOptions(
    232         filename          = 'validity',
    233         apiname           = 'vulkan',
    234         profile           = None,
    235         versions          = allVersions,
    236         emitversions      = allVersions,
    237         defaultExtensions = None,
    238         addExtensions     =
    239             makeREstring([
    240                 'VK_KHR_sampler_mirror_clamp_to_edge',
    241             ]),
    242         removeExtensions  =
    243             makeREstring([
    244             ]),
    245         genDirectory      = '../../doc/specs/vulkan')
    246     ],
    247     # Vulkan 1.0 draft - core API host sync table files for spec
    248     # Overwrites subdirectory in spec source tree
    249     [ HostSynchronizationOutputGenerator,
    250       DocGeneratorOptions(
    251         filename          = 'hostsynctable',
    252         apiname           = 'vulkan',
    253         profile           = None,
    254         versions          = allVersions,
    255         emitversions      = allVersions,
    256         defaultExtensions = None,
    257         addExtensions     =
    258             makeREstring([
    259                 'VK_KHR_sampler_mirror_clamp_to_edge',
    260             ]),
    261         removeExtensions  =
    262             makeREstring([
    263             ]),
    264         genDirectory      = '../../doc/specs/vulkan')
    265     ],
    266     # Vulkan 1.0 draft - thread checking layer
    267     [ ThreadOutputGenerator,
    268       ThreadGeneratorOptions(
    269         filename          = 'thread_check.h',
    270         apiname           = 'vulkan',
    271         profile           = None,
    272         versions          = allVersions,
    273         emitversions      = allVersions,
    274         defaultExtensions = 'vulkan',
    275         addExtensions     = None,
    276         removeExtensions  = None,
    277         prefixText        = prefixStrings + vkPrefixStrings,
    278         genFuncPointers   = True,
    279         protectFile       = protectFile,
    280         protectFeature    = False,
    281         protectProto      = True,
    282         protectProtoStr   = 'VK_PROTOTYPES',
    283         apicall           = 'VKAPI_ATTR ',
    284         apientry          = 'VKAPI_CALL ',
    285         apientryp         = 'VKAPI_PTR *',
    286         alignFuncParam    = 48,
    287         genDirectory      = outDir)
    288     ],
    289     [ ParamCheckerOutputGenerator,
    290       ParamCheckerGeneratorOptions(
    291         filename          = 'parameter_validation.h',
    292         apiname           = 'vulkan',
    293         profile           = None,
    294         versions          = allVersions,
    295         emitversions      = allVersions,
    296         defaultExtensions = 'vulkan',
    297         addExtensions     = None,
    298         removeExtensions  = None,
    299         prefixText        = prefixStrings + vkPrefixStrings,
    300         genFuncPointers   = True,
    301         protectFile       = protectFile,
    302         protectFeature    = False,
    303         protectProto      = None,
    304         protectProtoStr   = 'VK_NO_PROTOTYPES',
    305         apicall           = 'VKAPI_ATTR ',
    306         apientry          = 'VKAPI_CALL ',
    307         apientryp         = 'VKAPI_PTR *',
    308         alignFuncParam    = 48,
    309         genDirectory      = outDir)
    310     ],
    311     None
    312 ]
    313 
    314 # create error/warning & diagnostic files
    315 if (errFilename):
    316     errWarn = open(errFilename,'w')
    317 else:
    318     errWarn = sys.stderr
    319 diag = open(diagFilename, 'w')
    320 
    321 # check that output directory exists
    322 if (not os.path.isdir(outDir)):
    323     write('Output directory does not exist: ', outDir)
    324     raise
    325 
    326 def genHeaders():
    327     # Loop over targets, building each
    328     generated = 0
    329     for item in buildList:
    330         if (item == None):
    331             break
    332         createGenerator = item[0]
    333         genOpts = item[1]
    334         if (target and target != genOpts.filename):
    335             # write('*** Skipping', genOpts.filename)
    336             continue
    337         write('*** Building', genOpts.filename)
    338         generated = generated + 1
    339         startTimer()
    340         gen = createGenerator(errFile=errWarn,
    341                               warnFile=errWarn,
    342                               diagFile=diag)
    343         reg.setGenerator(gen)
    344         reg.apiGen(genOpts)
    345         write('** Generated', genOpts.filename)
    346         endTimer('Time to generate ' + genOpts.filename + ' =')
    347     if (target and generated == 0):
    348         write('Failed to generate target:', target)
    349 
    350 if (debug):
    351     pdb.run('genHeaders()')
    352 elif (profile):
    353     import cProfile, pstats
    354     cProfile.run('genHeaders()', 'profile.txt')
    355     p = pstats.Stats('profile.txt')
    356     p.strip_dirs().sort_stats('time').print_stats(50)
    357 else:
    358     genHeaders()
    359