vulkaninfo: Add video profiles support
[KhronosGroup/Vulkan-Tools.git] / scripts / kvt_genvk.py
bloba31bc08e3ac81fdc6d2a83305b64e3ff0bcaee9d
1 #!/usr/bin/python3
3 # Copyright (c) 2013-2024 The Khronos Group Inc.
4 # Copyright (c) 2023-2024 RasterGrid Kft.
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
18 import argparse
19 import cProfile
20 import pdb
21 import string
22 import sys
23 import time
24 import os
26 # Simple timer functions
27 startTime = None
30 def startTimer(timeit):
31 global startTime
32 if timeit:
33 startTime = time.process_time()
36 def endTimer(timeit, msg):
37 global startTime
38 if timeit:
39 endTime = time.process_time()
40 write(msg, endTime - startTime, file=sys.stderr)
41 startTime = None
43 # Turn a list of strings into a regexp string matching exactly those strings
46 def makeREstring(list, default=None):
47 if len(list) > 0 or default is None:
48 return '^(' + '|'.join(list) + ')$'
49 else:
50 return default
52 # Returns a directory of [ generator function, generator options ] indexed
53 # by specified short names. The generator options incorporate the following
54 # parameters:
56 # args is an parsed argument object; see below for the fields that are used.
59 def makeGenOpts(args):
60 global genOpts
61 genOpts = {}
63 # API to generate sources for
64 apiname = args.api
66 # Default class of extensions to include, or None
67 if args.defaultExtensions is not None:
68 defaultExtensions = args.defaultExtensions
69 else:
70 defaultExtensions = apiname
72 # Additional extensions to include (list of extensions)
73 extensions = args.extension
75 # Extensions to remove (list of extensions)
76 removeExtensions = args.removeExtensions
78 # Extensions to emit (list of extensions)
79 emitExtensions = args.emitExtensions
81 # Features to include (list of features)
82 features = args.feature
84 # Whether to disable inclusion protect in headers
85 protect = args.protect
87 # Output target directory
88 directory = args.directory
90 # Path to generated files, particularly api.py
91 genpath = args.genpath
93 # Descriptive names for various regexp patterns used to select
94 # versions and extensions
95 allFeatures = allExtensions = '.*'
96 noFeatures = noExtensions = None
98 # Turn lists of names/patterns into matching regular expressions
99 addExtensionsPat = makeREstring(extensions, None)
100 removeExtensionsPat = makeREstring(removeExtensions, None)
101 emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
102 featuresPat = makeREstring(features, allFeatures)
104 # Copyright text prefixing all headers (list of strings).
105 prefixStrings = [
106 '/*',
107 '** Copyright (c) 2015-2024 The Khronos Group Inc.',
108 '**',
109 '** Licensed under the Apache License, Version 2.0 (the "License");',
110 '** you may not use this file except in compliance with the License.',
111 '** You may obtain a copy of the License at',
112 '**',
113 '** http://www.apache.org/licenses/LICENSE-2.0',
114 '**',
115 '** Unless required by applicable law or agreed to in writing, software',
116 '** distributed under the License is distributed on an "AS IS" BASIS,',
117 '** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
118 '** See the License for the specific language governing permissions and',
119 '** limitations under the License.',
120 '*/',
124 # Text specific to Vulkan headers
125 vkPrefixStrings = [
126 '/*',
127 '** This header is generated from the Khronos Vulkan XML API Registry.',
128 '**',
129 '*/',
133 # Defaults for generating re-inclusion protection wrappers (or not)
134 protectFeature = protect
136 # An API style conventions object
137 conventions = VulkanConventions()
139 # Helper file generator options for typemap_helper.h
140 genOpts['vk_typemap_helper.h'] = [
141 HelperFileOutputGenerator,
142 HelperFileOutputGeneratorOptions(
143 conventions=conventions,
144 filename='vk_typemap_helper.h',
145 directory=directory,
146 genpath=None,
147 apiname=apiname,
148 profile=None,
149 versions=featuresPat,
150 emitversions=featuresPat,
151 defaultExtensions=defaultExtensions,
152 addExtensions=addExtensionsPat,
153 removeExtensions=removeExtensionsPat,
154 emitExtensions=emitExtensionsPat,
155 prefixText=prefixStrings + vkPrefixStrings,
156 protectFeature=False,
157 apicall='VKAPI_ATTR ',
158 apientry='VKAPI_CALL ',
159 apientryp='VKAPI_PTR *',
160 alignFuncParam=48,
161 expandEnumerants=False,
162 helper_file_type='typemap_helper_header')
165 # Options for mock ICD header
166 genOpts['function_declarations.h'] = [
167 MockICDOutputGenerator,
168 MockICDGeneratorOptions(
169 conventions=conventions,
170 filename='function_declarations.h',
171 directory=directory,
172 genpath=None,
173 apiname=apiname,
174 profile=None,
175 versions=featuresPat,
176 emitversions=featuresPat,
177 defaultExtensions=defaultExtensions,
178 addExtensions=addExtensionsPat,
179 removeExtensions=removeExtensionsPat,
180 emitExtensions=emitExtensionsPat,
181 prefixText=prefixStrings + vkPrefixStrings,
182 protectFeature=False,
183 apicall='VKAPI_ATTR ',
184 apientry='VKAPI_CALL ',
185 apientryp='VKAPI_PTR *',
186 alignFuncParam=48,
187 expandEnumerants=False,
188 helper_file_type='mock_icd_function_declaration_implementation')
191 # Options for mock ICD cpp
192 genOpts['function_definitions.h'] = [
193 MockICDOutputGenerator,
194 MockICDGeneratorOptions(
195 conventions=conventions,
196 filename='function_definitions.h',
197 directory=directory,
198 genpath=None,
199 apiname=apiname,
200 profile=None,
201 versions=featuresPat,
202 emitversions=featuresPat,
203 defaultExtensions=defaultExtensions,
204 addExtensions=addExtensionsPat,
205 removeExtensions=removeExtensionsPat,
206 emitExtensions=emitExtensionsPat,
207 prefixText=prefixStrings + vkPrefixStrings,
208 protectFeature=False,
209 apicall='VKAPI_ATTR ',
210 apientry='VKAPI_CALL ',
211 apientryp='VKAPI_PTR *',
212 alignFuncParam=48,
213 expandEnumerants=False,
214 helper_file_type='mock_icd_function_definition_implementation')
217 # Options for vulkaninfo.hpp
218 genOpts['vulkaninfo.hpp'] = [
219 VulkanInfoGenerator,
220 VulkanInfoGeneratorOptions(
221 conventions=conventions,
222 filename='vulkaninfo.hpp',
223 directory=directory,
224 genpath=None,
225 apiname=apiname,
226 profile=None,
227 versions=featuresPat,
228 emitversions=featuresPat,
229 defaultExtensions=defaultExtensions,
230 addExtensions=addExtensionsPat,
231 removeExtensions=removeExtensionsPat,
232 emitExtensions=emitExtensionsPat,
233 prefixText=prefixStrings + vkPrefixStrings,
234 protectFeature=False,
235 apicall='VKAPI_ATTR ',
236 apientry='VKAPI_CALL ',
237 apientryp='VKAPI_PTR *',
238 alignFuncParam=48,
239 expandEnumerants=False,
240 registryFile=args.registry)
244 # Generate a target based on the options in the matching genOpts{} object.
245 # This is encapsulated in a function so it can be profiled and/or timed.
246 # The args parameter is an parsed argument object containing the following
247 # fields that are used:
248 # target - target to generate
249 # directory - directory to generate it in
250 # protect - True if re-inclusion wrappers should be created
251 # extensions - list of additional extensions to include in generated
252 # interfaces
253 def genTarget(args):
254 global genOpts
256 # Create generator options with specified parameters
257 makeGenOpts(args)
259 if (args.target in genOpts.keys()):
260 createGenerator = genOpts[args.target][0]
261 options = genOpts[args.target][1]
263 if not args.quiet:
264 write('* Building', options.filename, file=sys.stderr)
265 write('* options.apiname =', options.apiname, file=sys.stderr)
266 write('* options.versions =', options.versions, file=sys.stderr)
267 write('* options.emitversions =', options.emitversions, file=sys.stderr)
268 write('* options.defaultExtensions =', options.defaultExtensions, file=sys.stderr)
269 write('* options.addExtensions =', options.addExtensions, file=sys.stderr)
270 write('* options.removeExtensions =', options.removeExtensions, file=sys.stderr)
271 write('* options.emitExtensions =', options.emitExtensions, file=sys.stderr)
273 gen = createGenerator(errFile=errWarn,
274 warnFile=errWarn,
275 diagFile=diag)
276 if not args.quiet:
277 write('* Generated', options.filename, file=sys.stderr)
278 return (gen, options)
279 else:
280 write('No generator options for unknown target:',
281 args.target, file=sys.stderr)
282 return none
284 # -feature name
285 # -extension name
286 # For both, "name" may be a single name, or a space-separated list
287 # of names, or a regular expression.
288 if __name__ == '__main__':
289 parser = argparse.ArgumentParser()
291 parser.add_argument('-api', action='store',
292 default='vulkan',
293 choices=['vulkan', 'vulkansc'],
294 help='Specify API name to generate')
295 parser.add_argument('-defaultExtensions', action='store',
296 default=None,
297 help='Specify a single class of extensions to add to targets')
298 parser.add_argument('-directory', action='store', default='.',
299 help='Specify where the built file is place')
300 parser.add_argument('-extension', action='append',
301 default=[],
302 help='Specify an extension or extensions to add to targets')
303 parser.add_argument('-removeExtensions', action='append',
304 default=[],
305 help='Specify an extension or extensions to remove from targets')
306 parser.add_argument('-emitExtensions', action='append',
307 default=[],
308 help='Specify an extension or extensions to emit in targets')
309 parser.add_argument('-feature', action='append',
310 default=[],
311 help='Specify a core API feature name or names to add to targets')
312 parser.add_argument('-debug', action='store_true',
313 help='Enable debugging')
314 parser.add_argument('-dump', action='store_true',
315 help='Enable dump to stderr')
316 parser.add_argument('-diagfile', action='store',
317 default=None,
318 help='Write diagnostics to specified file')
319 parser.add_argument('-errfile', action='store',
320 default=None,
321 help='Write errors and warnings to specified file instead of stderr')
322 parser.add_argument('-noprotect', dest='protect', action='store_false',
323 help='Disable inclusion protection in output headers')
324 parser.add_argument('-profile', action='store_true',
325 help='Enable profiling')
326 parser.add_argument('-registry', action='store',
327 default='vk.xml',
328 help='Use specified registry file instead of vk.xml')
329 parser.add_argument('-time', action='store_true',
330 help='Enable timing')
331 parser.add_argument('-validate', action='store_true',
332 help='Enable XML group validation')
333 parser.add_argument('-genpath', action='store', default='gen',
334 help='Path to generated files')
335 parser.add_argument('-o', action='store', dest='directory',
336 default='.',
337 help='Create target and related files in specified directory')
338 parser.add_argument('target', metavar='target', nargs='?',
339 help='Specify target')
340 parser.add_argument('-quiet', action='store_true', default=True,
341 help='Suppress script output during normal execution.')
342 parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
343 help='Enable script output during normal execution.')
345 # This argument tells us where to load the script from the Vulkan-Headers registry
346 parser.add_argument('-scripts', action='store',
347 help='Find additional scripts in this directory')
349 args = parser.parse_args()
351 # default scripts path to be same as registry
352 if not args.scripts:
353 args.scripts = os.path.dirname(args.registry)
355 scripts_directory_path = os.path.dirname(os.path.abspath(__file__))
356 registry_headers_path = os.path.join(scripts_directory_path, args.scripts)
357 sys.path.insert(0, registry_headers_path)
359 from reg import *
360 from generator import write
361 from cgenerator import CGeneratorOptions, COutputGenerator
363 # Generator Modifications
364 from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator
365 from vulkan_tools_helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
366 from vulkaninfo_generator import VulkanInfoGenerator, VulkanInfoGeneratorOptions
367 # Temporary workaround for vkconventions python2 compatibility
368 import abc
369 abc.ABC = abc.ABCMeta('ABC', (object,), {})
370 from vkconventions import VulkanConventions
372 # This splits arguments which are space-separated lists
373 args.feature = [name for arg in args.feature for name in arg.split()]
374 args.extension = [name for arg in args.extension for name in arg.split()]
376 # create error/warning & diagnostic files
377 if (args.errfile):
378 errWarn = open(args.errfile, 'w', encoding='utf-8')
379 else:
380 errWarn = sys.stderr
382 if (args.diagfile):
383 diag = open(args.diagfile, 'w', encoding='utf-8')
384 else:
385 diag = None
387 # Create the API generator & generator options
388 (gen, options) = genTarget(args)
390 # Create the registry object with the specified generator and generator
391 # options. The options are set before XML loading as they may affect it.
392 reg = Registry(gen, options)
394 # Parse the specified registry XML into an ElementTree object
395 startTimer(args.time)
396 tree = etree.parse(args.registry)
397 endTimer(args.time, '* Time to make ElementTree =')
399 # Load the XML tree into the registry object
400 startTimer(args.time)
401 reg.loadElementTree(tree)
402 endTimer(args.time, '* Time to parse ElementTree =')
404 if (args.validate):
405 reg.validateGroups()
407 if (args.dump):
408 write('* Dumping registry to regdump.txt', file=sys.stderr)
409 reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
411 # Finally, use the output generator to create the requested target
412 if (args.debug):
413 pdb.run('reg.apiGen()')
414 else:
415 startTimer(args.time)
416 reg.apiGen()
417 endTimer(args.time, '* Time to generate ' + options.filename + ' =')
418 genTarget(args)