blob: 79aff0e3a8c85dac42b295eed2d9dd59e4fa2dcb [file] [log] [blame]
# Copyright (c) 2018 The Android Open Source Project
# Copyright (c) 2018 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.
from .common.codegen import CodeGen
from .common.vulkantypes import \
VulkanCompoundType, VulkanAPI, makeVulkanTypeSimple, vulkanTypeNeedsTransform, vulkanTypeGetNeededTransformTypes, VulkanTypeIterator, iterateVulkanType, vulkanTypeforEachSubType, TRIVIAL_TRANSFORMED_TYPES, NON_TRIVIAL_TRANSFORMED_TYPES, TRANSFORMED_TYPES
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
def deviceMemoryTransform(resourceTrackerVarName, structOrApiInfo, getExpr, getLen, cgen, variant="tohost"):
paramIndices = \
structOrApiInfo.deviceMemoryInfoParameterIndices
for _, info in paramIndices.items():
orderedKeys = [
"handle",
"offset",
"size",
"typeIndex",
"typeBits",]
casts = {
"handle" : "VkDeviceMemory*",
"offset" : "VkDeviceSize*",
"size" : "VkDeviceSize*",
"typeIndex" : "uint32_t*",
"typeBits" : "uint32_t*",
}
accesses = {
"handle" : "nullptr",
"offset" : "nullptr",
"size" : "nullptr",
"typeIndex" : "nullptr",
"typeBits" : "nullptr",
}
lenAccesses = {
"handle" : "0",
"offset" : "0",
"size" : "0",
"typeIndex" : "0",
"typeBits" : "0",
}
def doParam(i, vulkanType):
access = getExpr(vulkanType)
lenAccess = getLen(vulkanType)
for k in orderedKeys:
if i == info.__dict__[k]:
accesses[k] = access
if lenAccess is not None:
lenAccesses[k] = lenAccess
else:
lenAccesses[k] = "1"
vulkanTypeforEachSubType(structOrApiInfo, doParam)
callParams = ", ".join( \
["(%s)%s, %s" % (casts[k], accesses[k], lenAccesses[k]) \
for k in orderedKeys])
if variant == "tohost":
cgen.stmt("%s->deviceMemoryTransform_tohost(%s)" % \
(resourceTrackerVarName, callParams))
else:
cgen.stmt("%s->deviceMemoryTransform_fromhost(%s)" % \
(resourceTrackerVarName, callParams))
def directTransform(resourceTrackerVarName, vulkanType, getExpr, getLen, cgen, variant="tohost"):
access = getExpr(vulkanType)
lenAccess = getLen(vulkanType)
if lenAccess:
finalLenAccess = lenAccess
else:
finalLenAccess = "1"
cgen.stmt("%s->transformImpl_%s_%s(%s, %s)" % (resourceTrackerVarName,
vulkanType.typeName, variant, access, finalLenAccess))
def genTransformsForVulkanType(resourceTrackerVarName, structOrApiInfo, getExpr, getLen, cgen, variant="tohost"):
for transform in vulkanTypeGetNeededTransformTypes(structOrApiInfo):
if transform == "devicememory":
deviceMemoryTransform( \
resourceTrackerVarName,
structOrApiInfo,
getExpr, getLen, cgen, variant=variant)
class TransformCodegen(VulkanTypeIterator):
def __init__(self, cgen, inputVar, resourceTrackerVarName, prefix, variant):
self.cgen = cgen
self.inputVar = inputVar
self.prefix = prefix
self.resourceTrackerVarName = resourceTrackerVarName
def makeAccess(varName, asPtr = True):
return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
def makeLengthAccess(varName):
return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
def makeLengthAccessGuard(varName):
return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
self.exprAccessor = makeAccess(self.inputVar)
self.exprAccessorValue = makeAccess(self.inputVar, asPtr = False)
self.lenAccessor = makeLengthAccess(self.inputVar)
self.lenAccessorGuard = makeLengthAccessGuard(self.inputVar)
self.checked = False
self.variant = variant
def makeCastExpr(self, vulkanType):
return "(%s)" % (
self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
def asNonConstCast(self, access, vulkanType):
if vulkanType.staticArrExpr:
casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
elif vulkanType.accessibleAsPointer():
casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForNonConstAccess()), access)
else:
casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
return casted
def onCheck(self, vulkanType):
pass
def endCheck(self, vulkanType):
pass
def onCompoundType(self, vulkanType):
access = self.exprAccessor(vulkanType)
lenAccess = self.lenAccessor(vulkanType)
lenAccessGuard = self.lenAccessorGuard(vulkanType)
isPtr = vulkanType.pointerIndirectionLevels > 0
if lenAccessGuard is not None:
self.cgen.beginIf(lenAccessGuard)
if isPtr:
self.cgen.beginIf(access)
if lenAccess is not None:
loopVar = "i"
access = "%s + %s" % (access, loopVar)
forInit = "uint32_t %s = 0" % loopVar
forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
forIncr = "++%s" % loopVar
self.cgen.beginFor(forInit, forCond, forIncr)
accessCasted = self.asNonConstCast(access, vulkanType)
if vulkanType.isTransformed:
directTransform(self.resourceTrackerVarName, vulkanType, self.exprAccessor, self.lenAccessor, self.cgen, variant=self.variant)
self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
[self.resourceTrackerVarName, accessCasted])
if lenAccess is not None:
self.cgen.endFor()
if isPtr:
self.cgen.endIf()
if lenAccessGuard is not None:
self.cgen.endIf()
def onString(self, vulkanType):
pass
def onStringArray(self, vulkanType):
pass
def onStaticArr(self, vulkanType):
pass
def onStructExtension(self, vulkanType):
access = self.exprAccessor(vulkanType)
castedAccessExpr = "(%s)(%s)" % ("void*", access)
self.cgen.beginIf(access)
self.cgen.funcCall(None, self.prefix + "extension_struct",
[self.resourceTrackerVarName, castedAccessExpr])
self.cgen.endIf()
def onPointer(self, vulkanType):
pass
def onValue(self, vulkanType):
pass
class VulkanTransform(VulkanWrapperGenerator):
def __init__(self, module, typeInfo, resourceTrackerTypeName="ResourceTracker", resourceTrackerVarName="resourceTracker"):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.transformPrefix = "transform_"
self.tohostpart = "tohost"
self.fromhostpart = "fromhost"
self.variants = [self.tohostpart, self.fromhostpart]
self.toTransformVar = "toTransform"
self.resourceTrackerTypeName = resourceTrackerTypeName
self.resourceTrackerVarName = resourceTrackerVarName
self.transformParam = \
makeVulkanTypeSimple(False, self.resourceTrackerTypeName, 1,
self.resourceTrackerVarName)
self.voidType = makeVulkanTypeSimple(False, "void", 0)
self.extensionTransformPrototypes = []
for variant in self.variants:
self.extensionTransformPrototypes.append( \
VulkanAPI(self.transformPrefix + variant + "_extension_struct",
self.voidType,
[self.transformParam, STRUCT_EXTENSION_PARAM_FOR_WRITE]))
self.knownStructs = {}
self.needsTransform = set([])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
# Set up a convenience macro fro the transformed structs
# and forward-declare the resource tracker class
self.codegen.stmt("class %s" % self.resourceTrackerTypeName)
self.codegen.line("#define LIST_TRIVIAL_TRANSFORMED_TYPES(f) \\")
for name in TRIVIAL_TRANSFORMED_TYPES:
self.codegen.line("f(%s) \\" % name)
self.codegen.line("")
self.codegen.line("#define LIST_NON_TRIVIAL_TRANSFORMED_TYPES(f) \\")
for name in NON_TRIVIAL_TRANSFORMED_TYPES:
self.codegen.line("f(%s) \\" % name)
self.codegen.line("")
self.codegen.line("#define LIST_TRANSFORMED_TYPES(f) \\")
self.codegen.line("LIST_TRIVIAL_TRANSFORMED_TYPES(f) \\")
self.codegen.line("LIST_NON_TRIVIAL_TRANSFORMED_TYPES(f) \\")
self.codegen.line("")
self.module.appendHeader(self.codegen.swapCode())
for prototype in self.extensionTransformPrototypes:
self.module.appendImpl(self.codegen.makeFuncDecl(
prototype))
def onGenType(self, typeXml, name, alias):
VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
if name in self.knownStructs:
return
category = self.typeInfo.categoryOf(name)
if category in ["struct", "union"] and alias:
for variant in self.variants:
self.module.appendHeader(
self.codegen.makeFuncAlias(self.transformPrefix + variant + "_" + name,
self.transformPrefix + variant + "_" + alias))
if category in ["struct", "union"] and not alias:
structInfo = self.typeInfo.structs[name]
self.knownStructs[name] = structInfo
for variant in self.variants:
api = VulkanAPI( \
self.transformPrefix + variant + "_" + name,
self.voidType,
[self.transformParam] + \
[makeVulkanTypeSimple( \
False, name, 1, self.toTransformVar)])
transformer = TransformCodegen(
None,
self.toTransformVar,
self.resourceTrackerVarName,
self.transformPrefix + variant + "_",
variant)
def funcDefGenerator(cgen):
transformer.cgen = cgen
for p in api.parameters:
cgen.stmt("(void)%s" % p.paramName)
genTransformsForVulkanType(
self.resourceTrackerVarName,
structInfo,
transformer.exprAccessor,
transformer.lenAccessor,
cgen,
variant=variant)
for member in structInfo.members:
iterateVulkanType(
self.typeInfo, member,
transformer)
self.module.appendHeader(
self.codegen.makeFuncDecl(api))
self.module.appendImpl(
self.codegen.makeFuncImpl(api, funcDefGenerator))
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
def onEnd(self,):
VulkanWrapperGenerator.onEnd(self)
for (variant, prototype) in zip(self.variants, self.extensionTransformPrototypes):
def forEachExtensionTransform(ext, castedAccess, cgen):
if ext.isTransformed:
directTransform(self.resourceTrackerVarName, ext, lambda _ : castedAccess, lambda _ : "1", cgen, variant);
cgen.funcCall(None, self.transformPrefix + variant + "_" + ext.name,
[self.resourceTrackerVarName, castedAccess])
self.module.appendImpl(
self.codegen.makeFuncImpl(
prototype,
lambda cgen: self.emitForEachStructExtension(
cgen,
self.voidType,
STRUCT_EXTENSION_PARAM_FOR_WRITE,
forEachExtensionTransform)))