# 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 copy import copy from .common.codegen import CodeGen, VulkanAPIWrapper from .common.vulkantypes import \ VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda from .wrapperdefs import VulkanWrapperGenerator from .wrapperdefs import VULKAN_STREAM_VAR_NAME from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM from .wrapperdefs import STREAM_RET_TYPE from .wrapperdefs import MARSHAL_INPUT_VAR_NAME from .wrapperdefs import UNMARSHAL_INPUT_VAR_NAME from .wrapperdefs import PARAMETERS_MARSHALING from .wrapperdefs import PARAMETERS_MARSHALING_GUEST from .wrapperdefs import STYPE_OVERRIDE from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME from .wrapperdefs import API_PREFIX_RESERVEDMARSHAL from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL from .marshalingdefs import CUSTOM_MARSHAL_TYPES class VulkanReservedMarshalingCodegen(VulkanTypeIterator): def __init__(self, cgen, variant, streamVarName, rootTypeVarName, inputVarName, ptrVarName, marshalPrefix, handlemapPrefix, direction = "write", forApiOutput = False, dynAlloc = False, mapHandles = True, handleMapOverwrites = False, doFiltering = True, stackVar=None, stackArrSize=None): self.cgen = cgen self.variant = variant self.direction = direction self.processSimple = "write" if self.direction == "write" else "read" self.forApiOutput = forApiOutput self.checked = False self.streamVarName = streamVarName self.rootTypeVarName = rootTypeVarName self.inputVarName = inputVarName self.ptrVar = ptrVarName self.marshalPrefix = marshalPrefix self.handlemapPrefix = handlemapPrefix self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = True) self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False) self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False) self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.inputVarName) self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard( t, parentVarName=self.inputVarName) self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.inputVarName) self.dynAlloc = dynAlloc self.mapHandles = mapHandles self.handleMapOverwrites = handleMapOverwrites self.doFiltering = doFiltering self.stackVar = stackVar self.stackArrSize = stackArrSize def getTypeForStreaming(self, vulkanType): res = copy(vulkanType) if not vulkanType.accessibleAsPointer(): res = res.getForAddressAccess() if vulkanType.staticArrExpr: res = res.getForAddressAccess() if self.direction == "write": return res else: return res.getForNonConstAccess() def makeCastExpr(self, vulkanType): return "(%s)" % ( self.cgen.makeCTypeDecl(vulkanType, useParamName=False)) def genPtrIncr(self, sizeExpr): self.cgen.stmt("*%s += %s" % (self.ptrVar, sizeExpr)) def genMemcpyAndIncr(self, varname, cast, toStreamExpr, sizeExpr, toBe = False, actualSize = 4): if self.direction == "write": self.cgen.stmt("memcpy(*%s, %s%s, %s)" % (varname, cast, toStreamExpr, sizeExpr)) else: self.cgen.stmt("memcpy(%s%s, *%s, %s)" % (cast, toStreamExpr, varname, sizeExpr)) if toBe: streamPrefix = "to" if "read" == self.direction: streamPrefix = "from" streamMethod = streamPrefix if 1 == actualSize: streamMethod += "Byte" elif 2 == actualSize: streamMethod += "Be16" elif 4 == actualSize: streamMethod += "Be32" elif 8 == actualSize: streamMethod += "Be64" else: pass streamNamespace = "gfxstream::guest" if self.variant == "guest" else "android::base" if self.direction == "write": self.cgen.stmt("%s::Stream::%s((uint8_t*)*%s)" % (streamNamespace, streamMethod, varname)) else: self.cgen.stmt("%s::Stream::%s((uint8_t*)%s)" % (streamNamespace, streamMethod, toStreamExpr)) self.genPtrIncr(sizeExpr) def genStreamCall(self, vulkanType, toStreamExpr, sizeExpr): varname = self.ptrVar cast = self.makeCastExpr(self.getTypeForStreaming(vulkanType)) self.genMemcpyAndIncr(varname, cast, toStreamExpr, sizeExpr) def genPrimitiveStreamCall(self, vulkanType, access): varname = self.ptrVar self.cgen.memcpyPrimitive( self.typeInfo, "(*" + varname + ")", access, vulkanType, self.variant, direction=self.direction) self.genPtrIncr(str(self.cgen.countPrimitive( self.typeInfo, vulkanType))) def genHandleMappingCall(self, vulkanType, access, lenAccess, lenAccessGuard): if lenAccess is None: lenAccess = "1" handle64Bytes = "8" else: handle64Bytes = "%s * 8" % lenAccess handle64Var = self.cgen.var() if lenAccess != "1": self.cgen.beginIf(lenAccess) self.cgen.stmt("uint8_t* %s_ptr = (uint8_t*)(*%s)" % (handle64Var, self.ptrVar)) handle64VarAccess = handle64Var handle64VarType = \ makeVulkanTypeSimple(False, "uint64_t", 1, paramName=handle64Var) else: self.cgen.stmt("uint64_t %s" % handle64Var) handle64VarAccess = "&%s" % handle64Var handle64VarType = \ makeVulkanTypeSimple(False, "uint64_t", 0, paramName=handle64Var) if "" == self.handlemapPrefix: mapFunc = ("(%s)" % vulkanType.typeName) mapFunc64 = ("(%s)" % "uint64_t") else: mapFunc = self.handlemapPrefix + vulkanType.typeName mapFunc64 = mapFunc if self.direction == "write": if self.handleMapOverwrites: self.cgen.stmt( "static_assert(8 == sizeof(%s), \"handle map overwrite requres %s to be 8 bytes long\")" % \ (vulkanType.typeName, vulkanType.typeName)) if "1" == lenAccess: self.cgen.stmt("*%s = (%s)%s(*%s)" % (access, vulkanType.typeName, mapFunc, access)) self.genStreamCall(vulkanType, access, "8 * %s" % lenAccess) else: if lenAccessGuard is not None: self.cgen.beginIf(lenAccessGuard) self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k") self.cgen.stmt("%s[k] = (%s)%s(%s[k])" % (access, vulkanType.typeName, mapFunc, access)) self.cgen.endFor() if lenAccessGuard is not None: self.cgen.endIf() self.genPtrIncr("8 * %s" % lenAccess) else: if "1" == lenAccess: self.cgen.stmt("*%s = %s((*%s))" % (handle64VarAccess, mapFunc64, access)) self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes) else: if lenAccessGuard is not None: self.cgen.beginIf(lenAccessGuard) self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k") self.cgen.stmt("uint64_t tmpval = %s(%s[k])" % (mapFunc64, access)) self.cgen.stmt("memcpy(%s_ptr + k * 8, &tmpval, sizeof(uint64_t))" % (handle64Var)) self.cgen.endFor() if lenAccessGuard is not None: self.cgen.endIf() self.genPtrIncr("8 * %s" % lenAccess) else: if "1" == lenAccess: self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes) self.cgen.stmt("*%s%s = (%s)%s((%s)(*%s))" % ( self.makeCastExpr(vulkanType.getForNonConstAccess()), access, vulkanType.typeName, mapFunc, vulkanType.typeName, handle64VarAccess)) else: self.genPtrIncr("8 * %s" % lenAccess) if lenAccessGuard is not None: self.cgen.beginIf(lenAccessGuard) self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k") self.cgen.stmt("uint64_t tmpval; memcpy(&tmpval, %s_ptr + k * 8, sizeof(uint64_t))" % handle64Var) self.cgen.stmt("*((%s%s) + k) = (%s)%s((%s)tmpval)" % ( self.makeCastExpr(vulkanType.getForNonConstAccess()), access, vulkanType.typeName, mapFunc, vulkanType.typeName)) if lenAccessGuard is not None: self.cgen.endIf() self.cgen.endFor() if lenAccess != "1": self.cgen.endIf() def doAllocSpace(self, vulkanType): if self.dynAlloc and self.direction == "read": access = self.exprAccessor(vulkanType) lenAccess = self.lenAccessor(vulkanType) sizeof = self.cgen.sizeofExpr(vulkanType.getForValueAccess()) if lenAccess: bytesExpr = "%s * %s" % (lenAccess, sizeof) else: bytesExpr = sizeof lenAccess = "1" if self.stackVar: if self.stackArrSize != lenAccess: self.cgen.beginIf("%s <= %s" % (lenAccess, self.stackArrSize)) self.cgen.stmt( "%s = %s%s" % (access, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.stackVar)) if self.stackArrSize != lenAccess: self.cgen.endIf() self.cgen.beginElse() if self.stackArrSize != lenAccess: self.cgen.stmt( "%s->alloc((void**)&%s, %s)" % (self.streamVarName, access, bytesExpr)) if self.stackArrSize != lenAccess: self.cgen.endIf() else: self.cgen.stmt( "%s->alloc((void**)&%s, %s)" % (self.streamVarName, access, bytesExpr)) def getOptionalStringFeatureExpr(self, vulkanType): streamFeature = vulkanType.getProtectStreamFeature() if streamFeature is None: return None return "%s->getFeatureBits() & %s" % (self.streamVarName, streamFeature) def onCheck(self, vulkanType): if self.forApiOutput: return featureExpr = self.getOptionalStringFeatureExpr(vulkanType) self.checked = True access = self.exprAccessor(vulkanType) needConsistencyCheck = False self.cgen.line("// WARNING PTR CHECK") if (self.dynAlloc and self.direction == "read") or self.direction == "write": checkAccess = self.exprAccessor(vulkanType) addrExpr = "&" + checkAccess sizeExpr = self.cgen.sizeofExpr(vulkanType) else: checkName = "check_%s" % vulkanType.paramName self.cgen.stmt("%s %s" % ( self.cgen.makeCTypeDecl(vulkanType, useParamName = False), checkName)) checkAccess = checkName addrExpr = "&" + checkAccess sizeExpr = self.cgen.sizeofExpr(vulkanType) needConsistencyCheck = True if featureExpr is not None: self.cgen.beginIf(featureExpr) self.genPrimitiveStreamCall( vulkanType, checkAccess) if featureExpr is not None: self.cgen.endIf() if featureExpr is not None: self.cgen.beginIf("(!(%s) || %s)" % (featureExpr, access)) else: self.cgen.beginIf(access) if needConsistencyCheck and featureExpr is None: self.cgen.beginIf("!(%s)" % checkName) self.cgen.stmt( "fprintf(stderr, \"fatal: %s inconsistent between guest and host\\n\")" % (access)) self.cgen.endIf() def onCheckWithNullOptionalStringFeature(self, vulkanType): self.cgen.beginIf("%s->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.streamVarName) self.onCheck(vulkanType) def endCheckWithNullOptionalStringFeature(self, vulkanType): self.endCheck(vulkanType) self.cgen.endIf() self.cgen.beginElse() def finalCheckWithNullOptionalStringFeature(self, vulkanType): self.cgen.endElse() def endCheck(self, vulkanType): if self.checked: self.cgen.endIf() self.checked = False def genFilterFunc(self, filterfunc, env): def loop(expr, lambdaEnv={}): def do_func(expr): fnamestr = expr.name.name if "not" == fnamestr: return "!(%s)" % (loop(expr.args[0], lambdaEnv)) if "eq" == fnamestr: return "(%s == %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) if "and" == fnamestr: return "(%s && %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) if "or" == fnamestr: return "(%s || %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) if "bitwise_and" == fnamestr: return "(%s & %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) if "getfield" == fnamestr: ptrlevels = get_ptrlevels(expr.args[0].val.name) if ptrlevels == 0: return "%s.%s" % (loop(expr.args[0], lambdaEnv), expr.args[1].val) else: return "(%s(%s)).%s" % ("*" * ptrlevels, loop(expr.args[0], lambdaEnv), expr.args[1].val) if "if" == fnamestr: return "((%s) ? (%s) : (%s))" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv), loop(expr.args[2], lambdaEnv)) return "%s(%s)" % (fnamestr, ", ".join(map(lambda e: loop(e, lambdaEnv), expr.args))) def do_expratom(atomname, lambdaEnv= {}): if lambdaEnv.get(atomname, None) is not None: return atomname enventry = env.get(atomname, None) if None != enventry: return self.getEnvAccessExpr(atomname) return atomname def get_ptrlevels(atomname, lambdaEnv= {}): if lambdaEnv.get(atomname, None) is not None: return 0 enventry = env.get(atomname, None) if None != enventry: return self.getPointerIndirectionLevels(atomname) return 0 def do_exprval(expr, lambdaEnv= {}): expratom = expr.val if Atom == type(expratom): return do_expratom(expratom.name, lambdaEnv) return "%s" % expratom def do_lambda(expr, lambdaEnv= {}): params = expr.vs body = expr.body newEnv = {} for (k, v) in lambdaEnv.items(): newEnv[k] = v for p in params: newEnv[p.name] = p.typ return "[](%s) { return %s; }" % (", ".join(list(map(lambda p: "%s %s" % (p.typ, p.name), params))), loop(body, lambdaEnv=newEnv)) if FuncExpr == type(expr): return do_func(expr) if FuncLambda == type(expr): return do_lambda(expr) elif FuncExprVal == type(expr): return do_exprval(expr) return loop(filterfunc) def beginFilterGuard(self, vulkanType): if vulkanType.filterVar == None: return if self.doFiltering == False: return filterVarAccess = self.getEnvAccessExpr(vulkanType.filterVar) filterValsExpr = None filterFuncExpr = None filterExpr = None filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName if None != vulkanType.filterVals: filterValsExpr = " || ".join(map(lambda filterval: "(%s == %s)" % (filterval, filterVarAccess), vulkanType.filterVals)) if None != vulkanType.filterFunc: filterFuncExpr = self.genFilterFunc(vulkanType.filterFunc, self.currentStructInfo.environment) if None != filterValsExpr and None != filterFuncExpr: filterExpr = "%s || %s" % (filterValsExpr, filterFuncExpr) elif None == filterValsExpr and None == filterFuncExpr: # Assume is bool self.cgen.beginIf(filterVarAccess) elif None != filterValsExpr: self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterValsExpr)) elif None != filterFuncExpr: self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterFuncExpr)) def endFilterGuard(self, vulkanType, cleanupExpr=None): if vulkanType.filterVar == None: return if self.doFiltering == False: return if cleanupExpr == None: self.cgen.endIf() else: self.cgen.endIf() self.cgen.beginElse() self.cgen.stmt(cleanupExpr) self.cgen.endElse() def getEnvAccessExpr(self, varName): parentEnvEntry = self.currentStructInfo.environment.get(varName, None) if parentEnvEntry != None: isParentMember = parentEnvEntry["structmember"] if isParentMember: envAccess = self.exprValueAccessor(list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0]) else: envAccess = varName return envAccess return None def getPointerIndirectionLevels(self, varName): parentEnvEntry = self.currentStructInfo.environment.get(varName, None) if parentEnvEntry != None: isParentMember = parentEnvEntry["structmember"] if isParentMember: return list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0].pointerIndirectionLevels else: return 0 return 0 return 0 def onCompoundType(self, vulkanType): access = self.exprAccessor(vulkanType) lenAccess = self.lenAccessor(vulkanType) self.beginFilterGuard(vulkanType) if vulkanType.pointerIndirectionLevels > 0: self.doAllocSpace(vulkanType) 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) accessWithCast = "%s(%s)" % (self.makeCastExpr( self.getTypeForStreaming(vulkanType)), access) callParams = [self.streamVarName, self.rootTypeVarName, accessWithCast, self.ptrVar] for (bindName, localName) in vulkanType.binds.items(): callParams.append(self.getEnvAccessExpr(localName)) self.cgen.funcCall(None, self.marshalPrefix + vulkanType.typeName, callParams) if lenAccess is not None: self.cgen.endFor() if self.direction == "read": self.endFilterGuard(vulkanType, "%s = 0" % self.exprAccessor(vulkanType)) else: self.endFilterGuard(vulkanType) def onString(self, vulkanType): access = self.exprAccessor(vulkanType) if self.direction == "write": self.cgen.beginBlock() self.cgen.stmt("uint32_t l = %s ? strlen(%s): 0" % (access, access)) self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&l", "sizeof(uint32_t)", toBe = True, actualSize = 4) self.genMemcpyAndIncr(self.ptrVar, "(char*)", access, "l") self.cgen.endBlock() else: castExpr = \ self.makeCastExpr( \ self.getTypeForStreaming( \ vulkanType.getForAddressAccess())) self.cgen.stmt( \ "%s->loadStringInPlaceWithStreamPtr(%s&%s, %s)" % (self.streamVarName, castExpr, access, self.ptrVar)) def onStringArray(self, vulkanType): access = self.exprAccessor(vulkanType) lenAccess = self.lenAccessor(vulkanType) lenAccessGuard = self.lenAccessorGuard(vulkanType) if self.direction == "write": self.cgen.beginBlock() self.cgen.stmt("uint32_t c = 0") if lenAccessGuard is not None: self.cgen.beginIf(lenAccessGuard) self.cgen.stmt("c = %s" % (lenAccess)) if lenAccessGuard is not None: self.cgen.endIf() self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&c", "sizeof(uint32_t)", toBe = True, actualSize = 4) self.cgen.beginFor("uint32_t i = 0", "i < c", "++i") self.cgen.stmt("uint32_t l = %s ? strlen(%s[i]): 0" % (access, access)) self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&l", "sizeof(uint32_t)", toBe = True, actualSize = 4) self.cgen.beginIf("l") self.genMemcpyAndIncr(self.ptrVar, "(char*)", "(%s[i])" % access, "l") self.cgen.endIf() self.cgen.endFor() self.cgen.endBlock() else: castExpr = \ self.makeCastExpr( \ self.getTypeForStreaming( \ vulkanType.getForAddressAccess())) self.cgen.stmt("%s->loadStringArrayInPlaceWithStreamPtr(%s&%s, %s)" % (self.streamVarName, castExpr, access, self.ptrVar)) def onStaticArr(self, vulkanType): access = self.exprValueAccessor(vulkanType) lenAccess = self.lenAccessor(vulkanType) finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType)) self.genStreamCall(vulkanType, access, finalLenExpr) # Old version VkEncoder may have some sType values conflict with VkDecoder # of new versions. For host decoder, it should not carry the incorrect old # sType values to the |forUnmarshaling| struct. Instead it should overwrite # the sType value. def overwriteSType(self, vulkanType): if self.direction == "read": sTypeParam = copy(vulkanType) sTypeParam.paramName = "sType" sTypeAccess = self.exprAccessor(sTypeParam) typeName = vulkanType.parent.typeName if typeName in STYPE_OVERRIDE: self.cgen.stmt("%s = %s" % (sTypeAccess, STYPE_OVERRIDE[typeName])) def onStructExtension(self, vulkanType): self.overwriteSType(vulkanType) sTypeParam = copy(vulkanType) sTypeParam.paramName = "sType" access = self.exprAccessor(vulkanType) sizeVar = "%s_size" % vulkanType.paramName if self.direction == "read": castedAccessExpr = "(%s)(%s)" % ("void*", access) else: castedAccessExpr = access sTypeAccess = self.exprAccessor(sTypeParam) self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" % self.rootTypeVarName) self.cgen.stmt("%s = %s" % (self.rootTypeVarName, sTypeAccess)) self.cgen.endIf() if self.direction == "read" and self.dynAlloc: self.cgen.stmt("uint32_t %s" % sizeVar) self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)", "&" + sizeVar, "sizeof(uint32_t)", toBe = True, actualSize = 4) self.cgen.stmt("%s = nullptr" % access) self.cgen.beginIf(sizeVar) self.cgen.stmt( \ "%s->alloc((void**)&%s, sizeof(VkStructureType))" % (self.streamVarName, access)) self.genStreamCall(vulkanType, access, "sizeof(VkStructureType)") self.cgen.stmt("VkStructureType extType = *(VkStructureType*)(%s)" % access) self.cgen.stmt( \ "%s->alloc((void**)&%s, %s(%s->getFeatureBits(), %s, %s))" % (self.streamVarName, access, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, self.streamVarName, self.rootTypeVarName, access)) self.cgen.stmt("*(VkStructureType*)%s = extType" % access) self.cgen.funcCall(None, self.marshalPrefix + "extension_struct", [self.streamVarName, self.rootTypeVarName, castedAccessExpr, self.ptrVar]) self.cgen.endIf() else: self.cgen.funcCall(None, self.marshalPrefix + "extension_struct", [self.streamVarName, self.rootTypeVarName, castedAccessExpr, self.ptrVar]) def onPointer(self, vulkanType): access = self.exprAccessor(vulkanType) lenAccess = self.lenAccessor(vulkanType) lenAccessGuard = self.lenAccessorGuard(vulkanType) self.beginFilterGuard(vulkanType) self.doAllocSpace(vulkanType) if vulkanType.filterVar != None: print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar)) if vulkanType.isHandleType() and self.mapHandles: self.genHandleMappingCall( vulkanType, access, lenAccess, lenAccessGuard) else: if self.typeInfo.isNonAbiPortableType(vulkanType.typeName): if lenAccess is not None: if lenAccessGuard is not None: self.cgen.beginIf(lenAccessGuard) self.cgen.beginFor("uint32_t i = 0", "i < (uint32_t)%s" % lenAccess, "++i") self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "%s[i]" % access) self.cgen.endFor() if lenAccessGuard is not None: self.cgen.endIf() else: self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "(*%s)" % access) else: if lenAccess is not None: finalLenExpr = "%s * %s" % ( lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess())) else: finalLenExpr = "%s" % ( self.cgen.sizeofExpr(vulkanType.getForValueAccess())) self.genStreamCall(vulkanType, access, finalLenExpr) if self.direction == "read": self.endFilterGuard(vulkanType, "%s = 0" % access) else: self.endFilterGuard(vulkanType) def onValue(self, vulkanType): self.beginFilterGuard(vulkanType) if vulkanType.isHandleType() and self.mapHandles: access = self.exprAccessor(vulkanType) if vulkanType.filterVar != None: print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar)) self.genHandleMappingCall( vulkanType.getForAddressAccess(), access, "1", None) elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName): access = self.exprPrimitiveValueAccessor(vulkanType) self.genPrimitiveStreamCall(vulkanType, access) else: access = self.exprAccessor(vulkanType) self.genStreamCall(vulkanType, access, self.cgen.sizeofExpr(vulkanType)) self.endFilterGuard(vulkanType) def streamLetParameter(self, structInfo, letParamInfo): filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName)) self.cgen.beginIf(filterFeature) if self.direction == "write": bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"] self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment))) self.genPrimitiveStreamCall(letParamInfo, letParamInfo.paramName) self.cgen.endIf() class VulkanReservedMarshaling(VulkanWrapperGenerator): def __init__(self, module, typeInfo, variant="host"): VulkanWrapperGenerator.__init__(self, module, typeInfo) self.cgenHeader = CodeGen() self.cgenImpl = CodeGen() self.variant = variant self.currentFeature = None self.apiOpcodes = {} self.dynAlloc = self.variant != "guest" self.ptrVarName = "ptr" self.ptrVarType = makeVulkanTypeSimple(False, "uint8_t", 2, self.ptrVarName) self.ptrVarTypeUnmarshal = makeVulkanTypeSimple(False, "uint8_t", 2, self.ptrVarName) if self.variant == "guest": self.marshalingParams = PARAMETERS_MARSHALING_GUEST else: self.marshalingParams = PARAMETERS_MARSHALING self.writeCodegen = \ VulkanReservedMarshalingCodegen( None, self.variant, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, MARSHAL_INPUT_VAR_NAME, self.ptrVarName, API_PREFIX_RESERVEDMARSHAL, "get_host_u64_" if "guest" == self.variant else "", direction = "write") self.readCodegen = \ VulkanReservedMarshalingCodegen( None, self.variant, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, UNMARSHAL_INPUT_VAR_NAME, self.ptrVarName, API_PREFIX_RESERVEDUNMARSHAL, "unbox_" if "host" == self.variant else "", direction = "read", dynAlloc=self.dynAlloc) self.knownDefs = {} self.extensionMarshalPrototype = \ VulkanAPI(API_PREFIX_RESERVEDMARSHAL + "extension_struct", STREAM_RET_TYPE, self.marshalingParams + [STRUCT_EXTENSION_PARAM, self.ptrVarType]) self.extensionUnmarshalPrototype = \ VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + "extension_struct", STREAM_RET_TYPE, self.marshalingParams + [STRUCT_EXTENSION_PARAM_FOR_WRITE, self.ptrVarTypeUnmarshal]) def onBegin(self,): VulkanWrapperGenerator.onBegin(self) self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionMarshalPrototype)) self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionUnmarshalPrototype)) def onBeginFeature(self, featureName, featureType): VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType) self.currentFeature = featureName 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: if self.variant != "host": self.module.appendHeader( self.cgenHeader.makeFuncAlias(API_PREFIX_RESERVEDMARSHAL + name, API_PREFIX_RESERVEDMARSHAL + alias)) if self.variant != "guest": self.module.appendHeader( self.cgenHeader.makeFuncAlias(API_PREFIX_RESERVEDUNMARSHAL + name, API_PREFIX_RESERVEDUNMARSHAL + alias)) if category in ["struct", "union"] and not alias: structInfo = self.typeInfo.structs[name] marshalParams = self.marshalingParams + \ [makeVulkanTypeSimple(True, name, 1, MARSHAL_INPUT_VAR_NAME), self.ptrVarType] freeParams = [] letParams = [] for (envname, bindingInfo) in list(sorted(structInfo.environment.items(), key = lambda kv: kv[0])): if None == bindingInfo["binding"]: freeParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname)) else: if not bindingInfo["structmember"]: letParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname)) marshalPrototype = \ VulkanAPI(API_PREFIX_RESERVEDMARSHAL + name, STREAM_RET_TYPE, marshalParams + freeParams) marshalPrototypeNoFilter = \ VulkanAPI(API_PREFIX_RESERVEDMARSHAL + name, STREAM_RET_TYPE, marshalParams) def structMarshalingCustom(cgen): self.writeCodegen.cgen = cgen self.writeCodegen.currentStructInfo = structInfo marshalingCode = \ CUSTOM_MARSHAL_TYPES[name]["common"] + \ CUSTOM_MARSHAL_TYPES[name]["reservedmarshaling"].format( streamVarName=self.writeCodegen.streamVarName, rootTypeVarName=self.writeCodegen.rootTypeVarName, inputVarName=self.writeCodegen.inputVarName, newInputVarName=self.writeCodegen.inputVarName + "_new") for line in marshalingCode.split('\n'): cgen.line(line) def structMarshalingDef(cgen): self.writeCodegen.cgen = cgen self.writeCodegen.currentStructInfo = structInfo self.writeCodegen.cgen.stmt("(void)%s" % VULKAN_STREAM_VAR_NAME) self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) if category == "struct": # marshal 'let' parameters first for letp in letParams: self.writeCodegen.streamLetParameter(self.typeInfo, letp) for member in structInfo.members: iterateVulkanType(self.typeInfo, member, self.writeCodegen) if category == "union": iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen) def structMarshalingDefNoFilter(cgen): self.writeCodegen.cgen = cgen self.writeCodegen.currentStructInfo = structInfo self.writeCodegen.doFiltering = False self.writeCodegen.cgen.stmt("(void)%s" % VULKAN_STREAM_VAR_NAME) self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) if category == "struct": # marshal 'let' parameters first for letp in letParams: self.writeCodegen.streamLetParameter(self.typeInfo, letp) for member in structInfo.members: iterateVulkanType(self.typeInfo, member, self.writeCodegen) if category == "union": iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen) self.writeCodegen.doFiltering = True if self.variant != "host": self.module.appendHeader( self.cgenHeader.makeFuncDecl(marshalPrototype)) if name in CUSTOM_MARSHAL_TYPES: self.module.appendImpl( self.cgenImpl.makeFuncImpl( marshalPrototype, structMarshalingCustom)) else: self.module.appendImpl( self.cgenImpl.makeFuncImpl( marshalPrototype, structMarshalingDef)) if freeParams != []: self.module.appendHeader( self.cgenHeader.makeFuncDecl(marshalPrototypeNoFilter)) self.module.appendImpl( self.cgenImpl.makeFuncImpl( marshalPrototypeNoFilter, structMarshalingDefNoFilter)) unmarshalPrototype = \ VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + name, STREAM_RET_TYPE, self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME), self.ptrVarTypeUnmarshal] + freeParams) unmarshalPrototypeNoFilter = \ VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + name, STREAM_RET_TYPE, self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME), self.ptrVarTypeUnmarshal]) def structUnmarshalingCustom(cgen): self.readCodegen.cgen = cgen self.readCodegen.currentStructInfo = structInfo unmarshalingCode = \ CUSTOM_MARSHAL_TYPES[name]["common"] + \ CUSTOM_MARSHAL_TYPES[name]["reservedunmarshaling"].format( streamVarName=self.readCodegen.streamVarName, rootTypeVarName=self.readCodegen.rootTypeVarName, inputVarName=self.readCodegen.inputVarName, newInputVarName=self.readCodegen.inputVarName + "_new") for line in unmarshalingCode.split('\n'): cgen.line(line) def structUnmarshalingDef(cgen): self.readCodegen.cgen = cgen self.readCodegen.currentStructInfo = structInfo if category == "struct": # unmarshal 'let' parameters first for letp in letParams: self.readCodegen.streamLetParameter(self.typeInfo, letp) for member in structInfo.members: iterateVulkanType(self.typeInfo, member, self.readCodegen) if category == "union": iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen) def structUnmarshalingDefNoFilter(cgen): self.readCodegen.cgen = cgen self.readCodegen.currentStructInfo = structInfo self.readCodegen.doFiltering = False if category == "struct": # unmarshal 'let' parameters first for letp in letParams: iterateVulkanType(self.typeInfo, letp, self.readCodegen) for member in structInfo.members: iterateVulkanType(self.typeInfo, member, self.readCodegen) if category == "union": iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen) self.readCodegen.doFiltering = True if self.variant != "guest": self.module.appendHeader( self.cgenHeader.makeFuncDecl(unmarshalPrototype)) if name in CUSTOM_MARSHAL_TYPES: self.module.appendImpl( self.cgenImpl.makeFuncImpl( unmarshalPrototype, structUnmarshalingCustom)) else: self.module.appendImpl( self.cgenImpl.makeFuncImpl( unmarshalPrototype, structUnmarshalingDef)) if freeParams != []: self.module.appendHeader( self.cgenHeader.makeFuncDecl(unmarshalPrototypeNoFilter)) self.module.appendImpl( self.cgenImpl.makeFuncImpl( unmarshalPrototypeNoFilter, structUnmarshalingDefNoFilter)) def onGenCmd(self, cmdinfo, name, alias): VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias) def doExtensionStructMarshalingCodegen(self, cgen, retType, extParam, forEach, funcproto, direction): accessVar = "structAccess" sizeVar = "currExtSize" cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName)) cgen.stmt("uint32_t %s = %s(%s->getFeatureBits(), %s, %s)" % (sizeVar, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, extParam.paramName)) cgen.beginIf("!%s && %s" % (sizeVar, extParam.paramName)) cgen.line("// unknown struct extension; skip and call on its pNext field"); cgen.funcCall(None, funcproto.name, ["vkStream", ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar, self.ptrVarName]) cgen.stmt("return") cgen.endIf() cgen.beginElse() cgen.line("// known or null extension struct") streamNamespace = "gfxstream::guest" if self.variant == "guest" else "android::base" if direction == "write": cgen.stmt("memcpy(*%s, &%s, sizeof(uint32_t));" % (self.ptrVarName, sizeVar)) cgen.stmt("%s::Stream::toBe32((uint8_t*)*%s); *%s += sizeof(uint32_t)" % (streamNamespace, self.ptrVarName, self.ptrVarName)) elif not self.dynAlloc: cgen.stmt("memcpy(&%s, *%s, sizeof(uint32_t));" % (sizeVar, self.ptrVarName)) cgen.stmt("%s::Stream::fromBe32((uint8_t*)&%s); *%s += sizeof(uint32_t)" % (streamNamespace, sizeVar, self.ptrVarName)) cgen.beginIf("!%s" % (sizeVar)) cgen.line("// exit if this was a null extension struct (size == 0 in this branch)") cgen.stmt("return") cgen.endIf() cgen.endIf() # Now we can do stream stuff if direction == "write": cgen.stmt("memcpy(*%s, %s, sizeof(VkStructureType)); *%s += sizeof(VkStructureType)" % (self.ptrVarName, extParam.paramName, self.ptrVarName)) elif not self.dynAlloc: cgen.stmt("uint64_t pNext_placeholder") placeholderAccess = "(&pNext_placeholder)" cgen.stmt("memcpy(%s, *%s, sizeof(VkStructureType)); *%s += sizeof(VkStructureType)" % (placeholderAccess, self.ptrVarName, self.ptrVarName)) cgen.stmt("(void)pNext_placeholder") def fatalDefault(cgen): cgen.line("// fatal; the switch is only taken if the extension struct is known"); cgen.stmt("abort()") pass self.emitForEachStructExtension( cgen, retType, extParam, forEach, defaultEmit=fatalDefault, rootTypeVar=ROOT_TYPE_PARAM) def onEnd(self,): VulkanWrapperGenerator.onEnd(self) def forEachExtensionMarshal(ext, castedAccess, cgen): cgen.funcCall(None, API_PREFIX_RESERVEDMARSHAL + ext.name, [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess, self.ptrVarName]) def forEachExtensionUnmarshal(ext, castedAccess, cgen): cgen.funcCall(None, API_PREFIX_RESERVEDUNMARSHAL + ext.name, [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess, self.ptrVarName]) if self.variant != "host": self.module.appendImpl( self.cgenImpl.makeFuncImpl( self.extensionMarshalPrototype, lambda cgen: self.doExtensionStructMarshalingCodegen( cgen, STREAM_RET_TYPE, STRUCT_EXTENSION_PARAM, forEachExtensionMarshal, self.extensionMarshalPrototype, "write"))) if self.variant != "guest": self.module.appendImpl( self.cgenImpl.makeFuncImpl( self.extensionUnmarshalPrototype, lambda cgen: self.doExtensionStructMarshalingCodegen( cgen, STREAM_RET_TYPE, STRUCT_EXTENSION_PARAM_FOR_WRITE, forEachExtensionUnmarshal, self.extensionUnmarshalPrototype, "read")))