You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1036 lines
41 KiB
1036 lines
41 KiB
# 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
|
|
import hashlib, sys
|
|
|
|
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_MARSHAL
|
|
from .wrapperdefs import API_PREFIX_UNMARSHAL
|
|
|
|
from .marshalingdefs import KNOWN_FUNCTION_OPCODES, CUSTOM_MARSHAL_TYPES
|
|
|
|
class VulkanMarshalingCodegen(VulkanTypeIterator):
|
|
|
|
def __init__(self,
|
|
cgen,
|
|
streamVarName,
|
|
rootTypeVarName,
|
|
inputVarName,
|
|
marshalPrefix,
|
|
direction = "write",
|
|
forApiOutput = False,
|
|
dynAlloc = False,
|
|
mapHandles = True,
|
|
handleMapOverwrites = False,
|
|
doFiltering = True):
|
|
self.cgen = cgen
|
|
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.marshalPrefix = marshalPrefix
|
|
|
|
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
|
|
|
|
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 genStreamCall(self, vulkanType, toStreamExpr, sizeExpr):
|
|
varname = self.streamVarName
|
|
func = self.processSimple
|
|
cast = self.makeCastExpr(self.getTypeForStreaming(vulkanType))
|
|
|
|
self.cgen.stmt(
|
|
"%s->%s(%s%s, %s)" % (varname, func, cast, toStreamExpr, sizeExpr))
|
|
|
|
def genPrimitiveStreamCall(self, vulkanType, access):
|
|
varname = self.streamVarName
|
|
|
|
self.cgen.streamPrimitive(
|
|
self.typeInfo,
|
|
varname,
|
|
access,
|
|
vulkanType,
|
|
direction=self.direction)
|
|
|
|
def genHandleMappingCall(self, vulkanType, access, lenAccess):
|
|
|
|
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("uint64_t* %s" % handle64Var)
|
|
self.cgen.stmt(
|
|
"%s->alloc((void**)&%s, %s * 8)" % \
|
|
(self.streamVarName, handle64Var, lenAccess))
|
|
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.direction == "write":
|
|
if self.handleMapOverwrites:
|
|
self.cgen.stmt(
|
|
"static_assert(8 == sizeof(%s), \"handle map overwrite requires %s to be 8 bytes long\")" % \
|
|
(vulkanType.typeName, vulkanType.typeName))
|
|
self.cgen.stmt(
|
|
"%s->handleMapping()->mapHandles_%s((%s*)%s, %s)" %
|
|
(self.streamVarName, vulkanType.typeName, vulkanType.typeName,
|
|
access, lenAccess))
|
|
self.genStreamCall(vulkanType, access, "8 * %s" % lenAccess)
|
|
else:
|
|
self.cgen.stmt(
|
|
"%s->handleMapping()->mapHandles_%s_u64(%s, %s, %s)" %
|
|
(self.streamVarName, vulkanType.typeName,
|
|
access,
|
|
handle64VarAccess, lenAccess))
|
|
self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
|
|
else:
|
|
self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
|
|
self.cgen.stmt(
|
|
"%s->handleMapping()->mapHandles_u64_%s(%s, %s%s, %s)" %
|
|
(self.streamVarName, vulkanType.typeName,
|
|
handle64VarAccess,
|
|
self.makeCastExpr(vulkanType.getForNonConstAccess()), access,
|
|
lenAccess))
|
|
|
|
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
|
|
|
|
self.cgen.stmt( \
|
|
"%s->alloc((void**)&%s, %s)" %
|
|
(self.streamVarName,
|
|
access, bytesExpr))
|
|
|
|
def getOptionalStringFeatureExpr(self, vulkanType):
|
|
if vulkanType.optionalStr is not None:
|
|
if vulkanType.optionalStr.startswith("streamFeature:"):
|
|
splitted = vulkanType.optionalStr.split(":")
|
|
featureExpr = "%s->getFeatureBits() & %s" % (self.streamVarName, splitted[1])
|
|
return featureExpr
|
|
return None
|
|
|
|
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 "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)
|
|
lenAccessGuard = self.lenAccessorGuard(vulkanType)
|
|
|
|
self.beginFilterGuard(vulkanType)
|
|
|
|
if vulkanType.pointerIndirectionLevels > 0:
|
|
self.doAllocSpace(vulkanType)
|
|
|
|
if lenAccess is not None:
|
|
if lenAccessGuard is not None:
|
|
self.cgen.beginIf(lenAccessGuard)
|
|
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]
|
|
|
|
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 lenAccessGuard is not None:
|
|
self.cgen.endIf()
|
|
|
|
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.stmt("%s->putString(%s)" % (self.streamVarName, access))
|
|
else:
|
|
castExpr = \
|
|
self.makeCastExpr( \
|
|
self.getTypeForStreaming( \
|
|
vulkanType.getForAddressAccess()))
|
|
|
|
self.cgen.stmt( \
|
|
"%s->loadStringInPlace(%s&%s)" % (self.streamVarName, castExpr, access))
|
|
|
|
def onStringArray(self, vulkanType):
|
|
|
|
access = self.exprAccessor(vulkanType)
|
|
lenAccess = self.lenAccessor(vulkanType)
|
|
|
|
if self.direction == "write":
|
|
self.cgen.stmt("saveStringArray(%s, %s, %s)" % (self.streamVarName,
|
|
access, lenAccess))
|
|
else:
|
|
castExpr = \
|
|
self.makeCastExpr( \
|
|
self.getTypeForStreaming( \
|
|
vulkanType.getForAddressAccess()))
|
|
|
|
self.cgen.stmt("%s->loadStringArrayInPlace(%s&%s)" % (self.streamVarName, castExpr, access))
|
|
|
|
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("size_t %s" % sizeVar)
|
|
self.cgen.stmt("%s = %s->getBe32()" % \
|
|
(sizeVar, self.streamVarName))
|
|
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.cgen.endIf()
|
|
else:
|
|
|
|
self.cgen.funcCall(None, self.marshalPrefix + "extension_struct",
|
|
[self.streamVarName, self.rootTypeVarName, castedAccessExpr])
|
|
|
|
|
|
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)
|
|
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")
|
|
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 VulkanMarshaling(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"
|
|
|
|
if self.variant == "guest":
|
|
self.marshalingParams = PARAMETERS_MARSHALING_GUEST
|
|
else:
|
|
self.marshalingParams = PARAMETERS_MARSHALING
|
|
|
|
self.writeCodegen = \
|
|
VulkanMarshalingCodegen(
|
|
None,
|
|
VULKAN_STREAM_VAR_NAME,
|
|
ROOT_TYPE_VAR_NAME,
|
|
MARSHAL_INPUT_VAR_NAME,
|
|
API_PREFIX_MARSHAL,
|
|
direction = "write")
|
|
|
|
self.readCodegen = \
|
|
VulkanMarshalingCodegen(
|
|
None,
|
|
VULKAN_STREAM_VAR_NAME,
|
|
ROOT_TYPE_VAR_NAME,
|
|
UNMARSHAL_INPUT_VAR_NAME,
|
|
API_PREFIX_UNMARSHAL,
|
|
direction = "read",
|
|
dynAlloc=self.dynAlloc)
|
|
|
|
self.knownDefs = {}
|
|
|
|
# Begin Vulkan API opcodes from something high
|
|
# that is not going to interfere with renderControl
|
|
# opcodes
|
|
self.beginOpcodeOld = 20000
|
|
self.endOpcodeOld = 30000
|
|
|
|
self.beginOpcode = 200000000
|
|
self.endOpcode = 300000000
|
|
self.knownOpcodes = set()
|
|
|
|
self.extensionMarshalPrototype = \
|
|
VulkanAPI(API_PREFIX_MARSHAL + "extension_struct",
|
|
STREAM_RET_TYPE,
|
|
self.marshalingParams +
|
|
[STRUCT_EXTENSION_PARAM])
|
|
|
|
self.extensionUnmarshalPrototype = \
|
|
VulkanAPI(API_PREFIX_UNMARSHAL + "extension_struct",
|
|
STREAM_RET_TYPE,
|
|
self.marshalingParams +
|
|
[STRUCT_EXTENSION_PARAM_FOR_WRITE])
|
|
|
|
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):
|
|
VulkanWrapperGenerator.onBeginFeature(self, featureName)
|
|
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:
|
|
self.module.appendHeader(
|
|
self.cgenHeader.makeFuncAlias(API_PREFIX_MARSHAL + name,
|
|
API_PREFIX_MARSHAL + alias))
|
|
self.module.appendHeader(
|
|
self.cgenHeader.makeFuncAlias(API_PREFIX_UNMARSHAL + name,
|
|
API_PREFIX_UNMARSHAL + 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)]
|
|
|
|
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_MARSHAL + name,
|
|
STREAM_RET_TYPE,
|
|
marshalParams + freeParams)
|
|
|
|
marshalPrototypeNoFilter = \
|
|
VulkanAPI(API_PREFIX_MARSHAL + name,
|
|
STREAM_RET_TYPE,
|
|
marshalParams)
|
|
|
|
def structMarshalingCustom(cgen):
|
|
self.writeCodegen.cgen = cgen
|
|
self.writeCodegen.currentStructInfo = structInfo
|
|
self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
|
|
|
|
marshalingCode = \
|
|
CUSTOM_MARSHAL_TYPES[name]["common"] + \
|
|
CUSTOM_MARSHAL_TYPES[name]["marshaling"].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" % 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" % 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
|
|
|
|
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_UNMARSHAL + name,
|
|
STREAM_RET_TYPE,
|
|
self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)] + freeParams)
|
|
|
|
unmarshalPrototypeNoFilter = \
|
|
VulkanAPI(API_PREFIX_UNMARSHAL + name,
|
|
STREAM_RET_TYPE,
|
|
self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)])
|
|
|
|
def structUnmarshalingCustom(cgen):
|
|
self.readCodegen.cgen = cgen
|
|
self.readCodegen.currentStructInfo = structInfo
|
|
self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
|
|
|
|
unmarshalingCode = \
|
|
CUSTOM_MARSHAL_TYPES[name]["common"] + \
|
|
CUSTOM_MARSHAL_TYPES[name]["unmarshaling"].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
|
|
self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
|
|
|
|
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
|
|
self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
|
|
|
|
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
|
|
|
|
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)
|
|
if name in KNOWN_FUNCTION_OPCODES:
|
|
opcode = KNOWN_FUNCTION_OPCODES[name]
|
|
else:
|
|
hashCode = hashlib.sha256(name.encode()).hexdigest()[:8]
|
|
hashInt = int(hashCode, 16)
|
|
opcode = self.beginOpcode + hashInt % (self.endOpcode - self.beginOpcode)
|
|
hasHashCollision = False
|
|
while opcode in self.knownOpcodes:
|
|
hasHashCollision = True
|
|
opcode += 1
|
|
if hasHashCollision:
|
|
print("Hash collision occurred on function '{}'. "
|
|
"Please add the following line to marshalingdefs.py:".format(name), file=sys.stderr)
|
|
print("----------------------", file=sys.stderr)
|
|
print(" \"{}\": {},".format(name, opcode), file=sys.stderr)
|
|
print("----------------------", file=sys.stderr)
|
|
|
|
self.module.appendHeader(
|
|
"#define OP_%s %d\n" % (name, opcode))
|
|
self.apiOpcodes[name] = (opcode, self.currentFeature)
|
|
self.knownOpcodes.add(opcode)
|
|
|
|
def doExtensionStructMarshalingCodegen(self, cgen, retType, extParam, forEach, funcproto, direction):
|
|
accessVar = "structAccess"
|
|
sizeVar = "currExtSize"
|
|
cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName))
|
|
cgen.stmt("size_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])
|
|
cgen.stmt("return")
|
|
|
|
cgen.endIf()
|
|
cgen.beginElse()
|
|
|
|
cgen.line("// known or null extension struct")
|
|
|
|
if direction == "write":
|
|
cgen.stmt("vkStream->putBe32(%s)" % sizeVar)
|
|
elif not self.dynAlloc:
|
|
cgen.stmt("vkStream->getBe32()");
|
|
|
|
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("vkStream->write(%s, sizeof(VkStructureType))" % extParam.paramName)
|
|
elif not self.dynAlloc:
|
|
cgen.stmt("uint64_t pNext_placeholder")
|
|
placeholderAccess = "(&pNext_placeholder)"
|
|
cgen.stmt("vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType))")
|
|
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_MARSHAL + ext.name,
|
|
[VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess])
|
|
|
|
def forEachExtensionUnmarshal(ext, castedAccess, cgen):
|
|
cgen.funcCall(None, API_PREFIX_UNMARSHAL + ext.name,
|
|
[VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess])
|
|
|
|
self.module.appendImpl(
|
|
self.cgenImpl.makeFuncImpl(
|
|
self.extensionMarshalPrototype,
|
|
lambda cgen: self.doExtensionStructMarshalingCodegen(
|
|
cgen,
|
|
STREAM_RET_TYPE,
|
|
STRUCT_EXTENSION_PARAM,
|
|
forEachExtensionMarshal,
|
|
self.extensionMarshalPrototype,
|
|
"write")))
|
|
|
|
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")))
|
|
|
|
opcode2stringPrototype = \
|
|
VulkanAPI("api_opcode_to_string",
|
|
makeVulkanTypeSimple(True, "char", 1, "none"),
|
|
[ makeVulkanTypeSimple(True, "uint32_t", 0, "opcode") ])
|
|
|
|
self.module.appendHeader(
|
|
self.cgenHeader.makeFuncDecl(opcode2stringPrototype))
|
|
|
|
def emitOpcode2StringImpl(apiOpcodes, cgen):
|
|
cgen.line("switch(opcode)")
|
|
cgen.beginBlock()
|
|
|
|
currFeature = None
|
|
|
|
for (name, (opcodeNum, feature)) in sorted(apiOpcodes.items(), key = lambda x : x[1][0]):
|
|
if not currFeature:
|
|
cgen.leftline("#ifdef %s" % feature)
|
|
currFeature = feature
|
|
|
|
if currFeature and feature != currFeature:
|
|
cgen.leftline("#endif")
|
|
cgen.leftline("#ifdef %s" % feature)
|
|
currFeature = feature
|
|
|
|
cgen.line("case OP_%s:" % name)
|
|
cgen.beginBlock()
|
|
cgen.stmt("return \"OP_%s\"" % name)
|
|
cgen.endBlock()
|
|
|
|
if currFeature:
|
|
cgen.leftline("#endif")
|
|
|
|
cgen.line("default:")
|
|
cgen.beginBlock()
|
|
cgen.stmt("return \"OP_UNKNOWN_API_CALL\"")
|
|
cgen.endBlock()
|
|
|
|
cgen.endBlock()
|
|
|
|
self.module.appendImpl(
|
|
self.cgenImpl.makeFuncImpl(
|
|
opcode2stringPrototype,
|
|
lambda cgen: emitOpcode2StringImpl(self.apiOpcodes, cgen)))
|
|
|
|
self.module.appendHeader(
|
|
"#define OP_vkFirst_old %d\n" % (self.beginOpcodeOld))
|
|
self.module.appendHeader(
|
|
"#define OP_vkLast_old %d\n" % (self.endOpcodeOld))
|
|
self.module.appendHeader(
|
|
"#define OP_vkFirst %d\n" % (self.beginOpcode))
|
|
self.module.appendHeader(
|
|
"#define OP_vkLast %d\n" % (self.endOpcode))
|