# 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 \ VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator from .wrapperdefs import VulkanWrapperGenerator from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_API_NAME class DeepcopyCodegen(VulkanTypeIterator): def __init__(self, cgen, inputVars, poolVarName, rootVarName, prefix, skipValues=False): self.cgen = cgen self.inputVars = inputVars self.prefix = prefix self.poolVarName = poolVarName self.rootVarName = rootVarName self.skipValues = skipValues 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.exprAccessorLhs = makeAccess(self.inputVars[0]) self.exprAccessorRhs = makeAccess(self.inputVars[1]) self.exprAccessorValueLhs = makeAccess(self.inputVars[0], asPtr = False) self.exprAccessorValueRhs = makeAccess(self.inputVars[1], asPtr = False) self.lenAccessorLhs = makeLengthAccess(self.inputVars[0]) self.lenAccessorRhs = makeLengthAccess(self.inputVars[1]) self.lenAccessorGuardLhs = makeLengthAccessGuard(self.inputVars[0]) self.lenAccessorGuardRhs = makeLengthAccessGuard(self.inputVars[1]) self.checked = False def needSkip(self, vulkanType): return False def makeCastExpr(self, vulkanType): return "(%s)" % ( self.cgen.makeCTypeDecl(vulkanType, useParamName=False)) def makeNonConstCastForCopy(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 makeAllocBytesExpr(self, lenAccess, vulkanType): sizeof = self.cgen.sizeofExpr( \ vulkanType.getForValueAccess()) if lenAccess: bytesExpr = "%s * %s" % (lenAccess, sizeof) else: bytesExpr = sizeof return bytesExpr def onCheck(self, vulkanType): pass def endCheck(self, vulkanType): pass def onCompoundType(self, vulkanType): if self.needSkip(vulkanType): self.cgen.line("// TODO: Unsupported : %s" % self.cgen.makeCTypeDecl(vulkanType)) return accessLhs = self.exprAccessorLhs(vulkanType) accessRhs = self.exprAccessorRhs(vulkanType) lenAccessLhs = self.lenAccessorLhs(vulkanType) lenAccessRhs = self.lenAccessorRhs(vulkanType) lenAccessorGuardLhs = self.lenAccessorGuardLhs(vulkanType) lenAccessorGuardRhs = self.lenAccessorGuardRhs(vulkanType) isPtr = vulkanType.pointerIndirectionLevels > 0 if lenAccessorGuardLhs is not None: self.cgen.beginIf(lenAccessorGuardLhs) if isPtr: self.cgen.stmt("%s = nullptr" % accessRhs) self.cgen.beginIf(accessLhs) self.cgen.stmt( \ "%s = %s%s->alloc(%s)" % \ (accessRhs, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.poolVarName, self.makeAllocBytesExpr(lenAccessLhs, vulkanType))) if lenAccessLhs is not None: loopVar = "i" accessLhs = "%s + %s" % (accessLhs, loopVar) forInit = "uint32_t %s = 0" % loopVar forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs) forIncr = "++%s" % loopVar if isPtr: # Avoid generating a self-assign. if lenAccessRhs != lenAccessLhs: self.cgen.stmt("%s = %s" % (lenAccessRhs, lenAccessLhs)) accessRhs = "%s + %s" % (accessRhs, loopVar) self.cgen.beginFor(forInit, forCond, forIncr) accessRhsCasted = self.makeNonConstCastForCopy(accessRhs, vulkanType) self.cgen.funcCall(None, self.prefix + vulkanType.typeName, [self.poolVarName, self.rootVarName, accessLhs, accessRhsCasted]) if lenAccessLhs is not None: self.cgen.endFor() if isPtr: self.cgen.endIf() if lenAccessorGuardLhs is not None: self.cgen.endIf() def onString(self, vulkanType): accessLhs = self.exprAccessorLhs(vulkanType) accessRhs = self.exprAccessorRhs(vulkanType) self.cgen.stmt("%s = nullptr" % accessRhs) self.cgen.beginIf(accessLhs) self.cgen.stmt( \ "%s = %s->strDup(%s)" % \ (accessRhs, self.poolVarName, accessLhs)) self.cgen.endIf() def onStringArray(self, vulkanType): accessLhs = self.exprAccessorLhs(vulkanType) accessRhs = self.exprAccessorRhs(vulkanType) lenAccessLhs = self.lenAccessorLhs(vulkanType) self.cgen.stmt("%s = nullptr" % accessRhs) self.cgen.beginIf("%s && %s" % (accessLhs, lenAccessLhs)) self.cgen.stmt( \ "%s = %s->strDupArray(%s, %s)" % \ (accessRhs, self.poolVarName, accessLhs, lenAccessLhs)) self.cgen.endIf() def onStaticArr(self, vulkanType): accessLhs = self.exprAccessorValueLhs(vulkanType) accessRhs = self.exprAccessorValueRhs(vulkanType) lenAccessLhs = self.lenAccessorLhs(vulkanType) bytesExpr = self.makeAllocBytesExpr(lenAccessLhs, vulkanType) self.cgen.stmt("memcpy(%s, %s, %s)" % (accessRhs, accessLhs, bytesExpr)) def onStructExtension(self, vulkanType): lhs = self.exprAccessorLhs(vulkanType) rhs = self.exprAccessorRhs(vulkanType) rhsExpr = "(%s)(%s)" % ("void*", rhs) nextVar = "from_%s" % vulkanType.paramName sizeVar = "%s_size" % vulkanType.paramName self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" % self.rootVarName) self.cgen.stmt("%s = from->sType" % self.rootVarName) self.cgen.endIf() self.cgen.stmt("const void* %s = %s" % (nextVar, self.inputVars[0])) self.cgen.stmt("size_t %s = 0u" % sizeVar) self.cgen.beginWhile("!%s && %s" % (sizeVar, nextVar)) self.cgen.stmt("%s = static_cast(%s)->%s" % ( nextVar, nextVar, vulkanType.paramName )) self.cgen.stmt("%s = %s(%s, %s)" % ( sizeVar, EXTENSION_SIZE_API_NAME, self.rootVarName, nextVar)) self.cgen.endWhile() self.cgen.stmt("%s = nullptr" % rhs) self.cgen.beginIf(sizeVar) self.cgen.stmt( \ "%s = %s%s->alloc(%s)" % \ (rhs, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.poolVarName, sizeVar)) self.cgen.funcCall(None, self.prefix + "extension_struct", [self.poolVarName, self.rootVarName, nextVar, rhsExpr]) self.cgen.endIf() def onPointer(self, vulkanType): accessLhs = self.exprAccessorLhs(vulkanType) accessRhs = self.exprAccessorRhs(vulkanType) if self.needSkip(vulkanType): self.cgen.stmt("%s = nullptr" % accessRhs) return lenAccessLhs = self.lenAccessorLhs(vulkanType) self.cgen.stmt("%s = nullptr" % accessRhs) self.cgen.beginIf(accessLhs) bytesExpr = self.makeAllocBytesExpr(lenAccessLhs, vulkanType) self.cgen.stmt( \ "%s = %s%s->dupArray(%s, %s)" % \ (accessRhs, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.poolVarName, accessLhs, bytesExpr)) self.cgen.endIf() def onValue(self, vulkanType): if self.skipValues: return accessLhs = self.exprAccessorValueLhs(vulkanType) accessRhs = self.exprAccessorValueRhs(vulkanType) self.cgen.stmt("%s = %s" % (accessRhs, accessLhs)) class VulkanDeepcopy(VulkanWrapperGenerator): def __init__(self, module, typeInfo): VulkanWrapperGenerator.__init__(self, module, typeInfo) self.codegen = CodeGen() self.deepcopyPrefix = "deepcopy_" self.deepcopyVars = ["from", "to"] self.deepcopyAllocatorVarName = "alloc" self.deepcopyAllocatorParam = \ makeVulkanTypeSimple(False, "Allocator", 1, self.deepcopyAllocatorVarName) self.deepcopyRootVarName = "rootType" self.deepcopyRootParam = \ makeVulkanTypeSimple(False, "VkStructureType", 0, self.deepcopyRootVarName) self.voidType = makeVulkanTypeSimple(False, "void", 0) self.deepcopyCodegen = \ DeepcopyCodegen( None, self.deepcopyVars, self.deepcopyAllocatorVarName, self.deepcopyRootVarName, self.deepcopyPrefix, skipValues=True) self.knownDefs = {} self.extensionDeepcopyPrototype = \ VulkanAPI(self.deepcopyPrefix + "extension_struct", self.voidType, [self.deepcopyAllocatorParam, self.deepcopyRootParam, STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE]) def onBegin(self,): VulkanWrapperGenerator.onBegin(self) self.module.appendImpl(self.codegen.makeFuncDecl( self.extensionDeepcopyPrototype)) def onGenType(self, typeXml, name, alias): VulkanWrapperGenerator.onGenType(self, typeXml, name, alias) if name in self.knownDefs: return category = self.typeInfo.categoryOf(name) if category in ["struct", "union"] and alias: self.module.appendHeader( self.codegen.makeFuncAlias(self.deepcopyPrefix + name, self.deepcopyPrefix + alias)) if category in ["struct", "union"] and not alias: structInfo = self.typeInfo.structs[name] typeFromName = \ lambda varname: \ makeVulkanTypeSimple(varname == "from", name, 1, varname) deepcopyParams = \ [self.deepcopyAllocatorParam, self.deepcopyRootParam] + \ list(map(typeFromName, self.deepcopyVars)) deepcopyPrototype = \ VulkanAPI(self.deepcopyPrefix + name, self.voidType, deepcopyParams) def structDeepcopyDef(cgen): self.deepcopyCodegen.cgen = cgen canSimplyAssign = True for member in structInfo.members: if not member.isSimpleValueType(self.typeInfo): canSimplyAssign = False cgen.stmt("(void)%s" % self.deepcopyAllocatorVarName) cgen.stmt("(void)%s" % self.deepcopyRootVarName) cgen.stmt("*to = *from") if canSimplyAssign: pass else: for member in structInfo.members: iterateVulkanType(self.typeInfo, member, self.deepcopyCodegen) self.module.appendHeader( self.codegen.makeFuncDecl(deepcopyPrototype)) self.module.appendImpl( self.codegen.makeFuncImpl(deepcopyPrototype, structDeepcopyDef)) def onGenCmd(self, cmdinfo, name, alias): VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias) def onEnd(self,): VulkanWrapperGenerator.onEnd(self) def deepcopyDstExpr(cgen, typeName): return cgen.makeReinterpretCast( \ STRUCT_EXTENSION_PARAM_FOR_WRITE.paramName, typeName, const=False) def forEachExtensionDeepcopy(ext, castedAccess, cgen): cgen.funcCall(None, self.deepcopyPrefix + ext.name, [self.deepcopyAllocatorVarName, self.deepcopyRootVarName, castedAccess, deepcopyDstExpr(cgen, ext.name)]) self.module.appendImpl( self.codegen.makeFuncImpl( self.extensionDeepcopyPrototype, lambda cgen: self.emitForEachStructExtension( cgen, self.voidType, STRUCT_EXTENSION_PARAM, forEachExtensionDeepcopy, rootTypeVar=self.deepcopyRootParam)))