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