blob: fc6383ddf7a00e53b8380a313443fdd5396af0da [file] [log] [blame]
# -*- coding: utf-8 -*-
import os
import re
import sys
from khr_util.format import indentLines, writeInlFile
DEQP_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
VULKAN_DIR = os.path.join(DEQP_DIR, "framework", "vulkan")
INL_HEADER = """\
/* WARNING: This is auto-generated file. Do not modify, since changes will
* be lost! Modify the generating script instead.
*/\
"""
PLATFORM_FUNCTIONS = [
"vkCreateInstance",
"vkDestroyInstance",
"vkEnumeratePhysicalDevices",
]
GET_PROC_ADDR = "vkGetProcAddr"
OBJECT_TYPE_REPL = {
"VkObject": None,
"VkNonDispatchable": None,
"VkDynamicStateObject": None,
"VkCmdBuffer": "VK_OBJECT_TYPE_COMMAND_BUFFER",
}
DEFINITIONS = [
"VK_API_VERSION",
"VK_MAX_PHYSICAL_DEVICE_NAME",
"VK_MAX_EXTENSION_NAME"
]
class Handle:
TYPE_ROOT = 0
TYPE_DISP = 1
TYPE_NONDISP = 2
def __init__ (self, type, name, parent = None):
assert (type == Handle.TYPE_ROOT) == (parent == None)
self.type = type
self.name = name
self.parent = parent
def getObjectType (self):
if self.name in OBJECT_TYPE_REPL:
return OBJECT_TYPE_REPL[self.name]
else:
name = re.sub(r'([A-Z])', r'_\1', self.name)
return "VK_OBJECT_TYPE_" + name[4:].upper()
class Enum:
def __init__ (self, name, values):
self.name = name
self.values = values
class Bitfield:
def __init__ (self, name, values):
self.name = name
self.values = values
class Variable:
def __init__ (self, type, name):
self.type = type
self.name = name
class Struct:
def __init__ (self, name, members):
self.name = name
self.members = members
class Function:
TYPE_GET_PROC_ADDR = 0 # Special
TYPE_PLATFORM = 1 # Not bound to VkPhysicalDevice
TYPE_DEVICE = 2 # Bound to VkPhysicalDevice
def __init__ (self, name, returnType, arguments):
self.name = name
self.returnType = returnType
self.arguments = arguments
def getType (self):
if self.name == GET_PROC_ADDR:
return Function.TYPE_GET_PROC_ADDR
elif self.name in PLATFORM_FUNCTIONS:
return Function.TYPE_PLATFORM
else:
return Function.TYPE_DEVICE
class API:
def __init__ (self, definitions, handles, enums, bitfields, structs, functions):
self.definitions = definitions
self.handles = handles
self.enums = enums
self.bitfields = bitfields
self.structs = structs
self.functions = functions
def readFile (filename):
with open(filename, 'rb') as f:
return f.read()
IDENT_PTRN = r'[a-zA-Z_][a-zA-Z0-9_]*'
TYPE_PTRN = r'[a-zA-Z_][a-zA-Z0-9_ \t*]*'
def endswith (s, postfix):
return len(s) >= len(postfix) and s[len(s)-len(postfix):] == postfix
def fixupEnumValues (values):
fixed = []
for name, value in values:
if endswith(name, "_BEGIN_RANGE") or endswith(name, "_END_RANGE"):
continue
fixed.append((name, value))
return fixed
def fixupType (type):
replacements = [
("uint8_t", "deUint8"),
("uint16_t", "deUint16"),
("uint32_t", "deUint32"),
("uint64_t", "deUint64"),
("int8_t", "deInt8"),
("int16_t", "deInt16"),
("int32_t", "deInt32"),
("int64_t", "deInt64"),
("bool32_t", "deUint32"),
("size_t", "deUintptr"),
]
for src, dst in replacements:
type = type.replace(src, dst)
return type
def fixupFunction (function):
fixedArgs = [Variable(fixupType(a.type), a.name) for a in function.arguments]
fixedReturnType = fixupType(function.returnType)
if function.name == "vkGetProcAddr":
fixedReturnType = "FunctionPtr"
return Function(function.name, fixedReturnType, fixedArgs)
def getInterfaceName (function):
assert function.name[:2] == "vk"
return function.name[2].lower() + function.name[3:]
def getFunctionTypeName (function):
assert function.name[:2] == "vk"
return function.name[2:] + "Func"
def getBitEnumNameForBitfield (bitfieldName):
assert bitfieldName[-1] == "s"
return bitfieldName[:-1] + "Bits"
def getBitfieldNameForBitEnum (bitEnumName):
assert bitEnumName[-4:] == "Bits"
return bitEnumName[:-4] + "s"
def parsePreprocDefinedValue (src, name):
return re.search(r'#\s*define\s+' + name + r'\s+([^\n]+)\n', src).group(1).strip()
def parseEnum (name, src):
keyValuePtrn = '(' + IDENT_PTRN + r')\s*=\s*([^\s,}]+)\s*[,}]'
matches = re.findall(keyValuePtrn, src)
return Enum(name, fixupEnumValues(matches))
# \note Parses raw enums, some are mapped to bitfields later
def parseEnums (src):
matches = re.findall(r'typedef enum ' + IDENT_PTRN + r'\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
enums = []
for contents, name in matches:
enums.append(parseEnum(name, contents))
return enums
def parseStruct (name, src):
# \todo [pyry] Array support is currently a hack (size coupled with name)
typeNamePtrn = r'(' + TYPE_PTRN + ')(\s' + IDENT_PTRN + r'(\[[^\]]+\])*)\s*;'
matches = re.findall(typeNamePtrn, src)
members = [Variable(fixupType(t.strip()), n.strip()) for t, n, a in matches]
return Struct(name, members)
def parseStructs (src):
matches = re.findall(r'typedef struct ' + IDENT_PTRN + r'\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
structs = []
for contents, name in matches:
structs.append(parseStruct(name, contents))
return structs
def parseHandles (src):
matches = re.findall(r'VK_DEFINE_(NONDISP|DISP)_SUBCLASS_HANDLE\((' + IDENT_PTRN + r'),\s*(' + IDENT_PTRN + r')\)[ \t]*[\n\r]', src)
handles = []
typeMap = {'DISP': Handle.TYPE_DISP, 'NONDISP': Handle.TYPE_NONDISP}
byName = {}
root = Handle(Handle.TYPE_ROOT, 'VkObject')
byName[root.name] = root
handles.append(root)
for type, name, parentName in matches:
parent = byName[parentName]
handle = Handle(typeMap[type], name, parent)
byName[handle.name] = handle
handles.append(handle)
return handles
def parseArgList (src):
typeNamePtrn = r'(' + TYPE_PTRN + ')(\s' + IDENT_PTRN + r')'
args = []
for rawArg in src.split(','):
m = re.search(typeNamePtrn, rawArg)
args.append(Variable(m.group(1).strip(), m.group(2).strip()))
return args
def parseFunctions (src):
ptrn = r'(' + TYPE_PTRN + ')VKAPI\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
matches = re.findall(ptrn, src)
functions = []
for returnType, name, argList in matches:
functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList)))
return [fixupFunction(f) for f in functions]
def parseBitfieldNames (src):
ptrn = r'typedef\s+VkFlags\s(' + IDENT_PTRN + r')\s*;'
matches = re.findall(ptrn, src)
return matches
def parseAPI (src):
definitions = [(name, parsePreprocDefinedValue(src, name)) for name in DEFINITIONS]
rawEnums = parseEnums(src)
bitfieldNames = parseBitfieldNames(src)
enums = []
bitfields = []
bitfieldEnums = set([getBitEnumNameForBitfield(n) for n in bitfieldNames])
for enum in rawEnums:
if enum.name in bitfieldEnums:
bitfields.append(Bitfield(getBitfieldNameForBitEnum(enum.name), enum.values))
else:
enums.append(enum)
return API(
definitions = definitions,
handles = parseHandles(src),
enums = enums,
bitfields = bitfields,
structs = parseStructs(src),
functions = parseFunctions(src))
def genEnumSrc (enum):
yield "enum %s" % enum.name
yield "{"
for line in indentLines(["\t%s\t= %s," % v for v in enum.values]):
yield line
yield "};"
def genBitfieldSrc (bitfield):
yield "enum %s" % getBitEnumNameForBitfield(bitfield.name)
yield "{"
for line in indentLines(["\t%s\t= %s," % v for v in bitfield.values]):
yield line
yield "};"
yield "typedef deUint32 %s;" % bitfield.name
def genStructSrc (struct):
yield "struct %s" % struct.name
yield "{"
for line in indentLines(["\t%s\t%s;" % (m.type, m.name) for m in struct.members]):
yield line
yield "};"
def genHandlesSrc (handles):
def genLines (handles):
for handle in handles:
if handle.type == Handle.TYPE_ROOT:
yield "VK_DEFINE_BASE_HANDLE\t(%s);" % handle.name
elif handle.type == Handle.TYPE_DISP:
yield "VK_DEFINE_DISP_SUBCLASS_HANDLE\t(%s,\t%s);" % (handle.name, handle.parent.name)
elif handle.type == Handle.TYPE_NONDISP:
yield "VK_DEFINE_NONDISP_SUBCLASS_HANDLE\t(%s,\t%s);" % (handle.name, handle.parent.name)
for line in indentLines(genLines(handles)):
yield line
def writeBasicTypes (api, filename):
def gen ():
for line in indentLines(["#define %s\t%s" % define for define in api.definitions]):
yield line
yield ""
for line in genHandlesSrc(api.handles):
yield line
yield ""
for enum in api.enums:
for line in genEnumSrc(enum):
yield line
yield ""
for bitfield in api.bitfields:
for line in genBitfieldSrc(bitfield):
yield line
yield ""
for line in indentLines(["VK_DEFINE_HANDLE_TYPE_TRAITS(%s);" % handle.name for handle in api.handles]):
yield line
writeInlFile(filename, INL_HEADER, gen())
def writeGetObjectTypeImpl (api, filename):
def gen ():
for line in indentLines(["template<> VkObjectType\tgetObjectType<%sT>\t(void) { return %s;\t}" % (handle.name, handle.getObjectType()) for handle in api.handles if handle.getObjectType() != None]):
yield line
writeInlFile(filename, INL_HEADER, gen())
def writeStructTypes (api, filename):
def gen ():
for struct in api.structs:
for line in genStructSrc(struct):
yield line
yield ""
writeInlFile(filename, INL_HEADER, gen())
def argListToStr (args):
return ", ".join("%s %s" % (v.type, v.name) for v in args)
def writeInterfaceDecl (api, filename, functionTypes, concrete):
def genProtos ():
postfix = "" if concrete else " = 0"
for function in api.functions:
if function.getType() in functionTypes:
yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments), postfix)
writeInlFile(filename, INL_HEADER, indentLines(genProtos()))
def writeFunctionPtrTypes (api, filename):
def genTypes ():
for function in api.functions:
yield "typedef VK_APICALL %s\t(VK_APIENTRY* %s)\t(%s);" % (function.returnType, getFunctionTypeName(function), argListToStr(function.arguments))
writeInlFile(filename, INL_HEADER, indentLines(genTypes()))
def writeFunctionPointers (api, filename, functionTypes):
writeInlFile(filename, INL_HEADER, indentLines(["%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function)) for function in api.functions if function.getType() in functionTypes]))
def writeInitFunctionPointers (api, filename, functionTypes):
def makeInitFunctionPointers ():
for function in api.functions:
if function.getType() in functionTypes:
yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
writeInlFile(filename, INL_HEADER, indentLines(makeInitFunctionPointers()))
def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className):
def makeFuncPtrInterfaceImpl ():
for function in api.functions:
if function.getType() in functionTypes:
yield ""
yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments))
yield "{"
yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
yield "}"
writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl())
def writeStrUtilProto (api, filename):
def makeStrUtilProto ():
for line in indentLines(["const char*\tget%sName\t(%s value);" % (enum.name[2:], enum.name) for enum in api.enums]):
yield line
yield ""
for line in indentLines(["inline tcu::Format::Enum<%s>\tget%sStr\t(%s value)\t{ return tcu::Format::Enum<%s>(get%sName, value);\t}" % (e.name, e.name[2:], e.name, e.name, e.name[2:]) for e in api.enums]):
yield line
yield ""
for line in indentLines(["inline std::ostream&\toperator<<\t(std::ostream& s, %s value)\t{ return s << get%sStr(value);\t}" % (e.name, e.name[2:]) for e in api.enums]):
yield line
yield ""
for line in indentLines(["tcu::Format::Bitfield<32>\tget%sStr\t(%s value);" % (bitfield.name[2:], bitfield.name) for bitfield in api.bitfields]):
yield line
yield ""
for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.structs]):
yield line
writeInlFile(filename, INL_HEADER, makeStrUtilProto())
def writeStrUtilImpl (api, filename):
def makeStrUtilImpl ():
for line in indentLines(["template<> const char*\tgetTypeName<%sT>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles]):
yield line
for enum in api.enums:
yield ""
yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name)
yield "{"
yield "\tswitch (value)"
yield "\t{"
for line in indentLines(["\t\tcase %s:\treturn \"%s\";" % (n, n) for n, v in enum.values] + ["\t\tdefault:\treturn DE_NULL;"]):
yield line
yield "\t}"
yield "}"
for bitfield in api.bitfields:
yield ""
yield "tcu::Format::Bitfield<32> get%sStr (%s value)" % (bitfield.name[2:], bitfield.name)
yield "{"
yield "\tstatic const tcu::Format::BitDesc s_desc[] ="
yield "\t{"
for line in indentLines(["\t\ttcu::Format::BitDesc(%s,\t\"%s\")," % (n, n) for n, v in bitfield.values]):
yield line
yield "\t};"
yield "\treturn tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));"
yield "}"
bitfieldTypeNames = set([bitfield.name for bitfield in api.bitfields])
for struct in api.structs:
yield ""
yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % struct.name
yield "{"
yield "\ts << \"%s = {\\n\";" % struct.name
for member in struct.members:
memberName = member.name
valFmt = None
if member.type in bitfieldTypeNames:
valFmt = "get%sStr(value.%s)" % (member.type[2:], member.name)
elif '[' in member.name:
baseName = member.name[:member.name.find('[')]
if baseName == "extName" or baseName == "deviceName":
valFmt = "(const char*)value.%s" % baseName
else:
valFmt = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), DE_ARRAY_END(value.%s))" % (baseName, baseName)
memberName = baseName
else:
valFmt = "value.%s" % member.name
yield ("\ts << \"%s = \" << " % memberName) + valFmt + " << '\\n';"
yield "\ts << '}';"
yield "\treturn s;"
yield "}"
writeInlFile(filename, INL_HEADER, makeStrUtilImpl())
class ConstructorFunction:
def __init__ (self, name, objectType, iface, arguments):
self.name = name
self.objectType = objectType
self.iface = iface
self.arguments = arguments
def getConstructorFunctions (api):
funcs = []
for function in api.functions:
if function.name[:8] == "vkCreate":
# \todo [pyry] Rather hacky
iface = None
if function.getType() == Function.TYPE_PLATFORM:
iface = Variable("const PlatformInterface&", "vk")
else:
iface = Variable("const DeviceInterface&", "vk")
objectType = function.arguments[-1].type.replace("*", "").strip()
arguments = function.arguments[:-1]
funcs.append(ConstructorFunction(getInterfaceName(function), objectType, iface, arguments))
return funcs
def writeRefUtilProto (api, filename):
functions = getConstructorFunctions(api)
def makeRefUtilProto ():
unindented = []
for line in indentLines(["Move<%sT>\t%s\t(%s);" % (function.objectType, function.name, argListToStr([function.iface] + function.arguments)) for function in functions]):
yield line
writeInlFile(filename, INL_HEADER, makeRefUtilProto())
def writeRefUtilImpl (api, filename):
functions = getConstructorFunctions(api)
def makeRefUtilImpl ():
for function in functions:
maybeDevice = ", device" if "device" in set([a.name for a in function.arguments]) else ""
yield "Move<%sT> %s (%s)" % (function.objectType, function.name, argListToStr([function.iface] + function.arguments))
yield "{"
yield "\t%s object = 0;" % function.objectType
yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"]))
yield "\treturn Move<%sT>(vk%s, check<%sT>(object));" % (function.objectType, maybeDevice, function.objectType)
yield "}"
yield ""
writeInlFile(filename, INL_HEADER, makeRefUtilImpl())
if __name__ == "__main__":
src = readFile(sys.argv[1])
api = parseAPI(src)
platformFuncs = set([Function.TYPE_GET_PROC_ADDR, Function.TYPE_PLATFORM])
deviceFuncs = set([Function.TYPE_DEVICE])
writeBasicTypes (api, os.path.join(VULKAN_DIR, "vkBasicTypes.inl"))
writeStructTypes (api, os.path.join(VULKAN_DIR, "vkStructTypes.inl"))
writeGetObjectTypeImpl (api, os.path.join(VULKAN_DIR, "vkGetObjectTypeImpl.inl"))
writeInterfaceDecl (api, os.path.join(VULKAN_DIR, "vkVirtualPlatformInterface.inl"), functionTypes = platformFuncs, concrete = False)
writeInterfaceDecl (api, os.path.join(VULKAN_DIR, "vkVirtualDeviceInterface.inl"), functionTypes = deviceFuncs, concrete = False)
writeInterfaceDecl (api, os.path.join(VULKAN_DIR, "vkConcretePlatformInterface.inl"), functionTypes = platformFuncs, concrete = True)
writeInterfaceDecl (api, os.path.join(VULKAN_DIR, "vkConcreteDeviceInterface.inl"), functionTypes = deviceFuncs, concrete = True)
writeFunctionPtrTypes (api, os.path.join(VULKAN_DIR, "vkFunctionPointerTypes.inl"))
writeFunctionPointers (api, os.path.join(VULKAN_DIR, "vkPlatformFunctionPointers.inl"), functionTypes = platformFuncs)
writeFunctionPointers (api, os.path.join(VULKAN_DIR, "vkDeviceFunctionPointers.inl"), functionTypes = deviceFuncs)
writeInitFunctionPointers (api, os.path.join(VULKAN_DIR, "vkInitPlatformFunctionPointers.inl"), functionTypes = set([Function.TYPE_PLATFORM])) # \note No vkGetProcAddr
writeInitFunctionPointers (api, os.path.join(VULKAN_DIR, "vkInitDeviceFunctionPointers.inl"), functionTypes = deviceFuncs)
writeFuncPtrInterfaceImpl (api, os.path.join(VULKAN_DIR, "vkPlatformDriverImpl.inl"), functionTypes = platformFuncs, className = "PlatformDriver")
writeFuncPtrInterfaceImpl (api, os.path.join(VULKAN_DIR, "vkDeviceDriverImpl.inl"), functionTypes = deviceFuncs, className = "DeviceDriver")
writeStrUtilProto (api, os.path.join(VULKAN_DIR, "vkStrUtil.inl"))
writeStrUtilImpl (api, os.path.join(VULKAN_DIR, "vkStrUtilImpl.inl"))
writeRefUtilProto (api, os.path.join(VULKAN_DIR, "vkRefUtil.inl"))
writeRefUtilImpl (api, os.path.join(VULKAN_DIR, "vkRefUtilImpl.inl"))