# 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)))