Merge pull request #31102 from akien-mga/vulkan
SCons: Streamline Vulkan buildsystem + fixups
This commit is contained in:
commit
c29d375088
|
@ -155,7 +155,7 @@ opts.Add(BoolVariable('builtin_pcre2_with_jit', "Use JIT compiler for the built-
|
|||
opts.Add(BoolVariable('builtin_recast', "Use the built-in Recast library", True))
|
||||
opts.Add(BoolVariable('builtin_rvo2', "Use the built-in RVO2 library", True))
|
||||
opts.Add(BoolVariable('builtin_squish', "Use the built-in squish library", True))
|
||||
opts.Add(BoolVariable('builtin_vulkan_loader', "Use the built-in Vulkan loader library", True))
|
||||
opts.Add(BoolVariable('builtin_vulkan', "Use the built-in Vulkan loader library and headers", True))
|
||||
opts.Add(BoolVariable('builtin_xatlas', "Use the built-in xatlas library", True))
|
||||
opts.Add(BoolVariable('builtin_zlib', "Use the built-in zlib library", True))
|
||||
opts.Add(BoolVariable('builtin_zstd', "Use the built-in Zstd library", True))
|
||||
|
|
|
@ -22,9 +22,6 @@ SConscript('alsamidi/SCsub')
|
|||
SConscript('coremidi/SCsub')
|
||||
SConscript('winmidi/SCsub')
|
||||
|
||||
if env["builtin_vulkan_loader"] and not (env["platform"]=="osx" and env['use_static_mvk']):
|
||||
SConscript('vulkan_loader/SCsub')
|
||||
|
||||
# Graphics drivers
|
||||
if (env["platform"] != "server"):
|
||||
# SConscript('gles3/SCsub')
|
||||
|
|
|
@ -2,7 +2,60 @@
|
|||
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.drivers_sources,"*.cpp")
|
||||
env.add_source_files(env.drivers_sources, "*.cpp")
|
||||
|
||||
if env['builtin_vulkan']:
|
||||
# Use bundled Vulkan headers
|
||||
thirdparty_dir = "#thirdparty/vulkan"
|
||||
env.Prepend(CPPPATH=[thirdparty_dir + "/include", thirdparty_dir + "/loader"])
|
||||
|
||||
#SConscript("shaders/SCsub")
|
||||
# Build Vulkan loader library
|
||||
env_thirdparty = env.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
||||
loader_sources = [
|
||||
"asm_offset.c",
|
||||
"cJSON.c",
|
||||
"debug_utils.c",
|
||||
"dev_ext_trampoline.c",
|
||||
"loader.c",
|
||||
"murmurhash.c",
|
||||
"phys_dev_ext.c",
|
||||
"trampoline.c",
|
||||
"unknown_ext_chain.c",
|
||||
"wsi.c",
|
||||
"extension_manual.c",
|
||||
]
|
||||
|
||||
if env['platform'] == "windows":
|
||||
loader_sources.append("dirent_on_windows.c")
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=[
|
||||
'VK_USE_PLATFORM_WIN32_KHR',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'WIN32_LEAN_AND_MEAN',
|
||||
'API_NAME=\\"%s\\"' % 'Vulkan'
|
||||
])
|
||||
if not env.msvc: # Windows 7+, missing in mingw headers
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=[
|
||||
"CM_GETIDLIST_FILTER_CLASS=0x00000200",
|
||||
"CM_GETIDLIST_FILTER_PRESENT=0x00000100"
|
||||
])
|
||||
elif env['platform'] == "osx":
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=[
|
||||
'VK_USE_PLATFORM_MACOS_MVK',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'SYSCONFDIR=\\"%s\\"' % '/etc',
|
||||
'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
|
||||
'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
|
||||
])
|
||||
elif env['platform'] == "x11":
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=[
|
||||
'VK_USE_PLATFORM_XLIB_KHR',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'SYSCONFDIR=\\"%s\\"' % '/etc',
|
||||
'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
|
||||
'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
|
||||
])
|
||||
|
||||
loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources]
|
||||
env_thirdparty.add_source_files(env.drivers_sources, loader_sources)
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import('env')
|
||||
|
||||
env_vlk_ldr = env.Clone()
|
||||
loader_dir = "#thirdparty/vulkan/loader/"
|
||||
loader_sources = [
|
||||
"asm_offset.c",
|
||||
"dev_ext_trampoline.c",
|
||||
"phys_dev_ext.c",
|
||||
"cJSON.c",
|
||||
"loader.c",
|
||||
"trampoline.c",
|
||||
"unknown_ext_chain.c",
|
||||
"wsi.c",
|
||||
"debug_utils.c",
|
||||
"extension_manual.c",
|
||||
"murmurhash.c"
|
||||
]
|
||||
|
||||
if (env_vlk_ldr["platform"]=="windows"):
|
||||
loader_sources.append("dirent_on_windows.c")
|
||||
env_vlk_ldr.AppendUnique(CPPDEFINES = [
|
||||
'VK_USE_PLATFORM_WIN32_KHR',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'WIN32_LEAN_AND_MEAN',
|
||||
'API_NAME=\\"%s\\"' % 'Vulkan'
|
||||
])
|
||||
if not env.msvc: #windows 7+, missing in mingw headers
|
||||
env_vlk_ldr.AppendUnique(CPPDEFINES = [
|
||||
"CM_GETIDLIST_FILTER_CLASS=0x00000200",
|
||||
"CM_GETIDLIST_FILTER_PRESENT=0x00000100"
|
||||
])
|
||||
elif (env_vlk_ldr["platform"]=="osx"):
|
||||
env_vlk_ldr.AppendUnique(CPPDEFINES = [
|
||||
'VK_USE_PLATFORM_MACOS_MVK',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'SYSCONFDIR=\\"%s\\"' % '/etc',
|
||||
'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
|
||||
'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
|
||||
])
|
||||
elif (env_vlk_ldr["platform"]=="x11"):
|
||||
env_vlk_ldr.AppendUnique(CPPDEFINES = [
|
||||
'VK_USE_PLATFORM_XLIB_KHR',
|
||||
'VULKAN_NON_CMAKE_BUILD',
|
||||
'SYSCONFDIR=\\"%s\\"' % '/etc',
|
||||
'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
|
||||
'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
|
||||
])
|
||||
loader_sources = [loader_dir + file for file in loader_sources]
|
||||
|
||||
env_thirdparty = env_vlk_ldr.Clone()
|
||||
env_thirdparty.add_source_files(env.drivers_sources, loader_sources)
|
||||
|
||||
env.Prepend(CPPPATH=[loader_dir])
|
|
@ -154,16 +154,15 @@ def configure(env):
|
|||
env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo', '-framework', 'AVFoundation', '-framework', 'CoreMedia'])
|
||||
env.Append(LIBS=['pthread', 'z'])
|
||||
|
||||
env.Prepend(CPPPATH=['#thirdparty/vulkan/include/', "#thirdparty/vulkan/registry/"])
|
||||
env.Append(CPPDEFINES=['VULKAN_ENABLED'])
|
||||
|
||||
#env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED'])
|
||||
|
||||
env.Append(LINKFLAGS=['-framework', 'Metal', '-framework', 'QuartzCore', '-framework', 'IOSurface'])
|
||||
if (env['use_static_mvk']):
|
||||
env.Append(LINKFLAGS=['-framework', 'MoltenVK'])
|
||||
elif not env["builtin_vulkan_loader"]:
|
||||
env['builtin_vulkan'] = False
|
||||
elif not env['builtin_vulkan']:
|
||||
env.Append(LIBS=['vulkan'])
|
||||
|
||||
#env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED'])
|
||||
|
||||
env.Append(CCFLAGS=['-mmacosx-version-min=10.11'])
|
||||
env.Append(LINKFLAGS=['-mmacosx-version-min=10.11'])
|
||||
|
|
|
@ -224,9 +224,8 @@ def configure_msvc(env, manual_msvc_config):
|
|||
'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt', 'Avrt',
|
||||
'dwmapi']
|
||||
|
||||
env.Prepend(CPPPATH=['#thirdparty/vulkan/include/', "#thirdparty/vulkan/registry/"])
|
||||
env.AppendUnique(CPPDEFINES = ['VULKAN_ENABLED'])
|
||||
if not env["builtin_vulkan_loader"]:
|
||||
env.AppendUnique(CPPDEFINES=['VULKAN_ENABLED'])
|
||||
if not env['builtin_vulkan']:
|
||||
LIBS += ['vulkan']
|
||||
else:
|
||||
LIBS += ['cfgmgr32']
|
||||
|
@ -361,13 +360,12 @@ def configure_mingw(env):
|
|||
env.Append(CPPDEFINES=[('WINVER', env['target_win_version']), ('_WIN32_WINNT', env['target_win_version'])])
|
||||
env.Append(LIBS=['mingw32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt', 'avrt', 'uuid', 'dwmapi'])
|
||||
|
||||
env.Prepend(CPPPATH=['#thirdparty/vulkan/include/', "#thirdparty/vulkan/registry/"])
|
||||
env.Append(CPPDEFINES=['VULKAN_ENABLED'])
|
||||
if not env["builtin_vulkan_loader"]:
|
||||
if not env['builtin_vulkan']:
|
||||
env.Append(LIBS=['vulkan'])
|
||||
else:
|
||||
env.Append(LIBS=['cfgmgr32'])
|
||||
|
||||
|
||||
## TODO !!! Reenable when OpenGLES Rendering Device is implemented !!!
|
||||
#env.Append(CPPDEFINES=['OPENGL_ENABLED'])
|
||||
env.Append(LIBS=['opengl32'])
|
||||
|
|
|
@ -320,10 +320,9 @@ def configure(env):
|
|||
env.Prepend(CPPPATH=['#platform/x11'])
|
||||
env.Append(CPPDEFINES=['X11_ENABLED', 'UNIX_ENABLED'])
|
||||
|
||||
env.Prepend(CPPPATH=['#thirdparty/vulkan/include/', "#thirdparty/vulkan/registry/"])
|
||||
env.Append(CPPDEFINES=['VULKAN_ENABLED'])
|
||||
if not env["builtin_vulkan_loader"]:
|
||||
env.Append(LIBS=['vulkan'])
|
||||
if not env['builtin_vulkan']:
|
||||
env.ParseConfig('pkg-config vulkan --cflags --libs')
|
||||
|
||||
#env.Append(CPPDEFINES=['OPENGL_ENABLED'])
|
||||
env.Append(LIBS=['GL'])
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# Third party libraries
|
||||
|
||||
Please keep categories (`##` level) listed alphabetically and matching their
|
||||
respective folder names. Use two empty lines to separate categories for
|
||||
readability.
|
||||
Subcategories (`###` level) where needed are separated by a single empty line.
|
||||
|
||||
|
||||
## assimp
|
||||
|
||||
|
@ -139,6 +144,7 @@ the GLES version Godot targets.
|
|||
Important: File `glslang/glslang/Include/Common.h` has
|
||||
Godot-made change marked with `// -- GODOT --` comments.
|
||||
|
||||
|
||||
## jpeg-compressor
|
||||
|
||||
- Upstream: https://github.com/richgel999/jpeg-compressor
|
||||
|
@ -259,25 +265,6 @@ changes to ensure they build for Javascript/HTML5. Those
|
|||
changes are marked with `// -- GODOT --` comments.
|
||||
|
||||
|
||||
## Vulkan Ecosystem Components (Vulkan ICD loader and headers)
|
||||
|
||||
- Upstream: https://github.com/KhronosGroup/Vulkan-Loader
|
||||
- Version: 1.1.113
|
||||
- License: Apache 2.0
|
||||
|
||||
|
||||
## wslay
|
||||
|
||||
- Upstream: https://github.com/tatsuhiro-t/wslay
|
||||
- Version: 1.1.0
|
||||
- License: MIT
|
||||
|
||||
File extracted from upstream release tarball:
|
||||
|
||||
- All `*.c` and `*.h` in `lib/` and `lib/includes/`
|
||||
- `wslay.h` has a small Godot addition to fix MSVC build.
|
||||
See `thirdparty/wslay/msvcfix.diff`
|
||||
|
||||
## mbedtls
|
||||
|
||||
- Upstream: https://tls.mbed.org/
|
||||
|
@ -528,6 +515,26 @@ They can be reapplied using the patches included in the `vhacd`
|
|||
folder.
|
||||
|
||||
|
||||
## vulkan
|
||||
|
||||
- Upstream: https://github.com/KhronosGroup/Vulkan-Loader
|
||||
- Version: 1.1.113
|
||||
- License: Apache 2.0
|
||||
|
||||
Unless there is a specific reason to package a more recent version, please stick
|
||||
to Vulkan SDK releases (prefixed by `sdk-`) for all components.
|
||||
|
||||
NOTE: Use `scripts/update_deps.py --ref <version>` in the Loader git repository
|
||||
to retrieve the `Vulkan-Headers` repository matching the loader version.
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- `Vulkan-Headers/include/` as `include/`
|
||||
- All `.c` and `.h` files in `loader/` and `loader/generated/`, put in a common
|
||||
`loader/` folder
|
||||
- `LICENSE.txt`
|
||||
|
||||
|
||||
## wslay
|
||||
|
||||
- Upstream: https://github.com/tatsuhiro-t/wslay
|
||||
|
|
|
@ -1,425 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from generator import (GeneratorOptions, OutputGenerator, noneStr,
|
||||
regSortFeatures, write)
|
||||
|
||||
# CGeneratorOptions - subclass of GeneratorOptions.
|
||||
#
|
||||
# Adds options used by COutputGenerator objects during C language header
|
||||
# generation.
|
||||
#
|
||||
# Additional members
|
||||
# prefixText - list of strings to prefix generated header with
|
||||
# (usually a copyright statement + calling convention macros).
|
||||
# protectFile - True if multiple inclusion protection should be
|
||||
# generated (based on the filename) around the entire header.
|
||||
# protectFeature - True if #ifndef..#endif protection should be
|
||||
# generated around a feature interface in the header file.
|
||||
# genFuncPointers - True if function pointer typedefs should be
|
||||
# generated
|
||||
# protectProto - If conditional protection should be generated
|
||||
# around prototype declarations, set to either '#ifdef'
|
||||
# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
|
||||
# to require opt-out (#ifndef protectProtoStr). Otherwise
|
||||
# set to None.
|
||||
# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
|
||||
# declarations, if protectProto is set
|
||||
# apicall - string to use for the function declaration prefix,
|
||||
# such as APICALL on Windows.
|
||||
# apientry - string to use for the calling convention macro,
|
||||
# in typedefs, such as APIENTRY.
|
||||
# apientryp - string to use for the calling convention macro
|
||||
# in function pointer typedefs, such as APIENTRYP.
|
||||
# directory - directory into which to generate include files
|
||||
# indentFuncProto - True if prototype declarations should put each
|
||||
# parameter on a separate line
|
||||
# indentFuncPointer - True if typedefed function pointers should put each
|
||||
# parameter on a separate line
|
||||
# alignFuncParam - if nonzero and parameters are being put on a
|
||||
# separate line, align parameter names at the specified column
|
||||
# genEnumBeginEndRange - True if BEGIN_RANGE / END_RANGE macros should
|
||||
# be generated for enumerated types
|
||||
# genAliasMacro - True if the OpenXR alias macro should be generated
|
||||
# for aliased types (unclear what other circumstances this is useful)
|
||||
# aliasMacro - alias macro to inject when genAliasMacro is True
|
||||
class CGeneratorOptions(GeneratorOptions):
|
||||
"""Represents options during C interface generation for headers"""
|
||||
|
||||
def __init__(self,
|
||||
conventions = None,
|
||||
filename = None,
|
||||
directory = '.',
|
||||
apiname = None,
|
||||
profile = None,
|
||||
versions = '.*',
|
||||
emitversions = '.*',
|
||||
defaultExtensions = None,
|
||||
addExtensions = None,
|
||||
removeExtensions = None,
|
||||
emitExtensions = None,
|
||||
sortProcedure = regSortFeatures,
|
||||
prefixText = "",
|
||||
genFuncPointers = True,
|
||||
protectFile = True,
|
||||
protectFeature = True,
|
||||
protectProto = None,
|
||||
protectProtoStr = None,
|
||||
apicall = '',
|
||||
apientry = '',
|
||||
apientryp = '',
|
||||
indentFuncProto = True,
|
||||
indentFuncPointer = False,
|
||||
alignFuncParam = 0,
|
||||
genEnumBeginEndRange = False,
|
||||
genAliasMacro = False,
|
||||
aliasMacro = ''
|
||||
):
|
||||
GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
|
||||
versions, emitversions, defaultExtensions,
|
||||
addExtensions, removeExtensions,
|
||||
emitExtensions, sortProcedure)
|
||||
self.prefixText = prefixText
|
||||
self.genFuncPointers = genFuncPointers
|
||||
self.protectFile = protectFile
|
||||
self.protectFeature = protectFeature
|
||||
self.protectProto = protectProto
|
||||
self.protectProtoStr = protectProtoStr
|
||||
self.apicall = apicall
|
||||
self.apientry = apientry
|
||||
self.apientryp = apientryp
|
||||
self.indentFuncProto = indentFuncProto
|
||||
self.indentFuncPointer = indentFuncPointer
|
||||
self.alignFuncParam = alignFuncParam
|
||||
self.genEnumBeginEndRange = genEnumBeginEndRange
|
||||
self.genAliasMacro = genAliasMacro
|
||||
self.aliasMacro = aliasMacro
|
||||
|
||||
# COutputGenerator - subclass of OutputGenerator.
|
||||
# Generates C-language API interfaces.
|
||||
#
|
||||
# ---- methods ----
|
||||
# COutputGenerator(errFile, warnFile, diagFile) - args as for
|
||||
# OutputGenerator. Defines additional internal state.
|
||||
# ---- methods overriding base class ----
|
||||
# beginFile(genOpts)
|
||||
# endFile()
|
||||
# beginFeature(interface, emit)
|
||||
# endFeature()
|
||||
# genType(typeinfo,name)
|
||||
# genStruct(typeinfo,name)
|
||||
# genGroup(groupinfo,name)
|
||||
# genEnum(enuminfo, name)
|
||||
# genCmd(cmdinfo)
|
||||
class COutputGenerator(OutputGenerator):
|
||||
"""Generate specified API interfaces in a specific style, such as a C header"""
|
||||
# This is an ordered list of sections in the header file.
|
||||
TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
|
||||
'group', 'bitmask', 'funcpointer', 'struct']
|
||||
ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
|
||||
|
||||
def __init__(self,
|
||||
errFile = sys.stderr,
|
||||
warnFile = sys.stderr,
|
||||
diagFile = sys.stdout):
|
||||
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
||||
# Internal state - accumulators for different inner block text
|
||||
self.sections = {section: [] for section in self.ALL_SECTIONS}
|
||||
self.feature_not_empty = False
|
||||
self.need_platform_include = False
|
||||
self.may_alias = None
|
||||
|
||||
def beginFile(self, genOpts):
|
||||
OutputGenerator.beginFile(self, genOpts)
|
||||
# C-specific
|
||||
#
|
||||
# Multiple inclusion protection & C++ wrappers.
|
||||
if genOpts.protectFile and self.genOpts.filename:
|
||||
headerSym = re.sub(r'\.h', '_h_',
|
||||
os.path.basename(self.genOpts.filename)).upper()
|
||||
write('#ifndef', headerSym, file=self.outFile)
|
||||
write('#define', headerSym, '1', file=self.outFile)
|
||||
self.newline()
|
||||
write('#ifdef __cplusplus', file=self.outFile)
|
||||
write('extern "C" {', file=self.outFile)
|
||||
write('#endif', file=self.outFile)
|
||||
self.newline()
|
||||
|
||||
# User-supplied prefix text, if any (list of strings)
|
||||
if genOpts.prefixText:
|
||||
for s in genOpts.prefixText:
|
||||
write(s, file=self.outFile)
|
||||
|
||||
def endFile(self):
|
||||
# C-specific
|
||||
# Finish C++ wrapper and multiple inclusion protection
|
||||
self.newline()
|
||||
write('#ifdef __cplusplus', file=self.outFile)
|
||||
write('}', file=self.outFile)
|
||||
write('#endif', file=self.outFile)
|
||||
if self.genOpts.protectFile and self.genOpts.filename:
|
||||
self.newline()
|
||||
write('#endif', file=self.outFile)
|
||||
# Finish processing in superclass
|
||||
OutputGenerator.endFile(self)
|
||||
|
||||
def beginFeature(self, interface, emit):
|
||||
# Start processing in superclass
|
||||
OutputGenerator.beginFeature(self, interface, emit)
|
||||
# C-specific
|
||||
# Accumulate includes, defines, types, enums, function pointer typedefs,
|
||||
# end function prototypes separately for this feature. They're only
|
||||
# printed in endFeature().
|
||||
self.sections = {section: [] for section in self.ALL_SECTIONS}
|
||||
self.feature_not_empty = False
|
||||
|
||||
def endFeature(self):
|
||||
# C-specific
|
||||
# Actually write the interface to the output file.
|
||||
if self.emit:
|
||||
if self.feature_not_empty:
|
||||
if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
|
||||
self.newline()
|
||||
if self.genOpts.protectFeature:
|
||||
write('#ifndef', self.featureName, file=self.outFile)
|
||||
# If type declarations are needed by other features based on
|
||||
# this one, it may be necessary to suppress the ExtraProtect,
|
||||
# or move it below the 'for section...' loop.
|
||||
if self.featureExtraProtect is not None:
|
||||
write('#ifdef', self.featureExtraProtect, file=self.outFile)
|
||||
self.newline()
|
||||
write('#define', self.featureName, '1', file=self.outFile)
|
||||
for section in self.TYPE_SECTIONS:
|
||||
# OpenXR:
|
||||
# If we need the explicit include of the external platform header,
|
||||
# put it right before the function pointer definitions
|
||||
if section == "funcpointer" and self.need_platform_include:
|
||||
write('// Include for OpenXR Platform-Specific Types', file=self.outFile)
|
||||
write('#include "openxr_platform.h"', file=self.outFile)
|
||||
self.newline()
|
||||
self.need_platform_include = False
|
||||
contents = self.sections[section]
|
||||
if contents:
|
||||
write('\n'.join(contents), file=self.outFile)
|
||||
if self.genOpts.genFuncPointers and self.sections['commandPointer']:
|
||||
write('\n'.join(self.sections['commandPointer']), file=self.outFile)
|
||||
self.newline()
|
||||
if self.sections['command']:
|
||||
if self.genOpts.protectProto:
|
||||
write(self.genOpts.protectProto,
|
||||
self.genOpts.protectProtoStr, file=self.outFile)
|
||||
write('\n'.join(self.sections['command']), end='', file=self.outFile)
|
||||
if self.genOpts.protectProto:
|
||||
write('#endif', file=self.outFile)
|
||||
else:
|
||||
self.newline()
|
||||
if self.featureExtraProtect is not None:
|
||||
write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
|
||||
if self.genOpts.protectFeature:
|
||||
write('#endif /*', self.featureName, '*/', file=self.outFile)
|
||||
# Finish processing in superclass
|
||||
OutputGenerator.endFeature(self)
|
||||
|
||||
# Append a definition to the specified section
|
||||
def appendSection(self, section, text):
|
||||
# self.sections[section].append('SECTION: ' + section + '\n')
|
||||
self.sections[section].append(text)
|
||||
self.feature_not_empty = True
|
||||
|
||||
# Type generation
|
||||
def genType(self, typeinfo, name, alias):
|
||||
OutputGenerator.genType(self, typeinfo, name, alias)
|
||||
typeElem = typeinfo.elem
|
||||
|
||||
# Vulkan:
|
||||
# Determine the category of the type, and the type section to add
|
||||
# its definition to.
|
||||
# 'funcpointer' is added to the 'struct' section as a workaround for
|
||||
# internal issue #877, since structures and function pointer types
|
||||
# can have cross-dependencies.
|
||||
category = typeElem.get('category')
|
||||
if category == 'funcpointer':
|
||||
section = 'struct'
|
||||
else:
|
||||
section = category
|
||||
|
||||
if category in ('struct', 'union'):
|
||||
# If the type is a struct type, generate it using the
|
||||
# special-purpose generator.
|
||||
self.genStruct(typeinfo, name, alias)
|
||||
else:
|
||||
# OpenXR: this section was not under 'else:' previously, just fell through
|
||||
if alias:
|
||||
# If the type is an alias, just emit a typedef declaration
|
||||
body = 'typedef ' + alias + ' ' + name + ';\n'
|
||||
else:
|
||||
# Replace <apientry /> tags with an APIENTRY-style string
|
||||
# (from self.genOpts). Copy other text through unchanged.
|
||||
# If the resulting text is an empty string, don't emit it.
|
||||
body = noneStr(typeElem.text)
|
||||
for elem in typeElem:
|
||||
if elem.tag == 'apientry':
|
||||
body += self.genOpts.apientry + noneStr(elem.tail)
|
||||
else:
|
||||
body += noneStr(elem.text) + noneStr(elem.tail)
|
||||
if body:
|
||||
# Add extra newline after multi-line entries.
|
||||
if '\n' in body[0:-1]:
|
||||
body += '\n'
|
||||
self.appendSection(section, body)
|
||||
|
||||
# Protection string generation
|
||||
# Protection strings are the strings defining the OS/Platform/Graphics
|
||||
# requirements for a given OpenXR command. When generating the
|
||||
# language header files, we need to make sure the items specific to a
|
||||
# graphics API or OS platform are properly wrapped in #ifs.
|
||||
def genProtectString(self, protect_str):
|
||||
protect_if_str = ''
|
||||
protect_end_str = ''
|
||||
protect_list = []
|
||||
if protect_str:
|
||||
if ',' in protect_str:
|
||||
protect_list.extend(protect_str.split(","))
|
||||
protect_def_str = ''
|
||||
count = 0
|
||||
for protect_define in protect_list:
|
||||
if count > 0:
|
||||
protect_def_str += ' &&'
|
||||
protect_def_str += ' defined(%s)' % protect_define
|
||||
count = count + 1
|
||||
count = count + 1
|
||||
protect_if_str = '#if'
|
||||
protect_if_str += protect_def_str
|
||||
protect_if_str += '\n'
|
||||
protect_end_str = '#endif //'
|
||||
protect_end_str += protect_def_str
|
||||
protect_end_str += '\n'
|
||||
else:
|
||||
protect_if_str += '#ifdef %s\n' % protect_str
|
||||
protect_end_str += '#endif // %s\n' % protect_str
|
||||
return (protect_if_str, protect_end_str)
|
||||
|
||||
def typeMayAlias(self, typeName):
|
||||
if not self.may_alias:
|
||||
# First time we've asked if a type may alias.
|
||||
# So, let's populate the set of all names of types that may.
|
||||
|
||||
# Everyone with an explicit mayalias="true"
|
||||
self.may_alias = set(typeName
|
||||
for typeName, data in self.registry.typedict.items()
|
||||
if data.elem.get('mayalias') == 'true')
|
||||
|
||||
# Every type mentioned in some other type's parentstruct attribute.
|
||||
self.may_alias.update(set(x for x in
|
||||
[otherType.elem.get('parentstruct')
|
||||
for _, otherType in self.registry.typedict.items()]
|
||||
if x is not None
|
||||
))
|
||||
return typeName in self.may_alias
|
||||
|
||||
# Struct (e.g. C "struct" type) generation.
|
||||
# This is a special case of the <type> tag where the contents are
|
||||
# interpreted as a set of <member> tags instead of freeform C
|
||||
# C type declarations. The <member> tags are just like <param>
|
||||
# tags - they are a declaration of a struct or union member.
|
||||
# Only simple member declarations are supported (no nested
|
||||
# structs etc.)
|
||||
# If alias is not None, then this struct aliases another; just
|
||||
# generate a typedef of that alias.
|
||||
def genStruct(self, typeinfo, typeName, alias):
|
||||
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
|
||||
|
||||
typeElem = typeinfo.elem
|
||||
|
||||
if alias:
|
||||
body = 'typedef ' + alias + ' ' + typeName + ';\n'
|
||||
else:
|
||||
body = ''
|
||||
(protect_begin, protect_end) = self.genProtectString(typeElem.get('protect'))
|
||||
if protect_begin:
|
||||
body += protect_begin
|
||||
body += 'typedef ' + typeElem.get('category')
|
||||
|
||||
# This is an OpenXR-specific alternative where aliasing refers
|
||||
# to an inheritance hierarchy of types rather than C-level type
|
||||
# aliases.
|
||||
if self.genOpts.genAliasMacro and self.typeMayAlias(typeName):
|
||||
body += ' ' + self.genOpts.aliasMacro
|
||||
|
||||
body += ' ' + typeName + ' {\n'
|
||||
|
||||
targetLen = 0
|
||||
for member in typeElem.findall('.//member'):
|
||||
targetLen = max(targetLen, self.getCParamTypeLength(member))
|
||||
for member in typeElem.findall('.//member'):
|
||||
body += self.makeCParamDecl(member, targetLen + 4)
|
||||
body += ';\n'
|
||||
body += '} ' + typeName + ';\n'
|
||||
if protect_end:
|
||||
body += protect_end
|
||||
|
||||
self.appendSection('struct', body)
|
||||
|
||||
# Group (e.g. C "enum" type) generation.
|
||||
# These are concatenated together with other types.
|
||||
# If alias is not None, it is the name of another group type
|
||||
# which aliases this type; just generate that alias.
|
||||
def genGroup(self, groupinfo, groupName, alias = None):
|
||||
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
|
||||
groupElem = groupinfo.elem
|
||||
|
||||
# After either enumerated type or alias paths, add the declaration
|
||||
# to the appropriate section for the group being defined.
|
||||
if groupElem.get('type') == 'bitmask':
|
||||
section = 'bitmask'
|
||||
else:
|
||||
section = 'group'
|
||||
|
||||
if alias:
|
||||
# If the group name is aliased, just emit a typedef declaration
|
||||
# for the alias.
|
||||
body = 'typedef ' + alias + ' ' + groupName + ';\n'
|
||||
self.appendSection(section, body)
|
||||
else:
|
||||
(section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName)
|
||||
self.appendSection(section, "\n" + body)
|
||||
|
||||
# Enumerant generation
|
||||
# <enum> tags may specify their values in several ways, but are usually
|
||||
# just integers.
|
||||
def genEnum(self, enuminfo, name, alias):
|
||||
OutputGenerator.genEnum(self, enuminfo, name, alias)
|
||||
(_, strVal) = self.enumToValue(enuminfo.elem, False)
|
||||
body = '#define ' + name.ljust(33) + ' ' + strVal
|
||||
self.appendSection('enum', body)
|
||||
|
||||
# Command generation
|
||||
def genCmd(self, cmdinfo, name, alias):
|
||||
OutputGenerator.genCmd(self, cmdinfo, name, alias)
|
||||
|
||||
# if alias:
|
||||
# prefix = '// ' + name + ' is an alias of command ' + alias + '\n'
|
||||
# else:
|
||||
# prefix = ''
|
||||
|
||||
prefix = ''
|
||||
decls = self.makeCDecls(cmdinfo.elem)
|
||||
self.appendSection('command', prefix + decls[0] + '\n')
|
||||
if self.genOpts.genFuncPointers:
|
||||
self.appendSection('commandPointer', decls[1])
|
|
@ -1,73 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2015-2017, 2019 The Khronos Group Inc.
|
||||
# Copyright (c) 2015-2017, 2019 Valve Corporation
|
||||
# Copyright (c) 2015-2017, 2019 LunarG, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Author: Mark Lobodzinski <mark@lunarg.com>
|
||||
|
||||
import os,re,sys,string
|
||||
import xml.etree.ElementTree as etree
|
||||
from generator import *
|
||||
from collections import namedtuple
|
||||
|
||||
# Copyright text prefixing all headers (list of strings).
|
||||
prefixStrings = [
|
||||
'/*',
|
||||
'** Copyright (c) 2015-2017, 2019 The Khronos Group Inc.',
|
||||
'** Copyright (c) 2015-2017, 2019 Valve Corporation',
|
||||
'** Copyright (c) 2015-2017, 2019 LunarG, Inc.',
|
||||
'** Copyright (c) 2015-2017, 2019 Google Inc.',
|
||||
'**',
|
||||
'** Licensed under the Apache License, Version 2.0 (the "License");',
|
||||
'** you may not use this file except in compliance with the License.',
|
||||
'** You may obtain a copy of the License at',
|
||||
'**',
|
||||
'** http://www.apache.org/licenses/LICENSE-2.0',
|
||||
'**',
|
||||
'** Unless required by applicable law or agreed to in writing, software',
|
||||
'** distributed under the License is distributed on an "AS IS" BASIS,',
|
||||
'** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
||||
'** See the License for the specific language governing permissions and',
|
||||
'** limitations under the License.',
|
||||
'*/',
|
||||
''
|
||||
]
|
||||
|
||||
|
||||
platform_dict = {
|
||||
'android' : 'VK_USE_PLATFORM_ANDROID_KHR',
|
||||
'fuchsia' : 'VK_USE_PLATFORM_FUCHSIA',
|
||||
'ggp': 'VK_USE_PLATFORM_GGP',
|
||||
'ios' : 'VK_USE_PLATFORM_IOS_MVK',
|
||||
'macos' : 'VK_USE_PLATFORM_MACOS_MVK',
|
||||
'metal' : 'VK_USE_PLATFORM_METAL_EXT',
|
||||
'vi' : 'VK_USE_PLATFORM_VI_NN',
|
||||
'wayland' : 'VK_USE_PLATFORM_WAYLAND_KHR',
|
||||
'win32' : 'VK_USE_PLATFORM_WIN32_KHR',
|
||||
'xcb' : 'VK_USE_PLATFORM_XCB_KHR',
|
||||
'xlib' : 'VK_USE_PLATFORM_XLIB_KHR',
|
||||
'xlib_xrandr' : 'VK_USE_PLATFORM_XLIB_XRANDR_EXT',
|
||||
}
|
||||
|
||||
#
|
||||
# Return appropriate feature protect string from 'platform' tag on feature
|
||||
def GetFeatureProtect(interface):
|
||||
"""Get platform protection string"""
|
||||
platform = interface.get('platform')
|
||||
protect = None
|
||||
if platform is not None:
|
||||
protect = platform_dict[platform]
|
||||
return protect
|
|
@ -1,132 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Base class for working-group-specific style conventions,
|
||||
# used in generation.
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
ABC = ABCMeta('ABC', (object,), {})
|
||||
|
||||
class ConventionsBase(ABC):
|
||||
"""WG-specific conventions."""
|
||||
|
||||
@abstractmethod
|
||||
def formatExtension(self, name):
|
||||
"""Mark up a name as an extension for the spec."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def null(self):
|
||||
"""Preferred spelling of NULL."""
|
||||
raise NotImplementedError
|
||||
|
||||
def makeProseList(self, elements, connective='and'):
|
||||
"""Make a (comma-separated) list for use in prose.
|
||||
|
||||
Adds a connective (by default, 'and')
|
||||
before the last element if there are more than 1.
|
||||
|
||||
Override with a different method or different call to
|
||||
_implMakeProseList if you want to add a comma for two elements,
|
||||
or not use a serial comma.
|
||||
"""
|
||||
return self._implMakeProseList(elements, connective)
|
||||
|
||||
@property
|
||||
def struct_macro(self):
|
||||
"""Get the appropriate format macro for a structure.
|
||||
|
||||
May override.
|
||||
"""
|
||||
return 'sname:'
|
||||
|
||||
def makeStructName(self, name):
|
||||
"""Prepend the appropriate format macro for a structure to a structure type name.
|
||||
|
||||
Uses struct_macro, so just override that if you want to change behavior.
|
||||
"""
|
||||
return self.struct_macro + name
|
||||
|
||||
@property
|
||||
def external_macro(self):
|
||||
"""Get the appropriate format macro for an external type like uint32_t.
|
||||
|
||||
May override.
|
||||
"""
|
||||
return 'basetype:'
|
||||
|
||||
def makeExternalTypeName(self, name):
|
||||
"""Prepend the appropriate format macro for an external type like uint32_t to a type name.
|
||||
|
||||
Uses external_macro, so just override that if you want to change behavior.
|
||||
"""
|
||||
return self.external_macro + name
|
||||
|
||||
def _implMakeProseList(self, elements, connective, comma_for_two_elts=False, serial_comma=True):
|
||||
"""Internal-use implementation to make a (comma-separated) list for use in prose.
|
||||
|
||||
Adds a connective (by default, 'and')
|
||||
before the last element if there are more than 1,
|
||||
and only includes commas if there are more than 2
|
||||
(if comma_for_two_elts is False).
|
||||
|
||||
Don't edit these defaults, override self.makeProseList().
|
||||
"""
|
||||
assert(serial_comma) # didn't implement what we didn't need
|
||||
my_elts = list(elements)
|
||||
if len(my_elts) > 1:
|
||||
my_elts[-1] = '{} {}'.format(connective, my_elts[-1])
|
||||
|
||||
if not comma_for_two_elts and len(my_elts) <= 2:
|
||||
return ' '.join(my_elts)
|
||||
return ', '.join(my_elts)
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def file_suffix(self):
|
||||
"""Return suffix of generated Asciidoctor files"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def api_name(self, spectype = None):
|
||||
"""Return API name"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def api_prefix(self):
|
||||
"""Return API token prefix"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def api_version_prefix(self):
|
||||
"""Return API core version token prefix"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def KHR_prefix(self):
|
||||
"""Return extension name prefix for KHR extensions"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def EXT_prefix(self):
|
||||
"""Return extension name prefix for EXT extensions"""
|
||||
raise NotImplementedError
|
|
@ -1,240 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2015-2017 The Khronos Group Inc.
|
||||
# Copyright (c) 2015-2017 Valve Corporation
|
||||
# Copyright (c) 2015-2017 LunarG, Inc.
|
||||
# Copyright (c) 2015-2017 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Author: Mark Lobodzinski <mark@lunarg.com>
|
||||
|
||||
import os,re,sys
|
||||
import xml.etree.ElementTree as etree
|
||||
from generator import *
|
||||
from collections import namedtuple
|
||||
from common_codegen import *
|
||||
|
||||
#
|
||||
# DispatchTableHelperOutputGeneratorOptions - subclass of GeneratorOptions.
|
||||
class DispatchTableHelperOutputGeneratorOptions(GeneratorOptions):
|
||||
def __init__(self,
|
||||
conventions = None,
|
||||
filename = None,
|
||||
directory = '.',
|
||||
apiname = None,
|
||||
profile = None,
|
||||
versions = '.*',
|
||||
emitversions = '.*',
|
||||
defaultExtensions = None,
|
||||
addExtensions = None,
|
||||
removeExtensions = None,
|
||||
emitExtensions = None,
|
||||
sortProcedure = regSortFeatures,
|
||||
prefixText = "",
|
||||
genFuncPointers = True,
|
||||
apicall = '',
|
||||
apientry = '',
|
||||
apientryp = '',
|
||||
alignFuncParam = 0,
|
||||
expandEnumerants = True):
|
||||
GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
|
||||
versions, emitversions, defaultExtensions,
|
||||
addExtensions, removeExtensions, emitExtensions, sortProcedure)
|
||||
self.prefixText = prefixText
|
||||
self.genFuncPointers = genFuncPointers
|
||||
self.prefixText = None
|
||||
self.apicall = apicall
|
||||
self.apientry = apientry
|
||||
self.apientryp = apientryp
|
||||
self.alignFuncParam = alignFuncParam
|
||||
#
|
||||
# DispatchTableHelperOutputGenerator - subclass of OutputGenerator.
|
||||
# Generates dispatch table helper header files for LVL
|
||||
class DispatchTableHelperOutputGenerator(OutputGenerator):
|
||||
"""Generate dispatch table helper header based on XML element attributes"""
|
||||
def __init__(self,
|
||||
errFile = sys.stderr,
|
||||
warnFile = sys.stderr,
|
||||
diagFile = sys.stdout):
|
||||
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
||||
# Internal state - accumulators for different inner block text
|
||||
self.instance_dispatch_list = [] # List of entries for instance dispatch list
|
||||
self.device_dispatch_list = [] # List of entries for device dispatch list
|
||||
self.dev_ext_stub_list = [] # List of stub functions for device extension functions
|
||||
self.device_extension_list = [] # List of device extension functions
|
||||
self.extension_type = ''
|
||||
#
|
||||
# Called once at the beginning of each run
|
||||
def beginFile(self, genOpts):
|
||||
OutputGenerator.beginFile(self, genOpts)
|
||||
write("#pragma once", file=self.outFile)
|
||||
# User-supplied prefix text, if any (list of strings)
|
||||
if (genOpts.prefixText):
|
||||
for s in genOpts.prefixText:
|
||||
write(s, file=self.outFile)
|
||||
# File Comment
|
||||
file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
|
||||
file_comment += '// See dispatch_helper_generator.py for modifications\n'
|
||||
write(file_comment, file=self.outFile)
|
||||
# Copyright Notice
|
||||
copyright = '/*\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
|
||||
copyright += ' * you may not use this file except in compliance with the License.\n'
|
||||
copyright += ' * You may obtain a copy of the License at\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
|
||||
copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
|
||||
copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
|
||||
copyright += ' * See the License for the specific language governing permissions and\n'
|
||||
copyright += ' * limitations under the License.\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>\n'
|
||||
copyright += ' * Author: Jon Ashburn <jon@lunarg.com>\n'
|
||||
copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
|
||||
copyright += ' */\n'
|
||||
|
||||
preamble = ''
|
||||
preamble += '#include <vulkan/vulkan.h>\n'
|
||||
preamble += '#include <vulkan/vk_layer.h>\n'
|
||||
preamble += '#include <string.h>\n'
|
||||
preamble += '#include "vk_layer_dispatch_table.h"\n'
|
||||
|
||||
write(copyright, file=self.outFile)
|
||||
write(preamble, file=self.outFile)
|
||||
#
|
||||
# Write generate and write dispatch tables to output file
|
||||
def endFile(self):
|
||||
device_table = ''
|
||||
instance_table = ''
|
||||
|
||||
device_table += self.OutputDispatchTableHelper('device')
|
||||
instance_table += self.OutputDispatchTableHelper('instance')
|
||||
|
||||
for stub in self.dev_ext_stub_list:
|
||||
write(stub, file=self.outFile)
|
||||
write("\n\n", file=self.outFile)
|
||||
write(device_table, file=self.outFile);
|
||||
write("\n", file=self.outFile)
|
||||
write(instance_table, file=self.outFile);
|
||||
|
||||
# Finish processing in superclass
|
||||
OutputGenerator.endFile(self)
|
||||
#
|
||||
# Processing at beginning of each feature or extension
|
||||
def beginFeature(self, interface, emit):
|
||||
OutputGenerator.beginFeature(self, interface, emit)
|
||||
self.featureExtraProtect = GetFeatureProtect(interface)
|
||||
self.extension_type = interface.get('type')
|
||||
|
||||
#
|
||||
# Process commands, adding to appropriate dispatch tables
|
||||
def genCmd(self, cmdinfo, name, alias):
|
||||
OutputGenerator.genCmd(self, cmdinfo, name, alias)
|
||||
|
||||
avoid_entries = ['vkCreateInstance',
|
||||
'vkCreateDevice']
|
||||
# Get first param type
|
||||
params = cmdinfo.elem.findall('param')
|
||||
info = self.getTypeNameTuple(params[0])
|
||||
|
||||
if name not in avoid_entries:
|
||||
self.AddCommandToDispatchList(name, info[0], self.featureExtraProtect, cmdinfo)
|
||||
|
||||
#
|
||||
# Determine if this API should be ignored or added to the instance or device dispatch table
|
||||
def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo):
|
||||
handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
|
||||
if handle is None:
|
||||
return
|
||||
if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
|
||||
self.device_dispatch_list.append((name, self.featureExtraProtect))
|
||||
if "VK_VERSION" not in self.featureName and self.extension_type == 'device':
|
||||
self.device_extension_list.append(name)
|
||||
# Build up stub function
|
||||
return_type = ''
|
||||
decl = self.makeCDecls(cmdinfo.elem)[1]
|
||||
if 'typedef VkResult' in decl:
|
||||
return_type = 'return VK_SUCCESS;'
|
||||
decl = decl.split('*PFN_vk')[1]
|
||||
decl = decl.replace(')(', '(')
|
||||
if return_type == '':
|
||||
decl = 'static VKAPI_ATTR void VKAPI_CALL Stub' + decl
|
||||
else:
|
||||
decl = 'static VKAPI_ATTR VkResult VKAPI_CALL Stub' + decl
|
||||
func_body = ' { ' + return_type + ' };'
|
||||
decl = decl.replace (';', func_body)
|
||||
if self.featureExtraProtect is not None:
|
||||
self.dev_ext_stub_list.append('#ifdef %s' % self.featureExtraProtect)
|
||||
self.dev_ext_stub_list.append(decl)
|
||||
if self.featureExtraProtect is not None:
|
||||
self.dev_ext_stub_list.append('#endif // %s' % self.featureExtraProtect)
|
||||
else:
|
||||
self.instance_dispatch_list.append((name, self.featureExtraProtect))
|
||||
return
|
||||
#
|
||||
# Retrieve the type and name for a parameter
|
||||
def getTypeNameTuple(self, param):
|
||||
type = ''
|
||||
name = ''
|
||||
for elem in param:
|
||||
if elem.tag == 'type':
|
||||
type = noneStr(elem.text)
|
||||
elif elem.tag == 'name':
|
||||
name = noneStr(elem.text)
|
||||
return (type, name)
|
||||
#
|
||||
# Create a dispatch table from the appropriate list and return it as a string
|
||||
def OutputDispatchTableHelper(self, table_type):
|
||||
entries = []
|
||||
table = ''
|
||||
if table_type == 'device':
|
||||
entries = self.device_dispatch_list
|
||||
table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n'
|
||||
table += ' memset(table, 0, sizeof(*table));\n'
|
||||
table += ' // Device function pointers\n'
|
||||
else:
|
||||
entries = self.instance_dispatch_list
|
||||
table += 'static inline void layer_init_instance_dispatch_table(VkInstance instance, VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa) {\n'
|
||||
table += ' memset(table, 0, sizeof(*table));\n'
|
||||
table += ' // Instance function pointers\n'
|
||||
|
||||
for item in entries:
|
||||
# Remove 'vk' from proto name
|
||||
base_name = item[0][2:]
|
||||
|
||||
if item[1] is not None:
|
||||
table += '#ifdef %s\n' % item[1]
|
||||
|
||||
# If we're looking for the proc we are passing in, just point the table to it. This fixes the issue where
|
||||
# a layer overrides the function name for the loader.
|
||||
if (table_type == 'device' and base_name == 'GetDeviceProcAddr'):
|
||||
table += ' table->GetDeviceProcAddr = gpa;\n'
|
||||
elif (table_type != 'device' and base_name == 'GetInstanceProcAddr'):
|
||||
table += ' table->GetInstanceProcAddr = gpa;\n'
|
||||
else:
|
||||
table += ' table->%s = (PFN_%s) gpa(%s, "%s");\n' % (base_name, item[0], table_type, item[0])
|
||||
if item[0] in self.device_extension_list:
|
||||
stub_check = ' if (table->%s == nullptr) { table->%s = (PFN_%s)Stub%s; }\n' % (base_name, base_name, item[0], base_name)
|
||||
table += stub_check
|
||||
if item[1] is not None:
|
||||
table += '#endif // %s\n' % item[1]
|
||||
|
||||
table += '}'
|
||||
return table
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
python loader_genvk.py -registry vk.xml -scripts . vk_layer_dispatch_table.h
|
||||
python loader_genvk.py -registry vk.xml -scripts . vk_dispatch_table_helper.h
|
||||
python loader_genvk.py -registry vk.xml -scripts . vk_object_types.h
|
||||
python loader_genvk.py -registry vk.xml -scripts . vk_loader_extensions.h
|
||||
python loader_genvk.py -registry vk.xml -scripts . vk_loader_extensions.c
|
||||
mv ./*.c ../loader/
|
||||
mv ./*.h ../loader/
|
|
@ -1,738 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import pdb
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def write( *args, **kwargs ):
|
||||
file = kwargs.pop('file',sys.stdout)
|
||||
end = kwargs.pop('end','\n')
|
||||
file.write(' '.join(str(arg) for arg in args))
|
||||
file.write(end)
|
||||
|
||||
# noneStr - returns string argument, or "" if argument is None.
|
||||
# Used in converting etree Elements into text.
|
||||
# s - string to convert
|
||||
def noneStr(s):
|
||||
if s:
|
||||
return s
|
||||
return ""
|
||||
|
||||
# enquote - returns string argument with surrounding quotes,
|
||||
# for serialization into Python code.
|
||||
def enquote(s):
|
||||
if s:
|
||||
return "'{}'".format(s)
|
||||
return None
|
||||
|
||||
# Primary sort key for regSortFeatures.
|
||||
# Sorts by category of the feature name string:
|
||||
# Core API features (those defined with a <feature> tag)
|
||||
# ARB/KHR/OES (Khronos extensions)
|
||||
# other (EXT/vendor extensions)
|
||||
# This will need changing for Vulkan!
|
||||
def regSortCategoryKey(feature):
|
||||
if feature.elem.tag == 'feature':
|
||||
return 0
|
||||
if (feature.category == 'ARB' or
|
||||
feature.category == 'KHR' or
|
||||
feature.category == 'OES'):
|
||||
return 1
|
||||
|
||||
return 2
|
||||
|
||||
# Secondary sort key for regSortFeatures.
|
||||
# Sorts by extension name.
|
||||
def regSortNameKey(feature):
|
||||
return feature.name
|
||||
|
||||
# Second sort key for regSortFeatures.
|
||||
# Sorts by feature version. <extension> elements all have version number "0"
|
||||
def regSortFeatureVersionKey(feature):
|
||||
return float(feature.versionNumber)
|
||||
|
||||
# Tertiary sort key for regSortFeatures.
|
||||
# Sorts by extension number. <feature> elements all have extension number 0.
|
||||
def regSortExtensionNumberKey(feature):
|
||||
return int(feature.number)
|
||||
|
||||
# regSortFeatures - default sort procedure for features.
|
||||
# Sorts by primary key of feature category ('feature' or 'extension')
|
||||
# then by version number (for features)
|
||||
# then by extension number (for extensions)
|
||||
def regSortFeatures(featureList):
|
||||
featureList.sort(key = regSortExtensionNumberKey)
|
||||
featureList.sort(key = regSortFeatureVersionKey)
|
||||
featureList.sort(key = regSortCategoryKey)
|
||||
|
||||
# GeneratorOptions - base class for options used during header production
|
||||
# These options are target language independent, and used by
|
||||
# Registry.apiGen() and by base OutputGenerator objects.
|
||||
#
|
||||
# Members
|
||||
# conventions - may be mandatory for some generators:
|
||||
# an object that implements ConventionsBase
|
||||
# filename - basename of file to generate, or None to write to stdout.
|
||||
# directory - directory in which to generate filename
|
||||
# apiname - string matching <api> 'apiname' attribute, e.g. 'gl'.
|
||||
# profile - string specifying API profile , e.g. 'core', or None.
|
||||
# versions - regex matching API versions to process interfaces for.
|
||||
# Normally '.*' or '[0-9]\.[0-9]' to match all defined versions.
|
||||
# emitversions - regex matching API versions to actually emit
|
||||
# interfaces for (though all requested versions are considered
|
||||
# when deciding which interfaces to generate). For GL 4.3 glext.h,
|
||||
# this might be '1\.[2-5]|[2-4]\.[0-9]'.
|
||||
# defaultExtensions - If not None, a string which must in its
|
||||
# entirety match the pattern in the "supported" attribute of
|
||||
# the <extension>. Defaults to None. Usually the same as apiname.
|
||||
# addExtensions - regex matching names of additional extensions
|
||||
# to include. Defaults to None.
|
||||
# removeExtensions - regex matching names of extensions to
|
||||
# remove (after defaultExtensions and addExtensions). Defaults
|
||||
# to None.
|
||||
# emitExtensions - regex matching names of extensions to actually emit
|
||||
# interfaces for (though all requested versions are considered when
|
||||
# deciding which interfaces to generate).
|
||||
# sortProcedure - takes a list of FeatureInfo objects and sorts
|
||||
# them in place to a preferred order in the generated output.
|
||||
# Default is core API versions, ARB/KHR/OES extensions, all
|
||||
# other extensions, alphabetically within each group.
|
||||
# The regex patterns can be None or empty, in which case they match
|
||||
# nothing.
|
||||
class GeneratorOptions:
|
||||
"""Represents options during header production from an API registry"""
|
||||
|
||||
def __init__(self,
|
||||
conventions = None,
|
||||
filename = None,
|
||||
directory = '.',
|
||||
apiname = None,
|
||||
profile = None,
|
||||
versions = '.*',
|
||||
emitversions = '.*',
|
||||
defaultExtensions = None,
|
||||
addExtensions = None,
|
||||
removeExtensions = None,
|
||||
emitExtensions = None,
|
||||
sortProcedure = regSortFeatures):
|
||||
self.conventions = conventions
|
||||
self.filename = filename
|
||||
self.directory = directory
|
||||
self.apiname = apiname
|
||||
self.profile = profile
|
||||
self.versions = self.emptyRegex(versions)
|
||||
self.emitversions = self.emptyRegex(emitversions)
|
||||
self.defaultExtensions = defaultExtensions
|
||||
self.addExtensions = self.emptyRegex(addExtensions)
|
||||
self.removeExtensions = self.emptyRegex(removeExtensions)
|
||||
self.emitExtensions = self.emptyRegex(emitExtensions)
|
||||
self.sortProcedure = sortProcedure
|
||||
|
||||
# Substitute a regular expression which matches no version
|
||||
# or extension names for None or the empty string.
|
||||
def emptyRegex(self, pat):
|
||||
if pat is None or pat == '':
|
||||
return '_nomatch_^'
|
||||
|
||||
return pat
|
||||
|
||||
# OutputGenerator - base class for generating API interfaces.
|
||||
# Manages basic logic, logging, and output file control
|
||||
# Derived classes actually generate formatted output.
|
||||
#
|
||||
# ---- methods ----
|
||||
# OutputGenerator(errFile, warnFile, diagFile)
|
||||
# errFile, warnFile, diagFile - file handles to write errors,
|
||||
# warnings, diagnostics to. May be None to not write.
|
||||
# logMsg(level, *args) - log messages of different categories
|
||||
# level - 'error', 'warn', or 'diag'. 'error' will also
|
||||
# raise a UserWarning exception
|
||||
# *args - print()-style arguments
|
||||
# setExtMap(map) - specify a dictionary map from extension names to
|
||||
# numbers, used in creating values for extension enumerants.
|
||||
# makeDir(directory) - create a directory, if not already done.
|
||||
# Generally called from derived generators creating hierarchies.
|
||||
# beginFile(genOpts) - start a new interface file
|
||||
# genOpts - GeneratorOptions controlling what's generated and how
|
||||
# endFile() - finish an interface file, closing it when done
|
||||
# beginFeature(interface, emit) - write interface for a feature
|
||||
# and tag generated features as having been done.
|
||||
# interface - element for the <version> / <extension> to generate
|
||||
# emit - actually write to the header only when True
|
||||
# endFeature() - finish an interface.
|
||||
# genType(typeinfo,name,alias) - generate interface for a type
|
||||
# typeinfo - TypeInfo for a type
|
||||
# genStruct(typeinfo,name,alias) - generate interface for a C "struct" type.
|
||||
# typeinfo - TypeInfo for a type interpreted as a struct
|
||||
# genGroup(groupinfo,name,alias) - generate interface for a group of enums (C "enum")
|
||||
# groupinfo - GroupInfo for a group
|
||||
# genEnum(enuminfo,name,alias) - generate interface for an enum (constant)
|
||||
# enuminfo - EnumInfo for an enum
|
||||
# name - enum name
|
||||
# genCmd(cmdinfo,name,alias) - generate interface for a command
|
||||
# cmdinfo - CmdInfo for a command
|
||||
# isEnumRequired(enumElem) - return True if this <enum> element is required
|
||||
# elem - <enum> element to test
|
||||
# makeCDecls(cmd) - return C prototype and function pointer typedef for a
|
||||
# <command> Element, as a list of two strings
|
||||
# cmd - Element for the <command>
|
||||
# newline() - print a newline to the output file (utility function)
|
||||
#
|
||||
class OutputGenerator:
|
||||
"""Generate specified API interfaces in a specific style, such as a C header"""
|
||||
|
||||
# categoryToPath - map XML 'category' to include file directory name
|
||||
categoryToPath = {
|
||||
'bitmask' : 'flags',
|
||||
'enum' : 'enums',
|
||||
'funcpointer' : 'funcpointers',
|
||||
'handle' : 'handles',
|
||||
'define' : 'defines',
|
||||
'basetype' : 'basetypes',
|
||||
}
|
||||
|
||||
# Constructor
|
||||
def __init__(self,
|
||||
errFile = sys.stderr,
|
||||
warnFile = sys.stderr,
|
||||
diagFile = sys.stdout):
|
||||
self.outFile = None
|
||||
self.errFile = errFile
|
||||
self.warnFile = warnFile
|
||||
self.diagFile = diagFile
|
||||
# Internal state
|
||||
self.featureName = None
|
||||
self.genOpts = None
|
||||
self.registry = None
|
||||
# Used for extension enum value generation
|
||||
self.extBase = 1000000000
|
||||
self.extBlockSize = 1000
|
||||
self.madeDirs = {}
|
||||
|
||||
# logMsg - write a message of different categories to different
|
||||
# destinations.
|
||||
# level -
|
||||
# 'diag' (diagnostic, voluminous)
|
||||
# 'warn' (warning)
|
||||
# 'error' (fatal error - raises exception after logging)
|
||||
# *args - print()-style arguments to direct to corresponding log
|
||||
def logMsg(self, level, *args):
|
||||
"""Log a message at the given level. Can be ignored or log to a file"""
|
||||
if level == 'error':
|
||||
strfile = io.StringIO()
|
||||
write('ERROR:', *args, file=strfile)
|
||||
if self.errFile is not None:
|
||||
write(strfile.getvalue(), file=self.errFile)
|
||||
raise UserWarning(strfile.getvalue())
|
||||
elif level == 'warn':
|
||||
if self.warnFile is not None:
|
||||
write('WARNING:', *args, file=self.warnFile)
|
||||
elif level == 'diag':
|
||||
if self.diagFile is not None:
|
||||
write('DIAG:', *args, file=self.diagFile)
|
||||
else:
|
||||
raise UserWarning(
|
||||
'*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
|
||||
|
||||
# enumToValue - parses and converts an <enum> tag into a value.
|
||||
# Returns a list
|
||||
# first element - integer representation of the value, or None
|
||||
# if needsNum is False. The value must be a legal number
|
||||
# if needsNum is True.
|
||||
# second element - string representation of the value
|
||||
# There are several possible representations of values.
|
||||
# A 'value' attribute simply contains the value.
|
||||
# A 'bitpos' attribute defines a value by specifying the bit
|
||||
# position which is set in that value.
|
||||
# A 'offset','extbase','extends' triplet specifies a value
|
||||
# as an offset to a base value defined by the specified
|
||||
# 'extbase' extension name, which is then cast to the
|
||||
# typename specified by 'extends'. This requires probing
|
||||
# the registry database, and imbeds knowledge of the
|
||||
# API extension enum scheme in this function.
|
||||
# A 'alias' attribute contains the name of another enum
|
||||
# which this is an alias of. The other enum must be
|
||||
# declared first when emitting this enum.
|
||||
def enumToValue(self, elem, needsNum):
|
||||
name = elem.get('name')
|
||||
numVal = None
|
||||
if 'value' in elem.keys():
|
||||
value = elem.get('value')
|
||||
# print('About to translate value =', value, 'type =', type(value))
|
||||
if needsNum:
|
||||
numVal = int(value, 0)
|
||||
# If there's a non-integer, numeric 'type' attribute (e.g. 'u' or
|
||||
# 'ull'), append it to the string value.
|
||||
# t = enuminfo.elem.get('type')
|
||||
# if t is not None and t != '' and t != 'i' and t != 's':
|
||||
# value += enuminfo.type
|
||||
self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']')
|
||||
return [numVal, value]
|
||||
if 'bitpos' in elem.keys():
|
||||
value = elem.get('bitpos')
|
||||
bitpos = int(value, 0)
|
||||
numVal = 1 << bitpos
|
||||
value = '0x%08x' % numVal
|
||||
if( bitpos >= 32 ):
|
||||
value = value + 'ULL'
|
||||
self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
|
||||
return [numVal, value]
|
||||
if 'offset' in elem.keys():
|
||||
# Obtain values in the mapping from the attributes
|
||||
enumNegative = False
|
||||
offset = int(elem.get('offset'),0)
|
||||
extnumber = int(elem.get('extnumber'),0)
|
||||
extends = elem.get('extends')
|
||||
if 'dir' in elem.keys():
|
||||
enumNegative = True
|
||||
self.logMsg('diag', 'Enum', name, 'offset =', offset,
|
||||
'extnumber =', extnumber, 'extends =', extends,
|
||||
'enumNegative =', enumNegative)
|
||||
# Now determine the actual enumerant value, as defined
|
||||
# in the "Layers and Extensions" appendix of the spec.
|
||||
numVal = self.extBase + (extnumber - 1) * self.extBlockSize + offset
|
||||
if enumNegative:
|
||||
numVal *= -1
|
||||
value = '%d' % numVal
|
||||
# More logic needed!
|
||||
self.logMsg('diag', 'Enum', name, '-> offset [', numVal, ',', value, ']')
|
||||
return [numVal, value]
|
||||
if 'alias' in elem.keys():
|
||||
return [None, elem.get('alias')]
|
||||
return [None, None]
|
||||
|
||||
# checkDuplicateEnums - sanity check for enumerated values
|
||||
# enums - list of <enum> Elements
|
||||
# returns the list with duplicates stripped
|
||||
def checkDuplicateEnums(self, enums):
|
||||
# Dictionaries indexed by name and numeric value.
|
||||
# Entries are [ Element, numVal, strVal ] matching name or value
|
||||
|
||||
nameMap = {}
|
||||
valueMap = {}
|
||||
|
||||
stripped = []
|
||||
for elem in enums:
|
||||
name = elem.get('name')
|
||||
(numVal, strVal) = self.enumToValue(elem, True)
|
||||
|
||||
if name in nameMap:
|
||||
# Duplicate name found; check values
|
||||
(name2, numVal2, strVal2) = nameMap[name]
|
||||
|
||||
# Duplicate enum values for the same name are benign. This
|
||||
# happens when defining the same enum conditionally in
|
||||
# several extension blocks.
|
||||
if (strVal2 == strVal or (numVal is not None and
|
||||
numVal == numVal2)):
|
||||
True
|
||||
# self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
|
||||
# ') found with the same value:' + strVal)
|
||||
else:
|
||||
self.logMsg('warn', 'checkDuplicateEnums: Duplicate enum (' + name +
|
||||
') found with different values:' + strVal +
|
||||
' and ' + strVal2)
|
||||
|
||||
# Don't add the duplicate to the returned list
|
||||
continue
|
||||
elif numVal in valueMap:
|
||||
# Duplicate value found (such as an alias); report it, but
|
||||
# still add this enum to the list.
|
||||
(name2, numVal2, strVal2) = valueMap[numVal]
|
||||
|
||||
try:
|
||||
self.logMsg('warn', 'Two enums found with the same value: '
|
||||
+ name + ' = ' + name2.get('name') + ' = ' + strVal)
|
||||
except:
|
||||
pdb.set_trace()
|
||||
|
||||
# Track this enum to detect followon duplicates
|
||||
nameMap[name] = [ elem, numVal, strVal ]
|
||||
if numVal is not None:
|
||||
valueMap[numVal] = [ elem, numVal, strVal ]
|
||||
|
||||
# Add this enum to the list
|
||||
stripped.append(elem)
|
||||
|
||||
# Return the list
|
||||
return stripped
|
||||
|
||||
# buildEnumCDecl
|
||||
# Generates the C declaration for an enum
|
||||
def buildEnumCDecl(self, expand, groupinfo, groupName):
|
||||
groupElem = groupinfo.elem
|
||||
|
||||
if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
|
||||
return self.buildEnumCDecl_Bitmask( groupinfo, groupName)
|
||||
else:
|
||||
return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
|
||||
|
||||
# buildEnumCDecl_Bitmask
|
||||
# Generates the C declaration for an "enum" that is actually a
|
||||
# set of flag bits
|
||||
def buildEnumCDecl_Bitmask(self, groupinfo, groupName):
|
||||
groupElem = groupinfo.elem
|
||||
flagTypeName = groupinfo.flagType.elem.get('name')
|
||||
|
||||
# Prefix
|
||||
body = "// Flag bits for " + flagTypeName + "\n"
|
||||
|
||||
# Loop over the nested 'enum' tags.
|
||||
for elem in groupElem.findall('enum'):
|
||||
# Convert the value to an integer and use that to track min/max.
|
||||
# Values of form -(number) are accepted but nothing more complex.
|
||||
# Should catch exceptions here for more complex constructs. Not yet.
|
||||
(_, strVal) = self.enumToValue(elem, True)
|
||||
name = elem.get('name')
|
||||
body += "static const " + flagTypeName + " " + name + " = " + strVal + ";\n"
|
||||
|
||||
# Postfix
|
||||
|
||||
return ("bitmask", body)
|
||||
|
||||
# Generates the C declaration for an enumerated type
|
||||
def buildEnumCDecl_Enum(self, expand, groupinfo, groupName):
|
||||
groupElem = groupinfo.elem
|
||||
|
||||
# Break the group name into prefix and suffix portions for range
|
||||
# enum generation
|
||||
expandName = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',groupName).upper()
|
||||
expandPrefix = expandName
|
||||
expandSuffix = ''
|
||||
expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName)
|
||||
if expandSuffixMatch:
|
||||
expandSuffix = '_' + expandSuffixMatch.group()
|
||||
# Strip off the suffix from the prefix
|
||||
expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
|
||||
|
||||
# Prefix
|
||||
body = "typedef enum " + groupName + " {\n"
|
||||
|
||||
# @@ Should use the type="bitmask" attribute instead
|
||||
isEnum = ('FLAG_BITS' not in expandPrefix)
|
||||
|
||||
# Get a list of nested 'enum' tags.
|
||||
enums = groupElem.findall('enum')
|
||||
|
||||
# Check for and report duplicates, and return a list with them
|
||||
# removed.
|
||||
enums = self.checkDuplicateEnums(enums)
|
||||
|
||||
# Loop over the nested 'enum' tags. Keep track of the minimum and
|
||||
# maximum numeric values, if they can be determined; but only for
|
||||
# core API enumerants, not extension enumerants. This is inferred
|
||||
# by looking for 'extends' attributes.
|
||||
minName = None
|
||||
|
||||
# Accumulate non-numeric enumerant values separately and append
|
||||
# them following the numeric values, to allow for aliases.
|
||||
# NOTE: this doesn't do a topological sort yet, so aliases of
|
||||
# aliases can still get in the wrong order.
|
||||
aliasText = ""
|
||||
|
||||
for elem in enums:
|
||||
# Convert the value to an integer and use that to track min/max.
|
||||
# Values of form -(number) are accepted but nothing more complex.
|
||||
# Should catch exceptions here for more complex constructs. Not yet.
|
||||
(numVal,strVal) = self.enumToValue(elem, True)
|
||||
name = elem.get('name')
|
||||
|
||||
# Extension enumerants are only included if they are required
|
||||
if self.isEnumRequired(elem):
|
||||
decl = " " + name + " = " + strVal + ",\n"
|
||||
if numVal is not None:
|
||||
body += decl
|
||||
else:
|
||||
aliasText += decl
|
||||
|
||||
# Don't track min/max for non-numbers (numVal is None)
|
||||
if isEnum and numVal is not None and elem.get('extends') is None:
|
||||
if minName is None:
|
||||
minName = maxName = name
|
||||
minValue = maxValue = numVal
|
||||
elif numVal < minValue:
|
||||
minName = name
|
||||
minValue = numVal
|
||||
elif numVal > maxValue:
|
||||
maxName = name
|
||||
maxValue = numVal
|
||||
|
||||
# Now append the non-numeric enumerant values
|
||||
body += aliasText
|
||||
|
||||
# Generate min/max value tokens and a range-padding enum. Need some
|
||||
# additional padding to generate correct names...
|
||||
if isEnum and expand:
|
||||
body += " " + expandPrefix + "_BEGIN_RANGE" + expandSuffix + " = " + minName + ",\n"
|
||||
body += " " + expandPrefix + "_END_RANGE" + expandSuffix + " = " + maxName + ",\n"
|
||||
body += " " + expandPrefix + "_RANGE_SIZE" + expandSuffix + " = (" + maxName + " - " + minName + " + 1),\n"
|
||||
|
||||
# Always generate this to make sure the enumerated type is 32 bits
|
||||
body += " " + expandPrefix + "_MAX_ENUM" + expandSuffix + " = 0x7FFFFFFF\n"
|
||||
|
||||
# Postfix
|
||||
body += "} " + groupName + ";"
|
||||
|
||||
# Determine appropriate section for this declaration
|
||||
if groupElem.get('type') == 'bitmask':
|
||||
section = 'bitmask'
|
||||
else:
|
||||
section = 'group'
|
||||
|
||||
return (section, body)
|
||||
|
||||
def makeDir(self, path):
|
||||
self.logMsg('diag', 'OutputGenerator::makeDir(' + path + ')')
|
||||
if path not in self.madeDirs:
|
||||
# This can get race conditions with multiple writers, see
|
||||
# https://stackoverflow.com/questions/273192/
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
self.madeDirs[path] = None
|
||||
|
||||
def beginFile(self, genOpts):
|
||||
self.genOpts = genOpts
|
||||
|
||||
# Open specified output file. Not done in constructor since a
|
||||
# Generator can be used without writing to a file.
|
||||
if self.genOpts.filename is not None:
|
||||
if sys.platform == 'win32':
|
||||
directory = Path(self.genOpts.directory)
|
||||
if not Path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
self.outFile = (directory / self.genOpts.filename).open('w', encoding='utf-8')
|
||||
else:
|
||||
filename = self.genOpts.directory + '/' + self.genOpts.filename
|
||||
self.outFile = io.open(filename, 'w', encoding='utf-8')
|
||||
else:
|
||||
self.outFile = sys.stdout
|
||||
|
||||
def endFile(self):
|
||||
if self.errFile:
|
||||
self.errFile.flush()
|
||||
if self.warnFile:
|
||||
self.warnFile.flush()
|
||||
if self.diagFile:
|
||||
self.diagFile.flush()
|
||||
self.outFile.flush()
|
||||
if self.outFile != sys.stdout and self.outFile != sys.stderr:
|
||||
self.outFile.close()
|
||||
self.genOpts = None
|
||||
|
||||
def beginFeature(self, interface, emit):
|
||||
self.emit = emit
|
||||
self.featureName = interface.get('name')
|
||||
# If there's an additional 'protect' attribute in the feature, save it
|
||||
self.featureExtraProtect = interface.get('protect')
|
||||
|
||||
def endFeature(self):
|
||||
# Derived classes responsible for emitting feature
|
||||
self.featureName = None
|
||||
self.featureExtraProtect = None
|
||||
|
||||
# Utility method to validate we're generating something only inside a
|
||||
# <feature> tag
|
||||
def validateFeature(self, featureType, featureName):
|
||||
if self.featureName is None:
|
||||
raise UserWarning('Attempt to generate', featureType,
|
||||
featureName, 'when not in feature')
|
||||
|
||||
# Type generation
|
||||
def genType(self, typeinfo, name, alias):
|
||||
self.validateFeature('type', name)
|
||||
|
||||
# Struct (e.g. C "struct" type) generation
|
||||
def genStruct(self, typeinfo, typeName, alias):
|
||||
self.validateFeature('struct', typeName)
|
||||
|
||||
# The mixed-mode <member> tags may contain no-op <comment> tags.
|
||||
# It is convenient to remove them here where all output generators
|
||||
# will benefit.
|
||||
for member in typeinfo.elem.findall('.//member'):
|
||||
for comment in member.findall('comment'):
|
||||
member.remove(comment)
|
||||
|
||||
# Group (e.g. C "enum" type) generation
|
||||
def genGroup(self, groupinfo, groupName, alias):
|
||||
self.validateFeature('group', groupName)
|
||||
|
||||
# Enumerant (really, constant) generation
|
||||
def genEnum(self, enuminfo, typeName, alias):
|
||||
self.validateFeature('enum', typeName)
|
||||
|
||||
# Command generation
|
||||
def genCmd(self, cmd, cmdinfo, alias):
|
||||
self.validateFeature('command', cmdinfo)
|
||||
|
||||
# Utility functions - turn a <proto> <name> into C-language prototype
|
||||
# and typedef declarations for that name.
|
||||
# name - contents of <name> tag
|
||||
# tail - whatever text follows that tag in the Element
|
||||
def makeProtoName(self, name, tail):
|
||||
return self.genOpts.apientry + name + tail
|
||||
|
||||
def makeTypedefName(self, name, tail):
|
||||
return '(' + self.genOpts.apientryp + 'PFN_' + name + tail + ')'
|
||||
|
||||
# makeCParamDecl - return a string which is an indented, formatted
|
||||
# declaration for a <param> or <member> block (e.g. function parameter
|
||||
# or structure/union member).
|
||||
# param - Element (<param> or <member>) to format
|
||||
# aligncol - if non-zero, attempt to align the nested <name> element
|
||||
# at this column
|
||||
def makeCParamDecl(self, param, aligncol):
|
||||
paramdecl = ' ' + noneStr(param.text)
|
||||
for elem in param:
|
||||
text = noneStr(elem.text)
|
||||
tail = noneStr(elem.tail)
|
||||
|
||||
if self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
|
||||
# OpenXR-specific macro insertion
|
||||
tail = self.genOpts.conventions.make_voidpointer_alias(tail)
|
||||
if elem.tag == 'name' and aligncol > 0:
|
||||
self.logMsg('diag', 'Aligning parameter', elem.text, 'to column', self.genOpts.alignFuncParam)
|
||||
# Align at specified column, if possible
|
||||
paramdecl = paramdecl.rstrip()
|
||||
oldLen = len(paramdecl)
|
||||
# This works around a problem where very long type names -
|
||||
# longer than the alignment column - would run into the tail
|
||||
# text.
|
||||
paramdecl = paramdecl.ljust(aligncol-1) + ' '
|
||||
newLen = len(paramdecl)
|
||||
self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
|
||||
paramdecl += text + tail
|
||||
return paramdecl
|
||||
|
||||
# getCParamTypeLength - return the length of the type field is an indented, formatted
|
||||
# declaration for a <param> or <member> block (e.g. function parameter
|
||||
# or structure/union member).
|
||||
# param - Element (<param> or <member>) to identify
|
||||
def getCParamTypeLength(self, param):
|
||||
paramdecl = ' ' + noneStr(param.text)
|
||||
for elem in param:
|
||||
text = noneStr(elem.text)
|
||||
tail = noneStr(elem.tail)
|
||||
|
||||
if self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
|
||||
# OpenXR-specific macro insertion
|
||||
tail = self.genOpts.conventions.make_voidpointer_alias(tail)
|
||||
if elem.tag == 'name':
|
||||
# Align at specified column, if possible
|
||||
newLen = len(paramdecl.rstrip())
|
||||
self.logMsg('diag', 'Identifying length of', elem.text, 'as', newLen)
|
||||
paramdecl += text + tail
|
||||
|
||||
return newLen
|
||||
|
||||
# isEnumRequired(elem) - return True if this <enum> element is
|
||||
# required, False otherwise
|
||||
# elem - <enum> element to test
|
||||
def isEnumRequired(self, elem):
|
||||
required = elem.get('required') is not None
|
||||
self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
|
||||
'->', required)
|
||||
return required
|
||||
|
||||
#@@@ This code is overridden by equivalent code now run in
|
||||
#@@@ Registry.generateFeature
|
||||
|
||||
required = False
|
||||
|
||||
extname = elem.get('extname')
|
||||
if extname is not None:
|
||||
# 'supported' attribute was injected when the <enum> element was
|
||||
# moved into the <enums> group in Registry.parseTree()
|
||||
if self.genOpts.defaultExtensions == elem.get('supported'):
|
||||
required = True
|
||||
elif re.match(self.genOpts.addExtensions, extname) is not None:
|
||||
required = True
|
||||
elif elem.get('version') is not None:
|
||||
required = re.match(self.genOpts.emitversions, elem.get('version')) is not None
|
||||
else:
|
||||
required = True
|
||||
|
||||
return required
|
||||
|
||||
# makeCDecls - return C prototype and function pointer typedef for a
|
||||
# command, as a two-element list of strings.
|
||||
# cmd - Element containing a <command> tag
|
||||
def makeCDecls(self, cmd):
|
||||
"""Generate C function pointer typedef for <command> Element"""
|
||||
proto = cmd.find('proto')
|
||||
params = cmd.findall('param')
|
||||
# Begin accumulating prototype and typedef strings
|
||||
pdecl = self.genOpts.apicall
|
||||
tdecl = 'typedef '
|
||||
|
||||
# Insert the function return type/name.
|
||||
# For prototypes, add APIENTRY macro before the name
|
||||
# For typedefs, add (APIENTRY *<name>) around the name and
|
||||
# use the PFN_cmdnameproc naming convention.
|
||||
# Done by walking the tree for <proto> element by element.
|
||||
# etree has elem.text followed by (elem[i], elem[i].tail)
|
||||
# for each child element and any following text
|
||||
# Leading text
|
||||
pdecl += noneStr(proto.text)
|
||||
tdecl += noneStr(proto.text)
|
||||
# For each child element, if it's a <name> wrap in appropriate
|
||||
# declaration. Otherwise append its contents and tail contents.
|
||||
for elem in proto:
|
||||
text = noneStr(elem.text)
|
||||
tail = noneStr(elem.tail)
|
||||
if elem.tag == 'name':
|
||||
pdecl += self.makeProtoName(text, tail)
|
||||
tdecl += self.makeTypedefName(text, tail)
|
||||
else:
|
||||
pdecl += text + tail
|
||||
tdecl += text + tail
|
||||
# Now add the parameter declaration list, which is identical
|
||||
# for prototypes and typedefs. Concatenate all the text from
|
||||
# a <param> node without the tags. No tree walking required
|
||||
# since all tags are ignored.
|
||||
# Uses: self.indentFuncProto
|
||||
# self.indentFuncPointer
|
||||
# self.alignFuncParam
|
||||
n = len(params)
|
||||
# Indented parameters
|
||||
if n > 0:
|
||||
indentdecl = '(\n'
|
||||
indentdecl += ',\n'.join(self.makeCParamDecl(p, self.genOpts.alignFuncParam)
|
||||
for p in params)
|
||||
indentdecl += ');'
|
||||
else:
|
||||
indentdecl = '(void);'
|
||||
# Non-indented parameters
|
||||
paramdecl = '('
|
||||
if n > 0:
|
||||
paramnames = (''.join(t for t in p.itertext())
|
||||
for p in params)
|
||||
paramdecl += ', '.join(paramnames)
|
||||
else:
|
||||
paramdecl += 'void'
|
||||
paramdecl += ");"
|
||||
return [ pdecl + indentdecl, tdecl + paramdecl ]
|
||||
|
||||
def newline(self):
|
||||
write('', file=self.outFile)
|
||||
|
||||
def setRegistry(self, registry):
|
||||
self.registry = registry
|
|
@ -1,541 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import pdb
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
from cgenerator import CGeneratorOptions, COutputGenerator
|
||||
from docgenerator import DocGeneratorOptions, DocOutputGenerator
|
||||
from extensionmetadocgenerator import (ExtensionMetaDocGeneratorOptions,
|
||||
ExtensionMetaDocOutputGenerator)
|
||||
from generator import write
|
||||
from hostsyncgenerator import HostSynchronizationOutputGenerator
|
||||
from pygenerator import PyOutputGenerator
|
||||
from reg import Registry
|
||||
from validitygenerator import ValidityOutputGenerator
|
||||
from vkconventions import VulkanConventions
|
||||
|
||||
# Simple timer functions
|
||||
startTime = None
|
||||
|
||||
|
||||
def startTimer(timeit):
|
||||
global startTime
|
||||
if timeit:
|
||||
startTime = time.process_time()
|
||||
|
||||
def endTimer(timeit, msg):
|
||||
global startTime
|
||||
if timeit:
|
||||
endTime = time.process_time()
|
||||
write(msg, endTime - startTime, file=sys.stderr)
|
||||
startTime = None
|
||||
|
||||
# Turn a list of strings into a regexp string matching exactly those strings
|
||||
def makeREstring(list, default = None):
|
||||
if len(list) > 0 or default is None:
|
||||
return '^(' + '|'.join(list) + ')$'
|
||||
else:
|
||||
return default
|
||||
|
||||
# Returns a directory of [ generator function, generator options ] indexed
|
||||
# by specified short names. The generator options incorporate the following
|
||||
# parameters:
|
||||
#
|
||||
# args is an parsed argument object; see below for the fields that are used.
|
||||
def makeGenOpts(args):
|
||||
global genOpts
|
||||
genOpts = {}
|
||||
|
||||
# Default class of extensions to include, or None
|
||||
defaultExtensions = args.defaultExtensions
|
||||
|
||||
# Additional extensions to include (list of extensions)
|
||||
extensions = args.extension
|
||||
|
||||
# Extensions to remove (list of extensions)
|
||||
removeExtensions = args.removeExtensions
|
||||
|
||||
# Extensions to emit (list of extensions)
|
||||
emitExtensions = args.emitExtensions
|
||||
|
||||
# Features to include (list of features)
|
||||
features = args.feature
|
||||
|
||||
# Whether to disable inclusion protect in headers
|
||||
protect = args.protect
|
||||
|
||||
# Output target directory
|
||||
directory = args.directory
|
||||
|
||||
# Descriptive names for various regexp patterns used to select
|
||||
# versions and extensions
|
||||
allFeatures = allExtensions = r'.*'
|
||||
|
||||
# Turn lists of names/patterns into matching regular expressions
|
||||
addExtensionsPat = makeREstring(extensions, None)
|
||||
removeExtensionsPat = makeREstring(removeExtensions, None)
|
||||
emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
|
||||
featuresPat = makeREstring(features, allFeatures)
|
||||
|
||||
# Copyright text prefixing all headers (list of strings).
|
||||
prefixStrings = [
|
||||
'/*',
|
||||
'** Copyright (c) 2015-2019 The Khronos Group Inc.',
|
||||
'**',
|
||||
'** Licensed under the Apache License, Version 2.0 (the "License");',
|
||||
'** you may not use this file except in compliance with the License.',
|
||||
'** You may obtain a copy of the License at',
|
||||
'**',
|
||||
'** http://www.apache.org/licenses/LICENSE-2.0',
|
||||
'**',
|
||||
'** Unless required by applicable law or agreed to in writing, software',
|
||||
'** distributed under the License is distributed on an "AS IS" BASIS,',
|
||||
'** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
||||
'** See the License for the specific language governing permissions and',
|
||||
'** limitations under the License.',
|
||||
'*/',
|
||||
''
|
||||
]
|
||||
|
||||
# Text specific to Vulkan headers
|
||||
vkPrefixStrings = [
|
||||
'/*',
|
||||
'** This header is generated from the Khronos Vulkan XML API Registry.',
|
||||
'**',
|
||||
'*/',
|
||||
''
|
||||
]
|
||||
|
||||
# Defaults for generating re-inclusion protection wrappers (or not)
|
||||
protectFile = protect
|
||||
|
||||
# An API style conventions object
|
||||
conventions = VulkanConventions()
|
||||
|
||||
# API include files for spec and ref pages
|
||||
# Overwrites include subdirectories in spec source tree
|
||||
# The generated include files do not include the calling convention
|
||||
# macros (apientry etc.), unlike the header files.
|
||||
# Because the 1.0 core branch includes ref pages for extensions,
|
||||
# all the extension interfaces need to be generated, even though
|
||||
# none are used by the core spec itself.
|
||||
genOpts['apiinc'] = [
|
||||
DocOutputGenerator,
|
||||
DocGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'timeMarker',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = None,
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = '',
|
||||
apientry = '',
|
||||
apientryp = '*',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False)
|
||||
]
|
||||
|
||||
# API names to validate man/api spec includes & links
|
||||
genOpts['vkapi.py'] = [
|
||||
PyOutputGenerator,
|
||||
DocGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vkapi.py',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = None,
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat)
|
||||
]
|
||||
|
||||
# API validity files for spec
|
||||
genOpts['validinc'] = [
|
||||
ValidityOutputGenerator,
|
||||
DocGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'timeMarker',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = None,
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat)
|
||||
]
|
||||
|
||||
# API host sync table files for spec
|
||||
genOpts['hostsyncinc'] = [
|
||||
HostSynchronizationOutputGenerator,
|
||||
DocGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'timeMarker',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = None,
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat)
|
||||
]
|
||||
|
||||
# Extension metainformation for spec extension appendices
|
||||
genOpts['extinc'] = [
|
||||
ExtensionMetaDocOutputGenerator,
|
||||
ExtensionMetaDocGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'timeMarker',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = None,
|
||||
defaultExtensions = defaultExtensions,
|
||||
addExtensions = None,
|
||||
removeExtensions = None,
|
||||
emitExtensions = emitExtensionsPat)
|
||||
]
|
||||
|
||||
# Platform extensions, in their own header files
|
||||
# Each element of the platforms[] array defines information for
|
||||
# generating a single platform:
|
||||
# [0] is the generated header file name
|
||||
# [1] is the set of platform extensions to generate
|
||||
# [2] is additional extensions whose interfaces should be considered,
|
||||
# but suppressed in the output, to avoid duplicate definitions of
|
||||
# dependent types like VkDisplayKHR and VkSurfaceKHR which come from
|
||||
# non-platform extensions.
|
||||
|
||||
# Track all platform extensions, for exclusion from vulkan_core.h
|
||||
allPlatformExtensions = []
|
||||
|
||||
# Extensions suppressed for all platforms.
|
||||
# Covers common WSI extension types.
|
||||
commonSuppressExtensions = [ 'VK_KHR_display', 'VK_KHR_swapchain' ]
|
||||
|
||||
platforms = [
|
||||
[ 'vulkan_android.h', [ 'VK_KHR_android_surface',
|
||||
'VK_ANDROID_external_memory_android_hardware_buffer'
|
||||
], commonSuppressExtensions ],
|
||||
[ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface'], commonSuppressExtensions ],
|
||||
[ 'vulkan_ggp.h', [ 'VK_GGP_stream_descriptor_surface',
|
||||
'VK_GGP_frame_token' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_ios.h', [ 'VK_MVK_ios_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_macos.h', [ 'VK_MVK_macos_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_vi.h', [ 'VK_NN_vi_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_wayland.h', [ 'VK_KHR_wayland_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_win32.h', [ 'VK_.*_win32(|_.*)', 'VK_EXT_full_screen_exclusive' ],
|
||||
commonSuppressExtensions +
|
||||
[ 'VK_KHR_external_semaphore',
|
||||
'VK_KHR_external_memory_capabilities',
|
||||
'VK_KHR_external_fence',
|
||||
'VK_KHR_external_fence_capabilities',
|
||||
'VK_KHR_get_surface_capabilities2',
|
||||
'VK_NV_external_memory_capabilities',
|
||||
] ],
|
||||
[ 'vulkan_xcb.h', [ 'VK_KHR_xcb_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_xlib.h', [ 'VK_KHR_xlib_surface' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_xlib_xrandr.h', [ 'VK_EXT_acquire_xlib_display' ], commonSuppressExtensions ],
|
||||
[ 'vulkan_metal.h', [ 'VK_EXT_metal_surface' ], commonSuppressExtensions ],
|
||||
]
|
||||
|
||||
for platform in platforms:
|
||||
headername = platform[0]
|
||||
|
||||
allPlatformExtensions += platform[1]
|
||||
|
||||
addPlatformExtensionsRE = makeREstring(platform[1] + platform[2])
|
||||
emitPlatformExtensionsRE = makeREstring(platform[1])
|
||||
|
||||
opts = CGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = headername,
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = None,
|
||||
defaultExtensions = None,
|
||||
addExtensions = addPlatformExtensionsRE,
|
||||
removeExtensions = None,
|
||||
emitExtensions = emitPlatformExtensionsRE,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
genFuncPointers = True,
|
||||
protectFile = protectFile,
|
||||
protectFeature = False,
|
||||
protectProto = '#ifndef',
|
||||
protectProtoStr = 'VK_NO_PROTOTYPES',
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
genEnumBeginEndRange = True)
|
||||
|
||||
genOpts[headername] = [ COutputGenerator, opts ]
|
||||
|
||||
# Header for core API + extensions.
|
||||
# To generate just the core API,
|
||||
# change to 'defaultExtensions = None' below.
|
||||
#
|
||||
# By default this adds all enabled, non-platform extensions.
|
||||
# It removes all platform extensions (from the platform headers options
|
||||
# constructed above) as well as any explicitly specified removals.
|
||||
|
||||
removeExtensionsPat = makeREstring(allPlatformExtensions + removeExtensions, None)
|
||||
|
||||
genOpts['vulkan_core.h'] = [
|
||||
COutputGenerator,
|
||||
CGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vulkan_core.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = defaultExtensions,
|
||||
addExtensions = None,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
genFuncPointers = True,
|
||||
protectFile = protectFile,
|
||||
protectFeature = False,
|
||||
protectProto = '#ifndef',
|
||||
protectProtoStr = 'VK_NO_PROTOTYPES',
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
genEnumBeginEndRange = True)
|
||||
]
|
||||
|
||||
# Unused - vulkan10.h target.
|
||||
# It is possible to generate a header with just the Vulkan 1.0 +
|
||||
# extension interfaces defined, but since the promoted KHR extensions
|
||||
# are now defined in terms of the 1.1 interfaces, such a header is very
|
||||
# similar to vulkan_core.h.
|
||||
genOpts['vulkan10.h'] = [
|
||||
COutputGenerator,
|
||||
CGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vulkan10.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = 'VK_VERSION_1_0',
|
||||
emitversions = 'VK_VERSION_1_0',
|
||||
defaultExtensions = defaultExtensions,
|
||||
addExtensions = None,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
genFuncPointers = True,
|
||||
protectFile = protectFile,
|
||||
protectFeature = False,
|
||||
protectProto = '#ifndef',
|
||||
protectProtoStr = 'VK_NO_PROTOTYPES',
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48)
|
||||
]
|
||||
|
||||
genOpts['alias.h'] = [
|
||||
COutputGenerator,
|
||||
CGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'alias.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = defaultExtensions,
|
||||
addExtensions = None,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = None,
|
||||
genFuncPointers = False,
|
||||
protectFile = False,
|
||||
protectFeature = False,
|
||||
protectProto = '',
|
||||
protectProtoStr = '',
|
||||
apicall = '',
|
||||
apientry = '',
|
||||
apientryp = '',
|
||||
alignFuncParam = 36)
|
||||
]
|
||||
|
||||
# Generate a target based on the options in the matching genOpts{} object.
|
||||
# This is encapsulated in a function so it can be profiled and/or timed.
|
||||
# The args parameter is an parsed argument object containing the following
|
||||
# fields that are used:
|
||||
# target - target to generate
|
||||
# directory - directory to generate it in
|
||||
# protect - True if re-inclusion wrappers should be created
|
||||
# extensions - list of additional extensions to include in generated
|
||||
# interfaces
|
||||
def genTarget(args):
|
||||
# Create generator options with specified parameters
|
||||
makeGenOpts(args)
|
||||
|
||||
if args.target in genOpts:
|
||||
createGenerator = genOpts[args.target][0]
|
||||
options = genOpts[args.target][1]
|
||||
|
||||
if not args.quiet:
|
||||
write('* Building', options.filename, file=sys.stderr)
|
||||
write('* options.versions =', options.versions, file=sys.stderr)
|
||||
write('* options.emitversions =', options.emitversions, file=sys.stderr)
|
||||
write('* options.defaultExtensions =', options.defaultExtensions, file=sys.stderr)
|
||||
write('* options.addExtensions =', options.addExtensions, file=sys.stderr)
|
||||
write('* options.removeExtensions =', options.removeExtensions, file=sys.stderr)
|
||||
write('* options.emitExtensions =', options.emitExtensions, file=sys.stderr)
|
||||
|
||||
startTimer(args.time)
|
||||
gen = createGenerator(errFile=errWarn,
|
||||
warnFile=errWarn,
|
||||
diagFile=diag)
|
||||
reg.setGenerator(gen)
|
||||
reg.apiGen(options)
|
||||
|
||||
if not args.quiet:
|
||||
write('* Generated', options.filename, file=sys.stderr)
|
||||
endTimer(args.time, '* Time to generate ' + options.filename + ' =')
|
||||
else:
|
||||
write('No generator options for unknown target:',
|
||||
args.target, file=sys.stderr)
|
||||
|
||||
|
||||
# -feature name
|
||||
# -extension name
|
||||
# For both, "name" may be a single name, or a space-separated list
|
||||
# of names, or a regular expression.
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('-defaultExtensions', action='store',
|
||||
default='vulkan',
|
||||
help='Specify a single class of extensions to add to targets')
|
||||
parser.add_argument('-extension', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to add to targets')
|
||||
parser.add_argument('-removeExtensions', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to remove from targets')
|
||||
parser.add_argument('-emitExtensions', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to emit in targets')
|
||||
parser.add_argument('-feature', action='append',
|
||||
default=[],
|
||||
help='Specify a core API feature name or names to add to targets')
|
||||
parser.add_argument('-debug', action='store_true',
|
||||
help='Enable debugging')
|
||||
parser.add_argument('-dump', action='store_true',
|
||||
help='Enable dump to stderr')
|
||||
parser.add_argument('-diagfile', action='store',
|
||||
default=None,
|
||||
help='Write diagnostics to specified file')
|
||||
parser.add_argument('-errfile', action='store',
|
||||
default=None,
|
||||
help='Write errors and warnings to specified file instead of stderr')
|
||||
parser.add_argument('-noprotect', dest='protect', action='store_false',
|
||||
help='Disable inclusion protection in output headers')
|
||||
parser.add_argument('-profile', action='store_true',
|
||||
help='Enable profiling')
|
||||
parser.add_argument('-registry', action='store',
|
||||
default='vk.xml',
|
||||
help='Use specified registry file instead of vk.xml')
|
||||
parser.add_argument('-time', action='store_true',
|
||||
help='Enable timing')
|
||||
parser.add_argument('-validate', action='store_true',
|
||||
help='Enable group validation')
|
||||
parser.add_argument('-o', action='store', dest='directory',
|
||||
default='.',
|
||||
help='Create target and related files in specified directory')
|
||||
parser.add_argument('target', metavar='target', nargs='?',
|
||||
help='Specify target')
|
||||
parser.add_argument('-quiet', action='store_true', default=True,
|
||||
help='Suppress script output during normal execution.')
|
||||
parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
|
||||
help='Enable script output during normal execution.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# This splits arguments which are space-separated lists
|
||||
args.feature = [name for arg in args.feature for name in arg.split()]
|
||||
args.extension = [name for arg in args.extension for name in arg.split()]
|
||||
|
||||
# Load & parse registry
|
||||
reg = Registry()
|
||||
|
||||
startTimer(args.time)
|
||||
tree = etree.parse(args.registry)
|
||||
endTimer(args.time, '* Time to make ElementTree =')
|
||||
|
||||
if args.debug:
|
||||
pdb.run('reg.loadElementTree(tree)')
|
||||
else:
|
||||
startTimer(args.time)
|
||||
reg.loadElementTree(tree)
|
||||
endTimer(args.time, '* Time to parse ElementTree =')
|
||||
|
||||
if args.validate:
|
||||
reg.validateGroups()
|
||||
|
||||
if args.dump:
|
||||
write('* Dumping registry to regdump.txt', file=sys.stderr)
|
||||
reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
|
||||
|
||||
# create error/warning & diagnostic files
|
||||
if args.errfile:
|
||||
errWarn = open(args.errfile, 'w', encoding='utf-8')
|
||||
else:
|
||||
errWarn = sys.stderr
|
||||
|
||||
if args.diagfile:
|
||||
diag = open(args.diagfile, 'w', encoding='utf-8')
|
||||
else:
|
||||
diag = None
|
||||
|
||||
if args.debug:
|
||||
pdb.run('genTarget(args)')
|
||||
elif args.profile:
|
||||
import cProfile, pstats
|
||||
cProfile.run('genTarget(args)', 'profile.txt')
|
||||
p = pstats.Stats('profile.txt')
|
||||
p.strip_dirs().sort_stats('time').print_stats(50)
|
||||
else:
|
||||
genTarget(args)
|
|
@ -1,513 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2015-2017 The Khronos Group Inc.
|
||||
# Copyright (c) 2015-2017 Valve Corporation
|
||||
# Copyright (c) 2015-2017 LunarG, Inc.
|
||||
# Copyright (c) 2015-2017 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Author: Mark Lobodzinski <mark@lunarg.com>
|
||||
# Author: Tobin Ehlis <tobine@google.com>
|
||||
# Author: John Zulauf <jzulauf@lunarg.com>
|
||||
|
||||
import os,re,sys
|
||||
import xml.etree.ElementTree as etree
|
||||
from generator import *
|
||||
from collections import namedtuple
|
||||
from common_codegen import *
|
||||
|
||||
#
|
||||
# HelperFileOutputGeneratorOptions - subclass of GeneratorOptions.
|
||||
class HelperFileOutputGeneratorOptions(GeneratorOptions):
|
||||
def __init__(self,
|
||||
conventions = None,
|
||||
filename = None,
|
||||
directory = '.',
|
||||
apiname = None,
|
||||
profile = None,
|
||||
versions = '.*',
|
||||
emitversions = '.*',
|
||||
defaultExtensions = None,
|
||||
addExtensions = None,
|
||||
removeExtensions = None,
|
||||
emitExtensions = None,
|
||||
sortProcedure = regSortFeatures,
|
||||
prefixText = "",
|
||||
genFuncPointers = True,
|
||||
protectFile = True,
|
||||
protectFeature = True,
|
||||
apicall = '',
|
||||
apientry = '',
|
||||
apientryp = '',
|
||||
alignFuncParam = 0,
|
||||
library_name = '',
|
||||
expandEnumerants = True,
|
||||
helper_file_type = ''):
|
||||
GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
|
||||
versions, emitversions, defaultExtensions,
|
||||
addExtensions, removeExtensions, emitExtensions, sortProcedure)
|
||||
self.prefixText = prefixText
|
||||
self.genFuncPointers = genFuncPointers
|
||||
self.protectFile = protectFile
|
||||
self.protectFeature = protectFeature
|
||||
self.apicall = apicall
|
||||
self.apientry = apientry
|
||||
self.apientryp = apientryp
|
||||
self.alignFuncParam = alignFuncParam
|
||||
self.library_name = library_name
|
||||
self.helper_file_type = helper_file_type
|
||||
#
|
||||
# HelperFileOutputGenerator - subclass of OutputGenerator. Outputs Vulkan helper files
|
||||
class HelperFileOutputGenerator(OutputGenerator):
|
||||
"""Generate helper file based on XML element attributes"""
|
||||
def __init__(self,
|
||||
errFile = sys.stderr,
|
||||
warnFile = sys.stderr,
|
||||
diagFile = sys.stdout):
|
||||
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
||||
# Internal state - accumulators for different inner block text
|
||||
self.enum_output = '' # string built up of enum string routines
|
||||
# Internal state - accumulators for different inner block text
|
||||
self.structNames = [] # List of Vulkan struct typenames
|
||||
self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
|
||||
self.structMembers = [] # List of StructMemberData records for all Vulkan structs
|
||||
self.object_types = [] # List of all handle types
|
||||
self.object_type_aliases = [] # Aliases to handles types (for handles that were extensions)
|
||||
self.debug_report_object_types = [] # Handy copy of debug_report_object_type enum data
|
||||
self.core_object_types = [] # Handy copy of core_object_type enum data
|
||||
self.device_extension_info = dict() # Dict of device extension name defines and ifdef values
|
||||
self.instance_extension_info = dict() # Dict of instance extension name defines and ifdef values
|
||||
|
||||
# Named tuples to store struct and command data
|
||||
self.StructType = namedtuple('StructType', ['name', 'value'])
|
||||
self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl'])
|
||||
self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect'])
|
||||
|
||||
self.custom_construct_params = {
|
||||
# safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers
|
||||
'VkGraphicsPipelineCreateInfo' :
|
||||
', const bool uses_color_attachment, const bool uses_depthstencil_attachment',
|
||||
# safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers
|
||||
'VkPipelineViewportStateCreateInfo' :
|
||||
', const bool is_dynamic_viewports, const bool is_dynamic_scissors',
|
||||
}
|
||||
#
|
||||
# Called once at the beginning of each run
|
||||
def beginFile(self, genOpts):
|
||||
OutputGenerator.beginFile(self, genOpts)
|
||||
# User-supplied prefix text, if any (list of strings)
|
||||
self.helper_file_type = genOpts.helper_file_type
|
||||
self.library_name = genOpts.library_name
|
||||
# File Comment
|
||||
file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
|
||||
file_comment += '// See helper_file_generator.py for modifications\n'
|
||||
write(file_comment, file=self.outFile)
|
||||
# Copyright Notice
|
||||
copyright = ''
|
||||
copyright += '\n'
|
||||
copyright += '/***************************************************************************\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
|
||||
copyright += ' * Copyright (c) 2015-2017 Google Inc.\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
|
||||
copyright += ' * you may not use this file except in compliance with the License.\n'
|
||||
copyright += ' * You may obtain a copy of the License at\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
|
||||
copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
|
||||
copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
|
||||
copyright += ' * See the License for the specific language governing permissions and\n'
|
||||
copyright += ' * limitations under the License.\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
|
||||
copyright += ' * Author: Courtney Goeltzenleuchter <courtneygo@google.com>\n'
|
||||
copyright += ' * Author: Tobin Ehlis <tobine@google.com>\n'
|
||||
copyright += ' * Author: Chris Forbes <chrisforbes@google.com>\n'
|
||||
copyright += ' * Author: John Zulauf<jzulauf@lunarg.com>\n'
|
||||
copyright += ' *\n'
|
||||
copyright += ' ****************************************************************************/\n'
|
||||
write(copyright, file=self.outFile)
|
||||
#
|
||||
# Write generated file content to output file
|
||||
def endFile(self):
|
||||
dest_file = ''
|
||||
dest_file += self.OutputDestFile()
|
||||
# Remove blank lines at EOF
|
||||
if dest_file.endswith('\n'):
|
||||
dest_file = dest_file[:-1]
|
||||
write(dest_file, file=self.outFile);
|
||||
# Finish processing in superclass
|
||||
OutputGenerator.endFile(self)
|
||||
#
|
||||
# Override parent class to be notified of the beginning of an extension
|
||||
def beginFeature(self, interface, emit):
|
||||
# Start processing in superclass
|
||||
OutputGenerator.beginFeature(self, interface, emit)
|
||||
self.featureExtraProtect = GetFeatureProtect(interface)
|
||||
|
||||
if self.featureName == 'VK_VERSION_1_0' or self.featureName == 'VK_VERSION_1_1':
|
||||
return
|
||||
name = self.featureName
|
||||
nameElem = interface[0][1]
|
||||
name_define = nameElem.get('name')
|
||||
if 'EXTENSION_NAME' not in name_define:
|
||||
print("Error in vk.xml file -- extension name is not available")
|
||||
requires = interface.get('requires')
|
||||
if requires is not None:
|
||||
required_extensions = requires.split(',')
|
||||
else:
|
||||
required_extensions = list()
|
||||
info = { 'define': name_define, 'ifdef':self.featureExtraProtect, 'reqs':required_extensions }
|
||||
if interface.get('type') == 'instance':
|
||||
self.instance_extension_info[name] = info
|
||||
else:
|
||||
self.device_extension_info[name] = info
|
||||
|
||||
#
|
||||
# Override parent class to be notified of the end of an extension
|
||||
def endFeature(self):
|
||||
# Finish processing in superclass
|
||||
OutputGenerator.endFeature(self)
|
||||
#
|
||||
# Grab group (e.g. C "enum" type) info to output for enum-string conversion helper
|
||||
def genGroup(self, groupinfo, groupName, alias):
|
||||
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
|
||||
groupElem = groupinfo.elem
|
||||
# For enum_string_header
|
||||
if self.helper_file_type == 'enum_string_header':
|
||||
value_set = set()
|
||||
for elem in groupElem.findall('enum'):
|
||||
if elem.get('supported') != 'disabled' and elem.get('alias') is None:
|
||||
value_set.add(elem.get('name'))
|
||||
self.enum_output += self.GenerateEnumStringConversion(groupName, value_set)
|
||||
elif self.helper_file_type == 'object_types_header':
|
||||
if groupName == 'VkDebugReportObjectTypeEXT':
|
||||
for elem in groupElem.findall('enum'):
|
||||
if elem.get('supported') != 'disabled':
|
||||
item_name = elem.get('name')
|
||||
self.debug_report_object_types.append(item_name)
|
||||
elif groupName == 'VkObjectType':
|
||||
for elem in groupElem.findall('enum'):
|
||||
if elem.get('supported') != 'disabled':
|
||||
item_name = elem.get('name')
|
||||
self.core_object_types.append(item_name)
|
||||
|
||||
#
|
||||
# Called for each type -- if the type is a struct/union, grab the metadata
|
||||
def genType(self, typeinfo, name, alias):
|
||||
OutputGenerator.genType(self, typeinfo, name, alias)
|
||||
typeElem = typeinfo.elem
|
||||
# If the type is a struct type, traverse the imbedded <member> tags generating a structure.
|
||||
# Otherwise, emit the tag text.
|
||||
category = typeElem.get('category')
|
||||
if category == 'handle':
|
||||
if alias:
|
||||
self.object_type_aliases.append((name,alias))
|
||||
else:
|
||||
self.object_types.append(name)
|
||||
elif (category == 'struct' or category == 'union'):
|
||||
self.structNames.append(name)
|
||||
self.genStruct(typeinfo, name, alias)
|
||||
#
|
||||
# Generate a VkStructureType based on a structure typename
|
||||
def genVkStructureType(self, typename):
|
||||
# Add underscore between lowercase then uppercase
|
||||
value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
|
||||
# Change to uppercase
|
||||
value = value.upper()
|
||||
# Add STRUCTURE_TYPE_
|
||||
return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
|
||||
#
|
||||
# Check if the parameter passed in is a pointer
|
||||
def paramIsPointer(self, param):
|
||||
ispointer = False
|
||||
for elem in param:
|
||||
if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
|
||||
ispointer = True
|
||||
return ispointer
|
||||
#
|
||||
# Check if the parameter passed in is a static array
|
||||
def paramIsStaticArray(self, param):
|
||||
isstaticarray = 0
|
||||
paramname = param.find('name')
|
||||
if (paramname.tail is not None) and ('[' in paramname.tail):
|
||||
isstaticarray = paramname.tail.count('[')
|
||||
return isstaticarray
|
||||
#
|
||||
# Retrieve the type and name for a parameter
|
||||
def getTypeNameTuple(self, param):
|
||||
type = ''
|
||||
name = ''
|
||||
for elem in param:
|
||||
if elem.tag == 'type':
|
||||
type = noneStr(elem.text)
|
||||
elif elem.tag == 'name':
|
||||
name = noneStr(elem.text)
|
||||
return (type, name)
|
||||
# Extract length values from latexmath. Currently an inflexible solution that looks for specific
|
||||
# patterns that are found in vk.xml. Will need to be updated when new patterns are introduced.
|
||||
def parseLateXMath(self, source):
|
||||
name = 'ERROR'
|
||||
decoratedName = 'ERROR'
|
||||
if 'mathit' in source:
|
||||
# Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]'
|
||||
match = re.match(r'latexmath\s*\:\s*\[\s*\\l(\w+)\s*\{\s*\\mathit\s*\{\s*(\w+)\s*\}\s*\\over\s*(\d+)\s*\}\s*\\r(\w+)\s*\]', source)
|
||||
if not match or match.group(1) != match.group(4):
|
||||
raise 'Unrecognized latexmath expression'
|
||||
name = match.group(2)
|
||||
# Need to add 1 for ceiling function; otherwise, the allocated packet
|
||||
# size will be less than needed during capture for some title which use
|
||||
# this in VkPipelineMultisampleStateCreateInfo. based on ceiling function
|
||||
# definition,it is '{0}%{1}?{0}/{1} + 1:{0}/{1}'.format(*match.group(2, 3)),
|
||||
# its value <= '{}/{} + 1'.
|
||||
if match.group(1) == 'ceil':
|
||||
decoratedName = '{}/{} + 1'.format(*match.group(2, 3))
|
||||
else:
|
||||
decoratedName = '{}/{}'.format(*match.group(2, 3))
|
||||
else:
|
||||
# Matches expressions similar to 'latexmath : [dataSize \over 4]'
|
||||
match = re.match(r'latexmath\s*\:\s*\[\s*(\\textrm\{)?(\w+)\}?\s*\\over\s*(\d+)\s*\]', source)
|
||||
name = match.group(2)
|
||||
decoratedName = '{}/{}'.format(*match.group(2, 3))
|
||||
return name, decoratedName
|
||||
#
|
||||
# Retrieve the value of the len tag
|
||||
def getLen(self, param):
|
||||
result = None
|
||||
len = param.attrib.get('len')
|
||||
if len and len != 'null-terminated':
|
||||
# For string arrays, 'len' can look like 'count,null-terminated', indicating that we
|
||||
# have a null terminated array of strings. We strip the null-terminated from the
|
||||
# 'len' field and only return the parameter specifying the string count
|
||||
if 'null-terminated' in len:
|
||||
result = len.split(',')[0]
|
||||
else:
|
||||
result = len
|
||||
if 'latexmath' in len:
|
||||
param_type, param_name = self.getTypeNameTuple(param)
|
||||
len_name, result = self.parseLateXMath(len)
|
||||
# Spec has now notation for len attributes, using :: instead of platform specific pointer symbol
|
||||
result = str(result).replace('::', '->')
|
||||
return result
|
||||
#
|
||||
# Check if a structure is or contains a dispatchable (dispatchable = True) or
|
||||
# non-dispatchable (dispatchable = False) handle
|
||||
def TypeContainsObjectHandle(self, handle_type, dispatchable):
|
||||
if dispatchable:
|
||||
type_key = 'VK_DEFINE_HANDLE'
|
||||
else:
|
||||
type_key = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
|
||||
handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
|
||||
if handle is not None and handle.find('type').text == type_key:
|
||||
return True
|
||||
# if handle_type is a struct, search its members
|
||||
if handle_type in self.structNames:
|
||||
member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None)
|
||||
if member_index is not None:
|
||||
for item in self.structMembers[member_index].members:
|
||||
handle = self.registry.tree.find("types/type/[name='" + item.type + "'][@category='handle']")
|
||||
if handle is not None and handle.find('type').text == type_key:
|
||||
return True
|
||||
return False
|
||||
#
|
||||
# Generate local ready-access data describing Vulkan structures and unions from the XML metadata
|
||||
def genStruct(self, typeinfo, typeName, alias):
|
||||
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
|
||||
members = typeinfo.elem.findall('.//member')
|
||||
# Iterate over members once to get length parameters for arrays
|
||||
lens = set()
|
||||
for member in members:
|
||||
len = self.getLen(member)
|
||||
if len:
|
||||
lens.add(len)
|
||||
# Generate member info
|
||||
membersInfo = []
|
||||
for member in members:
|
||||
# Get the member's type and name
|
||||
info = self.getTypeNameTuple(member)
|
||||
type = info[0]
|
||||
name = info[1]
|
||||
cdecl = self.makeCParamDecl(member, 1)
|
||||
# Process VkStructureType
|
||||
if type == 'VkStructureType':
|
||||
# Extract the required struct type value from the comments
|
||||
# embedded in the original text defining the 'typeinfo' element
|
||||
rawXml = etree.tostring(typeinfo.elem).decode('ascii')
|
||||
result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
|
||||
if result:
|
||||
value = result.group(0)
|
||||
else:
|
||||
value = self.genVkStructureType(typeName)
|
||||
# Store the required type value
|
||||
self.structTypes[typeName] = self.StructType(name=name, value=value)
|
||||
# Store pointer/array/string info
|
||||
isstaticarray = self.paramIsStaticArray(member)
|
||||
membersInfo.append(self.CommandParam(type=type,
|
||||
name=name,
|
||||
ispointer=self.paramIsPointer(member),
|
||||
isstaticarray=isstaticarray,
|
||||
isconst=True if 'const' in cdecl else False,
|
||||
iscount=True if name in lens else False,
|
||||
len=self.getLen(member),
|
||||
extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None,
|
||||
cdecl=cdecl))
|
||||
self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo, ifdef_protect=self.featureExtraProtect))
|
||||
#
|
||||
# Enum_string_header: Create a routine to convert an enumerated value into a string
|
||||
def GenerateEnumStringConversion(self, groupName, value_list):
|
||||
outstring = '\n'
|
||||
outstring += 'static inline const char* string_%s(%s input_value)\n' % (groupName, groupName)
|
||||
outstring += '{\n'
|
||||
outstring += ' switch ((%s)input_value)\n' % groupName
|
||||
outstring += ' {\n'
|
||||
for item in value_list:
|
||||
outstring += ' case %s:\n' % item
|
||||
outstring += ' return "%s";\n' % item
|
||||
outstring += ' default:\n'
|
||||
outstring += ' return "Unhandled %s";\n' % groupName
|
||||
outstring += ' }\n'
|
||||
outstring += '}\n'
|
||||
return outstring
|
||||
#
|
||||
# Combine object types helper header file preamble with body text and return
|
||||
def GenerateObjectTypesHelperHeader(self):
|
||||
object_types_helper_header = '\n'
|
||||
object_types_helper_header += '#pragma once\n'
|
||||
object_types_helper_header += '\n'
|
||||
object_types_helper_header += '#include <vulkan/vulkan.h>\n\n'
|
||||
object_types_helper_header += self.GenerateObjectTypesHeader()
|
||||
return object_types_helper_header
|
||||
#
|
||||
# Object types header: create object enum type header file
|
||||
def GenerateObjectTypesHeader(self):
|
||||
object_types_header = ''
|
||||
object_types_header += '// Object Type enum for validation layer internal object handling\n'
|
||||
object_types_header += 'typedef enum VulkanObjectType {\n'
|
||||
object_types_header += ' kVulkanObjectTypeUnknown = 0,\n'
|
||||
enum_num = 1
|
||||
type_list = [];
|
||||
enum_entry_map = {}
|
||||
|
||||
# Output enum definition as each handle is processed, saving the names to use for the conversion routine
|
||||
for item in self.object_types:
|
||||
fixup_name = item[2:]
|
||||
enum_entry = 'kVulkanObjectType%s' % fixup_name
|
||||
enum_entry_map[item] = enum_entry
|
||||
object_types_header += ' ' + enum_entry
|
||||
object_types_header += ' = %d,\n' % enum_num
|
||||
enum_num += 1
|
||||
type_list.append(enum_entry)
|
||||
object_types_header += ' kVulkanObjectTypeMax = %d,\n' % enum_num
|
||||
object_types_header += ' // Aliases for backwards compatibilty of "promoted" types\n'
|
||||
for (name, alias) in self.object_type_aliases:
|
||||
fixup_name = name[2:]
|
||||
object_types_header += ' kVulkanObjectType{} = {},\n'.format(fixup_name, enum_entry_map[alias])
|
||||
object_types_header += '} VulkanObjectType;\n\n'
|
||||
|
||||
# Output name string helper
|
||||
object_types_header += '// Array of object name strings for OBJECT_TYPE enum conversion\n'
|
||||
object_types_header += 'static const char * const object_string[kVulkanObjectTypeMax] = {\n'
|
||||
object_types_header += ' "Unknown",\n'
|
||||
for item in self.object_types:
|
||||
fixup_name = item[2:]
|
||||
object_types_header += ' "%s",\n' % fixup_name
|
||||
object_types_header += '};\n'
|
||||
|
||||
# Key creation helper for map comprehensions that convert between k<Name> and VK<Name> symbols
|
||||
def to_key(regex, raw_key): return re.search(regex, raw_key).group(1).lower().replace("_","")
|
||||
|
||||
# Output a conversion routine from the layer object definitions to the debug report definitions
|
||||
# As the VK_DEBUG_REPORT types are not being updated, specify UNKNOWN for unmatched types
|
||||
object_types_header += '\n'
|
||||
object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n'
|
||||
object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n'
|
||||
object_types_header += ' VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown\n'
|
||||
|
||||
dbg_re = '^VK_DEBUG_REPORT_OBJECT_TYPE_(.*)_EXT$'
|
||||
dbg_map = {to_key(dbg_re, dbg) : dbg for dbg in self.debug_report_object_types}
|
||||
dbg_default = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT'
|
||||
for object_type in type_list:
|
||||
vk_object_type = dbg_map.get(object_type.replace("kVulkanObjectType", "").lower(), dbg_default)
|
||||
object_types_header += ' %s, // %s\n' % (vk_object_type, object_type)
|
||||
object_types_header += '};\n'
|
||||
|
||||
# Output a conversion routine from the layer object definitions to the core object type definitions
|
||||
# This will intentionally *fail* for unmatched types as the VK_OBJECT_TYPE list should match the kVulkanObjectType list
|
||||
object_types_header += '\n'
|
||||
object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n'
|
||||
object_types_header += 'const VkObjectType get_object_type_enum[] = {\n'
|
||||
object_types_header += ' VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown\n'
|
||||
|
||||
vko_re = '^VK_OBJECT_TYPE_(.*)'
|
||||
vko_map = {to_key(vko_re, vko) : vko for vko in self.core_object_types}
|
||||
for object_type in type_list:
|
||||
vk_object_type = vko_map[object_type.replace("kVulkanObjectType", "").lower()]
|
||||
object_types_header += ' %s, // %s\n' % (vk_object_type, object_type)
|
||||
object_types_header += '};\n'
|
||||
|
||||
# Create a function to convert from VkDebugReportObjectTypeEXT to VkObjectType
|
||||
object_types_header += '\n'
|
||||
object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n'
|
||||
object_types_header += 'static inline VkObjectType convertDebugReportObjectToCoreObject(VkDebugReportObjectTypeEXT debug_report_obj){\n'
|
||||
object_types_header += ' if (debug_report_obj == VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) {\n'
|
||||
object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n'
|
||||
for core_object_type in self.core_object_types:
|
||||
core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower()
|
||||
core_target_type = core_target_type.replace("_", "")
|
||||
for dr_object_type in self.debug_report_object_types:
|
||||
dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower()
|
||||
dr_target_type = dr_target_type[:-4]
|
||||
dr_target_type = dr_target_type.replace("_", "")
|
||||
if core_target_type == dr_target_type:
|
||||
object_types_header += ' } else if (debug_report_obj == %s) {\n' % dr_object_type
|
||||
object_types_header += ' return %s;\n' % core_object_type
|
||||
break
|
||||
object_types_header += ' }\n'
|
||||
object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n'
|
||||
object_types_header += '}\n'
|
||||
|
||||
# Create a function to convert from VkObjectType to VkDebugReportObjectTypeEXT
|
||||
object_types_header += '\n'
|
||||
object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n'
|
||||
object_types_header += 'static inline VkDebugReportObjectTypeEXT convertCoreObjectToDebugReportObject(VkObjectType core_report_obj){\n'
|
||||
object_types_header += ' if (core_report_obj == VK_OBJECT_TYPE_UNKNOWN) {\n'
|
||||
object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n'
|
||||
for core_object_type in self.core_object_types:
|
||||
core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower()
|
||||
core_target_type = core_target_type.replace("_", "")
|
||||
for dr_object_type in self.debug_report_object_types:
|
||||
dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower()
|
||||
dr_target_type = dr_target_type[:-4]
|
||||
dr_target_type = dr_target_type.replace("_", "")
|
||||
if core_target_type == dr_target_type:
|
||||
object_types_header += ' } else if (core_report_obj == %s) {\n' % core_object_type
|
||||
object_types_header += ' return %s;\n' % dr_object_type
|
||||
break
|
||||
object_types_header += ' }\n'
|
||||
object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n'
|
||||
object_types_header += '}\n'
|
||||
return object_types_header
|
||||
|
||||
#
|
||||
# Create a helper file and return it as a string
|
||||
def OutputDestFile(self):
|
||||
if self.helper_file_type == 'object_types_header':
|
||||
return self.GenerateObjectTypesHelperHeader()
|
||||
else:
|
||||
return 'Bad Helper File Generator Option %s' % self.helper_file_type
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"repos" : [
|
||||
{
|
||||
"name" : "Vulkan-Headers",
|
||||
"url" : "https://github.com/KhronosGroup/Vulkan-Headers.git",
|
||||
"sub_dir" : "Vulkan-Headers",
|
||||
"build_dir" : "Vulkan-Headers/build",
|
||||
"install_dir" : "Vulkan-Headers/build/install",
|
||||
"commit" : "v1.1.113"
|
||||
}
|
||||
],
|
||||
"install_names" : {
|
||||
"Vulkan-Headers" : "VULKAN_HEADERS_INSTALL_DIR"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,516 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse, cProfile, pdb, string, sys, time, os
|
||||
|
||||
# Simple timer functions
|
||||
startTime = None
|
||||
|
||||
def startTimer(timeit):
|
||||
global startTime
|
||||
if timeit:
|
||||
startTime = time.process_time()
|
||||
|
||||
def endTimer(timeit, msg):
|
||||
global startTime
|
||||
if timeit:
|
||||
endTime = time.process_time()
|
||||
write(msg, endTime - startTime, file=sys.stderr)
|
||||
startTime = None
|
||||
|
||||
# Turn a list of strings into a regexp string matching exactly those strings
|
||||
def makeREstring(list, default = None):
|
||||
if len(list) > 0 or default is None:
|
||||
return '^(' + '|'.join(list) + ')$'
|
||||
else:
|
||||
return default
|
||||
|
||||
# Returns a directory of [ generator function, generator options ] indexed
|
||||
# by specified short names. The generator options incorporate the following
|
||||
# parameters:
|
||||
#
|
||||
# args is an parsed argument object; see below for the fields that are used.
|
||||
def makeGenOpts(args):
|
||||
global genOpts
|
||||
genOpts = {}
|
||||
|
||||
# Default class of extensions to include, or None
|
||||
defaultExtensions = args.defaultExtensions
|
||||
|
||||
# Additional extensions to include (list of extensions)
|
||||
extensions = args.extension
|
||||
|
||||
# Extensions to remove (list of extensions)
|
||||
removeExtensions = args.removeExtensions
|
||||
|
||||
# Extensions to emit (list of extensions)
|
||||
emitExtensions = args.emitExtensions
|
||||
|
||||
# Features to include (list of features)
|
||||
features = args.feature
|
||||
|
||||
# Whether to disable inclusion protect in headers
|
||||
protect = args.protect
|
||||
|
||||
# Output target directory
|
||||
directory = args.directory
|
||||
|
||||
# Descriptive names for various regexp patterns used to select
|
||||
# versions and extensions
|
||||
allFeatures = allExtensions = '.*'
|
||||
noFeatures = noExtensions = None
|
||||
|
||||
# Turn lists of names/patterns into matching regular expressions
|
||||
addExtensionsPat = makeREstring(extensions, None)
|
||||
removeExtensionsPat = makeREstring(removeExtensions, None)
|
||||
emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
|
||||
featuresPat = makeREstring(features, allFeatures)
|
||||
|
||||
# Copyright text prefixing all headers (list of strings).
|
||||
prefixStrings = [
|
||||
'/*',
|
||||
'** Copyright (c) 2015-2019 The Khronos Group Inc.',
|
||||
'**',
|
||||
'** Licensed under the Apache License, Version 2.0 (the "License");',
|
||||
'** you may not use this file except in compliance with the License.',
|
||||
'** You may obtain a copy of the License at',
|
||||
'**',
|
||||
'** http://www.apache.org/licenses/LICENSE-2.0',
|
||||
'**',
|
||||
'** Unless required by applicable law or agreed to in writing, software',
|
||||
'** distributed under the License is distributed on an "AS IS" BASIS,',
|
||||
'** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
||||
'** See the License for the specific language governing permissions and',
|
||||
'** limitations under the License.',
|
||||
'*/',
|
||||
''
|
||||
]
|
||||
|
||||
# Text specific to Vulkan headers
|
||||
vkPrefixStrings = [
|
||||
'/*',
|
||||
'** This header is generated from the Khronos Vulkan XML API Registry.',
|
||||
'**',
|
||||
'*/',
|
||||
''
|
||||
]
|
||||
|
||||
# Defaults for generating re-inclusion protection wrappers (or not)
|
||||
protectFeature = protect
|
||||
|
||||
# An API style conventions object
|
||||
conventions = VulkanConventions()
|
||||
|
||||
# Loader Generators
|
||||
# Options for dispatch table helper generator
|
||||
genOpts['vk_dispatch_table_helper.h'] = [
|
||||
DispatchTableHelperOutputGenerator,
|
||||
DispatchTableHelperOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_dispatch_table_helper.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False)
|
||||
]
|
||||
|
||||
# Options for Layer dispatch table generator
|
||||
genOpts['vk_layer_dispatch_table.h'] = [
|
||||
LoaderExtensionOutputGenerator,
|
||||
LoaderExtensionGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_layer_dispatch_table.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False)
|
||||
]
|
||||
|
||||
# Options for loader extension source generator
|
||||
genOpts['vk_loader_extensions.h'] = [
|
||||
LoaderExtensionOutputGenerator,
|
||||
LoaderExtensionGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_loader_extensions.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False)
|
||||
]
|
||||
|
||||
# Options for loader extension source generator
|
||||
genOpts['vk_loader_extensions.c'] = [
|
||||
LoaderExtensionOutputGenerator,
|
||||
LoaderExtensionGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_loader_extensions.c',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False)
|
||||
]
|
||||
|
||||
# Helper file generator options for vk_enum_string_helper.h
|
||||
genOpts['vk_enum_string_helper.h'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_enum_string_helper.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'enum_string_header')
|
||||
]
|
||||
|
||||
# Helper file generator options for vk_safe_struct.h
|
||||
genOpts['vk_safe_struct.h'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_safe_struct.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'safe_struct_header')
|
||||
]
|
||||
|
||||
# Helper file generator options for vk_safe_struct.cpp
|
||||
genOpts['vk_safe_struct.cpp'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_safe_struct.cpp',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'safe_struct_source')
|
||||
]
|
||||
|
||||
# Helper file generator options for vk_object_types.h
|
||||
genOpts['vk_object_types.h'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_object_types.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'object_types_header')
|
||||
]
|
||||
|
||||
# Helper file generator options for extension_helper.h
|
||||
genOpts['vk_extension_helper.h'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_extension_helper.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'extension_helper_header')
|
||||
]
|
||||
|
||||
# Helper file generator options for typemap_helper.h
|
||||
genOpts['vk_typemap_helper.h'] = [
|
||||
HelperFileOutputGenerator,
|
||||
HelperFileOutputGeneratorOptions(
|
||||
conventions = conventions,
|
||||
filename = 'vk_typemap_helper.h',
|
||||
directory = directory,
|
||||
apiname = 'vulkan',
|
||||
profile = None,
|
||||
versions = featuresPat,
|
||||
emitversions = featuresPat,
|
||||
defaultExtensions = 'vulkan',
|
||||
addExtensions = addExtensionsPat,
|
||||
removeExtensions = removeExtensionsPat,
|
||||
emitExtensions = emitExtensionsPat,
|
||||
prefixText = prefixStrings + vkPrefixStrings,
|
||||
protectFeature = False,
|
||||
apicall = 'VKAPI_ATTR ',
|
||||
apientry = 'VKAPI_CALL ',
|
||||
apientryp = 'VKAPI_PTR *',
|
||||
alignFuncParam = 48,
|
||||
expandEnumerants = False,
|
||||
helper_file_type = 'typemap_helper_header')
|
||||
]
|
||||
|
||||
# Generate a target based on the options in the matching genOpts{} object.
|
||||
# This is encapsulated in a function so it can be profiled and/or timed.
|
||||
# The args parameter is an parsed argument object containing the following
|
||||
# fields that are used:
|
||||
# target - target to generate
|
||||
# directory - directory to generate it in
|
||||
# protect - True if re-inclusion wrappers should be created
|
||||
# extensions - list of additional extensions to include in generated
|
||||
# interfaces
|
||||
def genTarget(args):
|
||||
global genOpts
|
||||
|
||||
# Create generator options with specified parameters
|
||||
makeGenOpts(args)
|
||||
|
||||
if (args.target in genOpts.keys()):
|
||||
createGenerator = genOpts[args.target][0]
|
||||
options = genOpts[args.target][1]
|
||||
|
||||
if not args.quiet:
|
||||
write('* Building', options.filename, file=sys.stderr)
|
||||
write('* options.versions =', options.versions, file=sys.stderr)
|
||||
write('* options.emitversions =', options.emitversions, file=sys.stderr)
|
||||
write('* options.defaultExtensions =', options.defaultExtensions, file=sys.stderr)
|
||||
write('* options.addExtensions =', options.addExtensions, file=sys.stderr)
|
||||
write('* options.removeExtensions =', options.removeExtensions, file=sys.stderr)
|
||||
write('* options.emitExtensions =', options.emitExtensions, file=sys.stderr)
|
||||
|
||||
startTimer(args.time)
|
||||
gen = createGenerator(errFile=errWarn,
|
||||
warnFile=errWarn,
|
||||
diagFile=diag)
|
||||
reg.setGenerator(gen)
|
||||
reg.apiGen(options)
|
||||
|
||||
if not args.quiet:
|
||||
write('* Generated', options.filename, file=sys.stderr)
|
||||
endTimer(args.time, '* Time to generate ' + options.filename + ' =')
|
||||
else:
|
||||
write('No generator options for unknown target:',
|
||||
args.target, file=sys.stderr)
|
||||
|
||||
# -feature name
|
||||
# -extension name
|
||||
# For both, "name" may be a single name, or a space-separated list
|
||||
# of names, or a regular expression.
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('-defaultExtensions', action='store',
|
||||
default='vulkan',
|
||||
help='Specify a single class of extensions to add to targets')
|
||||
parser.add_argument('-extension', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to add to targets')
|
||||
parser.add_argument('-removeExtensions', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to remove from targets')
|
||||
parser.add_argument('-emitExtensions', action='append',
|
||||
default=[],
|
||||
help='Specify an extension or extensions to emit in targets')
|
||||
parser.add_argument('-feature', action='append',
|
||||
default=[],
|
||||
help='Specify a core API feature name or names to add to targets')
|
||||
parser.add_argument('-debug', action='store_true',
|
||||
help='Enable debugging')
|
||||
parser.add_argument('-dump', action='store_true',
|
||||
help='Enable dump to stderr')
|
||||
parser.add_argument('-diagfile', action='store',
|
||||
default=None,
|
||||
help='Write diagnostics to specified file')
|
||||
parser.add_argument('-errfile', action='store',
|
||||
default=None,
|
||||
help='Write errors and warnings to specified file instead of stderr')
|
||||
parser.add_argument('-noprotect', dest='protect', action='store_false',
|
||||
help='Disable inclusion protection in output headers')
|
||||
parser.add_argument('-profile', action='store_true',
|
||||
help='Enable profiling')
|
||||
parser.add_argument('-registry', action='store',
|
||||
default='vk.xml',
|
||||
help='Use specified registry file instead of vk.xml')
|
||||
parser.add_argument('-time', action='store_true',
|
||||
help='Enable timing')
|
||||
parser.add_argument('-validate', action='store_true',
|
||||
help='Enable group validation')
|
||||
parser.add_argument('-o', action='store', dest='directory',
|
||||
default='.',
|
||||
help='Create target and related files in specified directory')
|
||||
parser.add_argument('target', metavar='target', nargs='?',
|
||||
help='Specify target')
|
||||
parser.add_argument('-quiet', action='store_true', default=True,
|
||||
help='Suppress script output during normal execution.')
|
||||
parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
|
||||
help='Enable script output during normal execution.')
|
||||
|
||||
# This argument tells us where to load the script from the Vulkan-Headers registry
|
||||
parser.add_argument('-scripts', action='store',
|
||||
help='Find additional scripts in this directory')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
scripts_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
registry_dir = os.path.join(scripts_dir, args.scripts)
|
||||
sys.path.insert(0, registry_dir)
|
||||
|
||||
# The imports need to be done here so that they can be picked up from Vulkan-Headers
|
||||
from reg import *
|
||||
from generator import write
|
||||
from cgenerator import CGeneratorOptions, COutputGenerator
|
||||
|
||||
from dispatch_table_helper_generator import DispatchTableHelperOutputGenerator, DispatchTableHelperOutputGeneratorOptions
|
||||
from helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
|
||||
from loader_extension_generator import LoaderExtensionOutputGenerator, LoaderExtensionGeneratorOptions
|
||||
# Temporary workaround for vkconventions python2 compatibility
|
||||
import abc; abc.ABC = abc.ABCMeta('ABC', (object,), {})
|
||||
from vkconventions import VulkanConventions
|
||||
|
||||
# This splits arguments which are space-separated lists
|
||||
args.feature = [name for arg in args.feature for name in arg.split()]
|
||||
args.extension = [name for arg in args.extension for name in arg.split()]
|
||||
|
||||
# Load & parse registry
|
||||
reg = Registry()
|
||||
|
||||
startTimer(args.time)
|
||||
tree = etree.parse(args.registry)
|
||||
endTimer(args.time, '* Time to make ElementTree =')
|
||||
|
||||
if args.debug:
|
||||
pdb.run('reg.loadElementTree(tree)')
|
||||
else:
|
||||
startTimer(args.time)
|
||||
reg.loadElementTree(tree)
|
||||
endTimer(args.time, '* Time to parse ElementTree =')
|
||||
|
||||
if (args.validate):
|
||||
reg.validateGroups()
|
||||
|
||||
if (args.dump):
|
||||
write('* Dumping registry to regdump.txt', file=sys.stderr)
|
||||
reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
|
||||
|
||||
# create error/warning & diagnostic files
|
||||
if (args.errfile):
|
||||
errWarn = open(args.errfile, 'w', encoding='utf-8')
|
||||
else:
|
||||
errWarn = sys.stderr
|
||||
|
||||
if (args.diagfile):
|
||||
diag = open(args.diagfile, 'w', encoding='utf-8')
|
||||
else:
|
||||
diag = None
|
||||
|
||||
if (args.debug):
|
||||
pdb.run('genTarget(args)')
|
||||
elif (args.profile):
|
||||
import cProfile, pstats
|
||||
cProfile.run('genTarget(args)', 'profile.txt')
|
||||
p = pstats.Stats('profile.txt')
|
||||
p.strip_dirs().sort_stats('time').print_stats(50)
|
||||
else:
|
||||
genTarget(args)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,679 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2017 The Glslang Authors. All rights reserved.
|
||||
# Copyright (c) 2018 Valve Corporation
|
||||
# Copyright (c) 2018 LunarG, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This script was heavily leveraged from KhronosGroup/glslang
|
||||
# update_glslang_sources.py.
|
||||
"""update_deps.py
|
||||
|
||||
Get and build dependent repositories using known-good commits.
|
||||
|
||||
Purpose
|
||||
-------
|
||||
|
||||
This program is intended to assist a developer of this repository
|
||||
(the "home" repository) by gathering and building the repositories that
|
||||
this home repository depend on. It also checks out each dependent
|
||||
repository at a "known-good" commit in order to provide stability in
|
||||
the dependent repositories.
|
||||
|
||||
Python Compatibility
|
||||
--------------------
|
||||
|
||||
This program can be used with Python 2.7 and Python 3.
|
||||
|
||||
Known-Good JSON Database
|
||||
------------------------
|
||||
|
||||
This program expects to find a file named "known-good.json" in the
|
||||
same directory as the program file. This JSON file is tailored for
|
||||
the needs of the home repository by including its dependent repositories.
|
||||
|
||||
Program Options
|
||||
---------------
|
||||
|
||||
See the help text (update_deps.py --help) for a complete list of options.
|
||||
|
||||
Program Operation
|
||||
-----------------
|
||||
|
||||
The program uses the user's current directory at the time of program
|
||||
invocation as the location for fetching and building the dependent
|
||||
repositories. The user can override this by using the "--dir" option.
|
||||
|
||||
For example, a directory named "build" in the repository's root directory
|
||||
is a good place to put the dependent repositories because that directory
|
||||
is not tracked by Git. (See the .gitignore file.) The "external" directory
|
||||
may also be a suitable location.
|
||||
A user can issue:
|
||||
|
||||
$ cd My-Repo
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../scripts/update_deps.py
|
||||
|
||||
or, to do the same thing, but using the --dir option:
|
||||
|
||||
$ cd My-Repo
|
||||
$ mkdir build
|
||||
$ scripts/update_deps.py --dir=build
|
||||
|
||||
With these commands, the "build" directory is considered the "top"
|
||||
directory where the program clones the dependent repositories. The
|
||||
JSON file configures the build and install working directories to be
|
||||
within this "top" directory.
|
||||
|
||||
Note that the "dir" option can also specify an absolute path:
|
||||
|
||||
$ cd My-Repo
|
||||
$ scripts/update_deps.py --dir=/tmp/deps
|
||||
|
||||
The "top" dir is then /tmp/deps (Linux filesystem example) and is
|
||||
where this program will clone and build the dependent repositories.
|
||||
|
||||
Helper CMake Config File
|
||||
------------------------
|
||||
|
||||
When the program finishes building the dependencies, it writes a file
|
||||
named "helper.cmake" to the "top" directory that contains CMake commands
|
||||
for setting CMake variables for locating the dependent repositories.
|
||||
This helper file can be used to set up the CMake build files for this
|
||||
"home" repository.
|
||||
|
||||
A complete sequence might look like:
|
||||
|
||||
$ git clone git@github.com:My-Group/My-Repo.git
|
||||
$ cd My-Repo
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../scripts/update_deps.py
|
||||
$ cmake -C helper.cmake ..
|
||||
$ cmake --build .
|
||||
|
||||
JSON File Schema
|
||||
----------------
|
||||
|
||||
There's no formal schema for the "known-good" JSON file, but here is
|
||||
a description of its elements. All elements are required except those
|
||||
marked as optional. Please see the "known_good.json" file for
|
||||
examples of all of these elements.
|
||||
|
||||
- name
|
||||
|
||||
The name of the dependent repository. This field can be referenced
|
||||
by the "deps.repo_name" structure to record a dependency.
|
||||
|
||||
- url
|
||||
|
||||
Specifies the URL of the repository.
|
||||
Example: https://github.com/KhronosGroup/Vulkan-Loader.git
|
||||
|
||||
- sub_dir
|
||||
|
||||
The directory where the program clones the repository, relative to
|
||||
the "top" directory.
|
||||
|
||||
- build_dir
|
||||
|
||||
The directory used to build the repository, relative to the "top"
|
||||
directory.
|
||||
|
||||
- install_dir
|
||||
|
||||
The directory used to store the installed build artifacts, relative
|
||||
to the "top" directory.
|
||||
|
||||
- commit
|
||||
|
||||
The commit used to checkout the repository. This can be a SHA-1
|
||||
object name or a refname used with the remote name "origin".
|
||||
For example, this field can be set to "origin/sdk-1.1.77" to
|
||||
select the end of the sdk-1.1.77 branch.
|
||||
|
||||
- deps (optional)
|
||||
|
||||
An array of pairs consisting of a CMake variable name and a
|
||||
repository name to specify a dependent repo and a "link" to
|
||||
that repo's install artifacts. For example:
|
||||
|
||||
"deps" : [
|
||||
{
|
||||
"var_name" : "VULKAN_HEADERS_INSTALL_DIR",
|
||||
"repo_name" : "Vulkan-Headers"
|
||||
}
|
||||
]
|
||||
|
||||
which represents that this repository depends on the Vulkan-Headers
|
||||
repository and uses the VULKAN_HEADERS_INSTALL_DIR CMake variable to
|
||||
specify the location where it expects to find the Vulkan-Headers install
|
||||
directory.
|
||||
Note that the "repo_name" element must match the "name" element of some
|
||||
other repository in the JSON file.
|
||||
|
||||
- prebuild (optional)
|
||||
- prebuild_linux (optional) (For Linux and MacOS)
|
||||
- prebuild_windows (optional)
|
||||
|
||||
A list of commands to execute before building a dependent repository.
|
||||
This is useful for repositories that require the execution of some
|
||||
sort of "update" script or need to clone an auxillary repository like
|
||||
googletest.
|
||||
|
||||
The commands listed in "prebuild" are executed first, and then the
|
||||
commands for the specific platform are executed.
|
||||
|
||||
- custom_build (optional)
|
||||
|
||||
A list of commands to execute as a custom build instead of using
|
||||
the built in CMake way of building. Requires "build_step" to be
|
||||
set to "custom"
|
||||
|
||||
You can insert the following keywords into the commands listed in
|
||||
"custom_build" if they require runtime information (like whether the
|
||||
build config is "Debug" or "Release").
|
||||
|
||||
Keywords:
|
||||
{0} reference to a dictionary of repos and their attributes
|
||||
{1} reference to the command line arguments set before start
|
||||
{2} reference to the CONFIG_MAP value of config.
|
||||
|
||||
Example:
|
||||
{2} returns the CONFIG_MAP value of config e.g. debug -> Debug
|
||||
{1}.config returns the config variable set when you ran update_dep.py
|
||||
{0}[Vulkan-Headers][repo_root] returns the repo_root variable from
|
||||
the Vulkan-Headers GoodRepo object.
|
||||
|
||||
- cmake_options (optional)
|
||||
|
||||
A list of options to pass to CMake during the generation phase.
|
||||
|
||||
- ci_only (optional)
|
||||
|
||||
A list of environment variables where one must be set to "true"
|
||||
(case-insensitive) in order for this repo to be fetched and built.
|
||||
This list can be used to specify repos that should be built only in CI.
|
||||
Typically, this list might contain "TRAVIS" and/or "APPVEYOR" because
|
||||
each of these CI systems sets an environment variable with its own
|
||||
name to "true". Note that this could also be (ab)used to control
|
||||
the processing of the repo with any environment variable. The default
|
||||
is an empty list, which means that the repo is always processed.
|
||||
|
||||
- build_step (optional)
|
||||
|
||||
Specifies if the dependent repository should be built or not. This can
|
||||
have a value of 'build', 'custom', or 'skip'. The dependent repositories are
|
||||
built by default.
|
||||
|
||||
- build_platforms (optional)
|
||||
|
||||
A list of platforms the repository will be built on.
|
||||
Legal options include:
|
||||
"windows"
|
||||
"linux"
|
||||
"darwin"
|
||||
|
||||
Builds on all platforms by default.
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
The "sub_dir", "build_dir", and "install_dir" elements are all relative
|
||||
to the effective "top" directory. Specifying absolute paths is not
|
||||
supported. However, the "top" directory specified with the "--dir"
|
||||
option can be a relative or absolute path.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import distutils.dir_util
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
import platform
|
||||
import multiprocessing
|
||||
import shlex
|
||||
import shutil
|
||||
|
||||
KNOWN_GOOD_FILE_NAME = 'known_good.json'
|
||||
|
||||
CONFIG_MAP = {
|
||||
'debug': 'Debug',
|
||||
'release': 'Release',
|
||||
'relwithdebinfo': 'RelWithDebInfo',
|
||||
'minsizerel': 'MinSizeRel'
|
||||
}
|
||||
|
||||
VERBOSE = False
|
||||
|
||||
DEVNULL = open(os.devnull, 'wb')
|
||||
|
||||
|
||||
def command_output(cmd, directory, fail_ok=False):
|
||||
"""Runs a command in a directory and returns its standard output stream.
|
||||
|
||||
Captures the standard error stream and prints it if error.
|
||||
|
||||
Raises a RuntimeError if the command fails to launch or otherwise fails.
|
||||
"""
|
||||
if VERBOSE:
|
||||
print('In {d}: {cmd}'.format(d=directory, cmd=cmd))
|
||||
p = subprocess.Popen(
|
||||
cmd, cwd=directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(stdout, stderr) = p.communicate()
|
||||
if p.returncode != 0:
|
||||
print('*** Error ***\nstderr contents:\n{}'.format(stderr))
|
||||
if not fail_ok:
|
||||
raise RuntimeError('Failed to run {} in {}'.format(cmd, directory))
|
||||
if VERBOSE:
|
||||
print(stdout)
|
||||
return stdout
|
||||
|
||||
class GoodRepo(object):
|
||||
"""Represents a repository at a known-good commit."""
|
||||
|
||||
def __init__(self, json, args):
|
||||
"""Initializes this good repo object.
|
||||
|
||||
Args:
|
||||
'json': A fully populated JSON object describing the repo.
|
||||
'args': Results from ArgumentParser
|
||||
"""
|
||||
self._json = json
|
||||
self._args = args
|
||||
# Required JSON elements
|
||||
self.name = json['name']
|
||||
self.url = json['url']
|
||||
self.sub_dir = json['sub_dir']
|
||||
self.commit = json['commit']
|
||||
# Optional JSON elements
|
||||
self.build_dir = None
|
||||
self.install_dir = None
|
||||
if json.get('build_dir'):
|
||||
self.build_dir = os.path.normpath(json['build_dir'])
|
||||
if json.get('install_dir'):
|
||||
self.install_dir = os.path.normpath(json['install_dir'])
|
||||
self.deps = json['deps'] if ('deps' in json) else []
|
||||
self.prebuild = json['prebuild'] if ('prebuild' in json) else []
|
||||
self.prebuild_linux = json['prebuild_linux'] if (
|
||||
'prebuild_linux' in json) else []
|
||||
self.prebuild_windows = json['prebuild_windows'] if (
|
||||
'prebuild_windows' in json) else []
|
||||
self.custom_build = json['custom_build'] if ('custom_build' in json) else []
|
||||
self.cmake_options = json['cmake_options'] if (
|
||||
'cmake_options' in json) else []
|
||||
self.ci_only = json['ci_only'] if ('ci_only' in json) else []
|
||||
self.build_step = json['build_step'] if ('build_step' in json) else 'build'
|
||||
self.build_platforms = json['build_platforms'] if ('build_platforms' in json) else []
|
||||
# Absolute paths for a repo's directories
|
||||
dir_top = os.path.abspath(args.dir)
|
||||
self.repo_dir = os.path.join(dir_top, self.sub_dir)
|
||||
if self.build_dir:
|
||||
self.build_dir = os.path.join(dir_top, self.build_dir)
|
||||
if self.install_dir:
|
||||
self.install_dir = os.path.join(dir_top, self.install_dir)
|
||||
# Check if platform is one to build on
|
||||
self.on_build_platform = False
|
||||
if self.build_platforms == [] or platform.system().lower() in self.build_platforms:
|
||||
self.on_build_platform = True
|
||||
|
||||
def Clone(self):
|
||||
distutils.dir_util.mkpath(self.repo_dir)
|
||||
command_output(['git', 'clone', self.url, '.'], self.repo_dir)
|
||||
|
||||
def Fetch(self):
|
||||
command_output(['git', 'fetch', 'origin'], self.repo_dir)
|
||||
|
||||
def Checkout(self):
|
||||
print('Checking out {n} in {d}'.format(n=self.name, d=self.repo_dir))
|
||||
if self._args.do_clean_repo:
|
||||
shutil.rmtree(self.repo_dir, ignore_errors=True)
|
||||
if not os.path.exists(os.path.join(self.repo_dir, '.git')):
|
||||
self.Clone()
|
||||
self.Fetch()
|
||||
if len(self._args.ref):
|
||||
command_output(['git', 'checkout', self._args.ref], self.repo_dir)
|
||||
else:
|
||||
command_output(['git', 'checkout', self.commit], self.repo_dir)
|
||||
print(command_output(['git', 'status'], self.repo_dir))
|
||||
|
||||
def CustomPreProcess(self, cmd_str, repo_dict):
|
||||
return cmd_str.format(repo_dict, self._args, CONFIG_MAP[self._args.config])
|
||||
|
||||
def PreBuild(self):
|
||||
"""Execute any prebuild steps from the repo root"""
|
||||
for p in self.prebuild:
|
||||
command_output(shlex.split(p), self.repo_dir)
|
||||
if platform.system() == 'Linux' or platform.system() == 'Darwin':
|
||||
for p in self.prebuild_linux:
|
||||
command_output(shlex.split(p), self.repo_dir)
|
||||
if platform.system() == 'Windows':
|
||||
for p in self.prebuild_windows:
|
||||
command_output(shlex.split(p), self.repo_dir)
|
||||
|
||||
def CustomBuild(self, repo_dict):
|
||||
"""Execute any custom_build steps from the repo root"""
|
||||
for p in self.custom_build:
|
||||
cmd = self.CustomPreProcess(p, repo_dict)
|
||||
command_output(shlex.split(cmd), self.repo_dir)
|
||||
|
||||
def CMakeConfig(self, repos):
|
||||
"""Build CMake command for the configuration phase and execute it"""
|
||||
if self._args.do_clean_build:
|
||||
shutil.rmtree(self.build_dir)
|
||||
if self._args.do_clean_install:
|
||||
shutil.rmtree(self.install_dir)
|
||||
|
||||
# Create and change to build directory
|
||||
distutils.dir_util.mkpath(self.build_dir)
|
||||
os.chdir(self.build_dir)
|
||||
|
||||
cmake_cmd = [
|
||||
'cmake', self.repo_dir,
|
||||
'-DCMAKE_INSTALL_PREFIX=' + self.install_dir
|
||||
]
|
||||
|
||||
# For each repo this repo depends on, generate a CMake variable
|
||||
# definitions for "...INSTALL_DIR" that points to that dependent
|
||||
# repo's install dir.
|
||||
for d in self.deps:
|
||||
dep_commit = [r for r in repos if r.name == d['repo_name']]
|
||||
if len(dep_commit):
|
||||
cmake_cmd.append('-D{var_name}={install_dir}'.format(
|
||||
var_name=d['var_name'],
|
||||
install_dir=dep_commit[0].install_dir))
|
||||
|
||||
# Add any CMake options
|
||||
for option in self.cmake_options:
|
||||
cmake_cmd.append(option)
|
||||
|
||||
# Set build config for single-configuration generators
|
||||
if platform.system() == 'Linux' or platform.system() == 'Darwin':
|
||||
cmake_cmd.append('-DCMAKE_BUILD_TYPE={config}'.format(
|
||||
config=CONFIG_MAP[self._args.config]))
|
||||
|
||||
# Use the CMake -A option to select the platform architecture
|
||||
# without needing a Visual Studio generator.
|
||||
if platform.system() == 'Windows':
|
||||
if self._args.arch == '64' or self._args.arch == 'x64' or self._args.arch == 'win64':
|
||||
cmake_cmd.append('-A')
|
||||
cmake_cmd.append('x64')
|
||||
|
||||
# Apply a generator, if one is specified. This can be used to supply
|
||||
# a specific generator for the dependent repositories to match
|
||||
# that of the main repository.
|
||||
if self._args.generator is not None:
|
||||
cmake_cmd.extend(['-G', self._args.generator])
|
||||
|
||||
if VERBOSE:
|
||||
print("CMake command: " + " ".join(cmake_cmd))
|
||||
|
||||
ret_code = subprocess.call(cmake_cmd)
|
||||
if ret_code != 0:
|
||||
sys.exit(ret_code)
|
||||
|
||||
def CMakeBuild(self):
|
||||
"""Build CMake command for the build phase and execute it"""
|
||||
cmake_cmd = ['cmake', '--build', self.build_dir, '--target', 'install']
|
||||
if self._args.do_clean:
|
||||
cmake_cmd.append('--clean-first')
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
cmake_cmd.append('--config')
|
||||
cmake_cmd.append(CONFIG_MAP[self._args.config])
|
||||
|
||||
# Speed up the build.
|
||||
if platform.system() == 'Linux' or platform.system() == 'Darwin':
|
||||
cmake_cmd.append('--')
|
||||
num_make_jobs = multiprocessing.cpu_count()
|
||||
env_make_jobs = os.environ.get('MAKE_JOBS', None)
|
||||
if env_make_jobs is not None:
|
||||
try:
|
||||
num_make_jobs = min(num_make_jobs, int(env_make_jobs))
|
||||
except ValueError:
|
||||
print('warning: environment variable MAKE_JOBS has non-numeric value "{}". '
|
||||
'Using {} (CPU count) instead.'.format(env_make_jobs, num_make_jobs))
|
||||
cmake_cmd.append('-j{}'.format(num_make_jobs))
|
||||
if platform.system() == 'Windows':
|
||||
cmake_cmd.append('--')
|
||||
cmake_cmd.append('/maxcpucount')
|
||||
|
||||
if VERBOSE:
|
||||
print("CMake command: " + " ".join(cmake_cmd))
|
||||
|
||||
ret_code = subprocess.call(cmake_cmd)
|
||||
if ret_code != 0:
|
||||
sys.exit(ret_code)
|
||||
|
||||
def Build(self, repos, repo_dict):
|
||||
"""Build the dependent repo"""
|
||||
print('Building {n} in {d}'.format(n=self.name, d=self.repo_dir))
|
||||
print('Build dir = {b}'.format(b=self.build_dir))
|
||||
print('Install dir = {i}\n'.format(i=self.install_dir))
|
||||
|
||||
# Run any prebuild commands
|
||||
self.PreBuild()
|
||||
|
||||
if self.build_step == 'custom':
|
||||
self.CustomBuild(repo_dict)
|
||||
return
|
||||
|
||||
# Build and execute CMake command for creating build files
|
||||
self.CMakeConfig(repos)
|
||||
|
||||
# Build and execute CMake command for the build
|
||||
self.CMakeBuild()
|
||||
|
||||
|
||||
def GetGoodRepos(args):
|
||||
"""Returns the latest list of GoodRepo objects.
|
||||
|
||||
The known-good file is expected to be in the same
|
||||
directory as this script unless overridden by the 'known_good_dir'
|
||||
parameter.
|
||||
"""
|
||||
if args.known_good_dir:
|
||||
known_good_file = os.path.join( os.path.abspath(args.known_good_dir),
|
||||
KNOWN_GOOD_FILE_NAME)
|
||||
else:
|
||||
known_good_file = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME)
|
||||
with open(known_good_file) as known_good:
|
||||
return [
|
||||
GoodRepo(repo, args)
|
||||
for repo in json.loads(known_good.read())['repos']
|
||||
]
|
||||
|
||||
|
||||
def GetInstallNames(args):
|
||||
"""Returns the install names list.
|
||||
|
||||
The known-good file is expected to be in the same
|
||||
directory as this script unless overridden by the 'known_good_dir'
|
||||
parameter.
|
||||
"""
|
||||
if args.known_good_dir:
|
||||
known_good_file = os.path.join(os.path.abspath(args.known_good_dir),
|
||||
KNOWN_GOOD_FILE_NAME)
|
||||
else:
|
||||
known_good_file = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME)
|
||||
with open(known_good_file) as known_good:
|
||||
install_info = json.loads(known_good.read())
|
||||
if install_info.get('install_names'):
|
||||
return install_info['install_names']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def CreateHelper(args, repos, filename):
|
||||
"""Create a CMake config helper file.
|
||||
|
||||
The helper file is intended to be used with 'cmake -C <file>'
|
||||
to build this home repo using the dependencies built by this script.
|
||||
|
||||
The install_names dictionary represents the CMake variables used by the
|
||||
home repo to locate the install dirs of the dependent repos.
|
||||
This information is baked into the CMake files of the home repo and so
|
||||
this dictionary is kept with the repo via the json file.
|
||||
"""
|
||||
def escape(path):
|
||||
return path.replace('\\', '\\\\')
|
||||
install_names = GetInstallNames(args)
|
||||
with open(filename, 'w') as helper_file:
|
||||
for repo in repos:
|
||||
if install_names and repo.name in install_names and repo.on_build_platform:
|
||||
helper_file.write('set({var} "{dir}" CACHE STRING "" FORCE)\n'
|
||||
.format(
|
||||
var=install_names[repo.name],
|
||||
dir=escape(repo.install_dir)))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Get and build dependent repos at known-good commits')
|
||||
parser.add_argument(
|
||||
'--known_good_dir',
|
||||
dest='known_good_dir',
|
||||
help="Specify directory for known_good.json file.")
|
||||
parser.add_argument(
|
||||
'--dir',
|
||||
dest='dir',
|
||||
default='.',
|
||||
help="Set target directory for repository roots. Default is \'.\'.")
|
||||
parser.add_argument(
|
||||
'--ref',
|
||||
dest='ref',
|
||||
default='',
|
||||
help="Override 'commit' with git reference. E.g., 'origin/master'")
|
||||
parser.add_argument(
|
||||
'--no-build',
|
||||
dest='do_build',
|
||||
action='store_false',
|
||||
help=
|
||||
"Clone/update repositories and generate build files without performing compilation",
|
||||
default=True)
|
||||
parser.add_argument(
|
||||
'--clean',
|
||||
dest='do_clean',
|
||||
action='store_true',
|
||||
help="Clean files generated by compiler and linker before building",
|
||||
default=False)
|
||||
parser.add_argument(
|
||||
'--clean-repo',
|
||||
dest='do_clean_repo',
|
||||
action='store_true',
|
||||
help="Delete repository directory before building",
|
||||
default=False)
|
||||
parser.add_argument(
|
||||
'--clean-build',
|
||||
dest='do_clean_build',
|
||||
action='store_true',
|
||||
help="Delete build directory before building",
|
||||
default=False)
|
||||
parser.add_argument(
|
||||
'--clean-install',
|
||||
dest='do_clean_install',
|
||||
action='store_true',
|
||||
help="Delete install directory before building",
|
||||
default=False)
|
||||
parser.add_argument(
|
||||
'--arch',
|
||||
dest='arch',
|
||||
choices=['32', '64', 'x86', 'x64', 'win32', 'win64'],
|
||||
type=str.lower,
|
||||
help="Set build files architecture (Windows)",
|
||||
default='64')
|
||||
parser.add_argument(
|
||||
'--config',
|
||||
dest='config',
|
||||
choices=['debug', 'release', 'relwithdebinfo', 'minsizerel'],
|
||||
type=str.lower,
|
||||
help="Set build files configuration",
|
||||
default='debug')
|
||||
parser.add_argument(
|
||||
'--generator',
|
||||
dest='generator',
|
||||
help="Set the CMake generator",
|
||||
default=None)
|
||||
|
||||
args = parser.parse_args()
|
||||
save_cwd = os.getcwd()
|
||||
|
||||
# Create working "top" directory if needed
|
||||
distutils.dir_util.mkpath(args.dir)
|
||||
abs_top_dir = os.path.abspath(args.dir)
|
||||
|
||||
repos = GetGoodRepos(args)
|
||||
repo_dict = {}
|
||||
|
||||
print('Starting builds in {d}'.format(d=abs_top_dir))
|
||||
for repo in repos:
|
||||
# If the repo has a platform whitelist, skip the repo
|
||||
# unless we are building on a whitelisted platform.
|
||||
if not repo.on_build_platform:
|
||||
continue
|
||||
|
||||
field_list = ('url',
|
||||
'sub_dir',
|
||||
'commit',
|
||||
'build_dir',
|
||||
'install_dir',
|
||||
'deps',
|
||||
'prebuild',
|
||||
'prebuild_linux',
|
||||
'prebuild_windows',
|
||||
'custom_build',
|
||||
'cmake_options',
|
||||
'ci_only',
|
||||
'build_step',
|
||||
'build_platforms',
|
||||
'repo_dir',
|
||||
'on_build_platform')
|
||||
repo_dict[repo.name] = {field: getattr(repo, field) for field in field_list}
|
||||
|
||||
# If the repo has a CI whitelist, skip the repo unless
|
||||
# one of the CI's environment variable is set to true.
|
||||
if len(repo.ci_only):
|
||||
do_build = False
|
||||
for env in repo.ci_only:
|
||||
if not env in os.environ:
|
||||
continue
|
||||
if os.environ[env].lower() == 'true':
|
||||
do_build = True
|
||||
break
|
||||
if not do_build:
|
||||
continue
|
||||
|
||||
# Clone/update the repository
|
||||
repo.Checkout()
|
||||
|
||||
# Build the repository
|
||||
if args.do_build and repo.build_step != 'skip':
|
||||
repo.Build(repos, repo_dict)
|
||||
|
||||
# Need to restore original cwd in order for CreateHelper to find json file
|
||||
os.chdir(save_cwd)
|
||||
CreateHelper(args, repos, os.path.join(abs_top_dir, 'helper.cmake'))
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,234 +0,0 @@
|
|||
#!/usr/bin/python3 -i
|
||||
#
|
||||
# Copyright (c) 2013-2019 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Working-group-specific style conventions,
|
||||
# used in generation.
|
||||
|
||||
import re
|
||||
|
||||
from conventions import ConventionsBase
|
||||
|
||||
|
||||
class VulkanConventions(ConventionsBase):
|
||||
def formatExtension(self, name):
|
||||
"""Mark up a name as an extension for the spec."""
|
||||
return '`<<{}>>`'.format(name)
|
||||
|
||||
@property
|
||||
def null(self):
|
||||
"""Preferred spelling of NULL."""
|
||||
return '`NULL`'
|
||||
|
||||
@property
|
||||
def constFlagBits(self):
|
||||
"""Returns True if static const flag bits should be generated, False if an enumerated type should be generated."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def struct_macro(self):
|
||||
return 'sname:'
|
||||
|
||||
@property
|
||||
def external_macro(self):
|
||||
return 'code:'
|
||||
|
||||
@property
|
||||
def structtype_member_name(self):
|
||||
"""Return name of the structure type member"""
|
||||
return 'sType'
|
||||
|
||||
@property
|
||||
def nextpointer_member_name(self):
|
||||
"""Return name of the structure pointer chain member"""
|
||||
return 'pNext'
|
||||
|
||||
@property
|
||||
def valid_pointer_prefix(self):
|
||||
"""Return prefix to pointers which must themselves be valid"""
|
||||
return 'valid'
|
||||
|
||||
def is_structure_type_member(self, paramtype, paramname):
|
||||
"""Determine if member type and name match the structure type member."""
|
||||
return paramtype == 'VkStructureType' and paramname == self.structtype_member_name
|
||||
|
||||
def is_nextpointer_member(self, paramtype, paramname):
|
||||
"""Determine if member type and name match the next pointer chain member."""
|
||||
return paramtype == 'void' and paramname == self.nextpointer_member_name
|
||||
|
||||
def generate_structure_type_from_name(self, structname):
|
||||
"""Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
|
||||
structure_type_parts = []
|
||||
# Tokenize into "words"
|
||||
for elem in re.findall(r'(([A-Z][a-z]+)|([A-Z][A-Z]+))', structname):
|
||||
if elem[0] == 'Vk':
|
||||
structure_type_parts.append('VK_STRUCTURE_TYPE')
|
||||
else:
|
||||
structure_type_parts.append(elem[0].upper())
|
||||
return '_'.join(structure_type_parts)
|
||||
|
||||
@property
|
||||
def warning_comment(self):
|
||||
"""Return warning comment to be placed in header of generated Asciidoctor files"""
|
||||
return '// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry'
|
||||
|
||||
@property
|
||||
def file_suffix(self):
|
||||
"""Return suffix of generated Asciidoctor files"""
|
||||
return '.txt'
|
||||
|
||||
def api_name(self, spectype = 'api'):
|
||||
"""Return API or specification name for citations in ref pages.ref
|
||||
pages should link to for
|
||||
|
||||
spectype is the spec this refpage is for: 'api' is the Vulkan API
|
||||
Specification. Defaults to 'api'. If an unrecognized spectype is
|
||||
given, returns None.
|
||||
"""
|
||||
if spectype == 'api' or spectype is None:
|
||||
return 'Vulkan'
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def xml_supported_name_of_api(self):
|
||||
"""Return the supported= attribute used in API XML"""
|
||||
return 'vulkan'
|
||||
|
||||
@property
|
||||
def api_prefix(self):
|
||||
"""Return API token prefix"""
|
||||
return 'VK_'
|
||||
|
||||
@property
|
||||
def api_version_prefix(self):
|
||||
"""Return API core version token prefix"""
|
||||
return 'VK_VERSION_'
|
||||
|
||||
@property
|
||||
def KHR_prefix(self):
|
||||
"""Return extension name prefix for KHR extensions"""
|
||||
return 'VK_KHR_'
|
||||
|
||||
@property
|
||||
def EXT_prefix(self):
|
||||
"""Return extension name prefix for EXT extensions"""
|
||||
return 'VK_EXT_'
|
||||
|
||||
@property
|
||||
def write_contacts(self):
|
||||
"""Return whether contact list should be written to extension appendices"""
|
||||
return True
|
||||
|
||||
@property
|
||||
def write_refpage_include(self):
|
||||
"""Return whether refpage include should be written to extension appendices"""
|
||||
return True
|
||||
|
||||
def writeFeature(self, featureExtraProtect, filename):
|
||||
"""Returns True if OutputGenerator.endFeature should write this feature.
|
||||
Used in COutputGenerator
|
||||
"""
|
||||
return True
|
||||
|
||||
def requires_error_validation(self, return_type):
|
||||
"""Returns True if the return_type element is an API result code
|
||||
requiring error validation.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def required_errors(self):
|
||||
"""Return a list of required error codes for validation."""
|
||||
return []
|
||||
|
||||
def is_externsync_command(self, protoname):
|
||||
"""Returns True if the protoname element is an API command requiring
|
||||
external synchronization
|
||||
"""
|
||||
return protoname is not None and 'vkCmd' in protoname
|
||||
|
||||
def is_api_name(self, name):
|
||||
"""Returns True if name is in the reserved API namespace.
|
||||
For Vulkan, these are names with a case-insensitive 'vk' prefix, or
|
||||
a 'PFN_vk' function pointer type prefix.
|
||||
"""
|
||||
return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk'
|
||||
|
||||
def is_voidpointer_alias(self, tag, text, tail):
|
||||
"""Return True if the declaration components (tag,text,tail) of an
|
||||
element represents a void * type
|
||||
"""
|
||||
return tag == 'type' and text == 'void' and tail.startswith('*')
|
||||
|
||||
def make_voidpointer_alias(self, tail):
|
||||
"""Reformat a void * declaration to include the API alias macro.
|
||||
Vulkan doesn't have an API alias macro, so do nothing.
|
||||
"""
|
||||
return tail
|
||||
|
||||
def specURL(self, spectype = 'api'):
|
||||
"""Return public registry URL which ref pages should link to for the
|
||||
current all-extensions HTML specification, so xrefs in the
|
||||
asciidoc source that aren't to ref pages can link into it
|
||||
instead. N.b. this may need to change on a per-refpage basis if
|
||||
there are multiple documents involved.
|
||||
"""
|
||||
return 'https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html'
|
||||
|
||||
@property
|
||||
def xml_api_name(self):
|
||||
"""Return the name used in the default API XML registry for the default API"""
|
||||
return 'vulkan'
|
||||
|
||||
@property
|
||||
def registry_path(self):
|
||||
"""Return relpath to the default API XML registry in this project."""
|
||||
return 'xml/vk.xml'
|
||||
|
||||
@property
|
||||
def specification_path(self):
|
||||
"""Return relpath to the Asciidoctor specification sources in this project."""
|
||||
return '../appendices/meta'
|
||||
|
||||
@property
|
||||
def extra_refpage_headers(self):
|
||||
"""Return any extra text to add to refpage headers."""
|
||||
return 'include::../config/attribs.txt[]'
|
||||
|
||||
@property
|
||||
def extension_index_prefixes(self):
|
||||
"""Return a list of extension prefixes used to group extension refpages."""
|
||||
return ['VK_KHR', 'VK_EXT', 'VK']
|
||||
|
||||
@property
|
||||
def unified_flag_refpages(self):
|
||||
"""Returns True if Flags/FlagBits refpages are unified, False if
|
||||
they're separate.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def spec_reflow_path(self):
|
||||
"""Return the relative path to the spec source folder to reflow"""
|
||||
return '.'
|
||||
|
||||
@property
|
||||
def spec_no_reflow_dirs(self):
|
||||
"""Return a set of directories not to automatically descend into
|
||||
when reflowing spec text
|
||||
"""
|
||||
return ('scripts', 'style')
|
||||
|
Loading…
Reference in New Issue