gfxstream: vulkan-Docs: import the cerealgenerator

This imports the cereal generator into the next gen
Vulkan docs.

Reviewed-by: Aaron Ruby <aruby@blackberry.com>
Acked-by: Yonggang Luo <luoyonggang@gmail.com>
Acked-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27246>
This commit is contained in:
Gurchetan Singh 2023-11-06 12:53:10 -08:00 committed by Marge Bot
parent c10d78e61e
commit 82ff5f769f
25 changed files with 12078 additions and 0 deletions

View file

@ -0,0 +1,20 @@
from .common import *
from .decoder import *
from .encoder import *
from .extensionstructs import *
from .frontend import *
from .functable import *
from .marshaling import *
from .reservedmarshaling import *
from .counting import *
from .testing import *
from .transform import *
from .deepcopy import *
from .handlemap import *
from .dispatch import *
from .unbox import *
from .decodersnapshot import *
from .subdecode import *
from .api_log_decoder import *
from .vkextensionstructuretype import VulkanGfxstreamStructureType, \
VulkanAndroidNativeBufferStructureType

View file

@ -0,0 +1,338 @@
import os
from typing import List, Set, Dict, Optional
from . import VulkanType, VulkanCompoundType
from .wrapperdefs import VulkanWrapperGenerator
class ApiLogDecoder(VulkanWrapperGenerator):
"""
This class generates decoding logic for the graphics API logs captured by
[GfxApiLogger](http://source/play-internal/battlestar/aosp/device/generic/vulkan-cereal/base/GfxApiLogger.h)
This allows developers to see a pretty-printed version of the API log data when using
print_gfx_logs.py
"""
# List of Vulkan APIs that we will generate decoding logic for
generated_apis = [
"vkAcquireImageANDROID",
"vkAllocateMemory",
"vkBeginCommandBufferAsyncGOOGLE",
"vkBindBufferMemory",
"vkBindImageMemory",
"vkCmdBeginRenderPass",
"vkCmdBindDescriptorSets",
"vkCmdBindIndexBuffer",
"vkCmdBindPipeline",
"vkCmdBindVertexBuffers",
"vkCmdClearAttachments",
"vkCmdClearColorImage",
"vkCmdCopyBufferToImage",
"vkCmdCopyImageToBuffer",
"vkCmdDraw",
"vkCmdDrawIndexed",
"vkCmdEndRenderPass",
"vkCmdPipelineBarrier",
"vkCmdSetScissor",
"vkCmdSetViewport",
"vkCollectDescriptorPoolIdsGOOGLE",
"vkCreateBufferWithRequirementsGOOGLE",
"vkCreateDescriptorPool",
"vkCreateDescriptorSetLayout",
"vkCreateFence",
"vkCreateFramebuffer",
"vkCreateGraphicsPipelines",
"vkCreateImageView",
"vkCreateImageWithRequirementsGOOGLE",
"vkCreatePipelineCache",
"vkCreateRenderPass",
"vkCreateSampler",
"vkCreateSemaphore",
"vkCreateShaderModule",
"vkDestroyBuffer",
"vkDestroyCommandPool",
"vkDestroyDescriptorPool",
"vkDestroyDescriptorSetLayout",
"vkDestroyDevice",
"vkDestroyFence",
"vkDestroyFramebuffer",
"vkDestroyImage",
"vkDestroyImageView",
"vkDestroyInstance",
"vkDestroyPipeline",
"vkDestroyPipelineCache",
"vkDestroyPipelineLayout",
"vkDestroyRenderPass",
"vkDestroySemaphore",
"vkDestroyShaderModule",
"vkEndCommandBufferAsyncGOOGLE",
"vkFreeCommandBuffers",
"vkFreeMemory",
"vkFreeMemorySyncGOOGLE",
"vkGetFenceStatus",
"vkGetMemoryHostAddressInfoGOOGLE",
"vkGetBlobGOOGLE",
"vkGetPhysicalDeviceFormatProperties",
"vkGetPhysicalDeviceProperties2KHR",
"vkGetPipelineCacheData",
"vkGetSwapchainGrallocUsageANDROID",
"vkQueueCommitDescriptorSetUpdatesGOOGLE",
"vkQueueFlushCommandsGOOGLE",
"vkQueueSignalReleaseImageANDROIDAsyncGOOGLE",
"vkQueueSubmitAsyncGOOGLE",
"vkQueueWaitIdle",
"vkResetFences",
"vkWaitForFences",
]
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
# Set of Vulkan structs that we need to write decoding logic for
self.structs: Set[str] = set()
# Maps enum group names to the list of enums in the group, for all enum groups in the spec
# E.g.: "VkResult": ["VK_SUCCESS", "VK_NOT_READY", "VK_TIMEOUT", etc...]
self.all_enums: Dict[str, List[str]] = {}
# Set of Vulkan enums that we need to write decoding logic for
self.needed_enums: Set[str] = {"VkStructureType"}
def onBegin(self):
self.module.append("""
#####################################################################################################
# Pretty-printer functions for Vulkan data structures
# THIS FILE IS AUTO-GENERATED - DO NOT EDIT
#
# To re-generate this file, run generate-vulkan-sources.sh
#####################################################################################################
""".lstrip())
def onGenGroup(self, groupinfo, groupName, alias=None):
"""Called for each enum group in the spec"""
for enum in groupinfo.elem.findall("enum"):
self.all_enums[groupName] = self.all_enums.get(groupName, []) + [enum.get('name')]
def onEnd(self):
for api_name in sorted(self.generated_apis):
self.process_api(api_name)
self.process_structs()
self.process_enums()
def process_api(self, api_name):
"""Main entry point to generate decoding logic for each Vulkan API"""
api = self.typeInfo.apis[api_name]
self.module.append('def OP_{}(printer, indent: int):\n'.format(api_name))
# Decode the sequence number. All commands have sequence numbers, except those handled
# by VkSubdecoder.cpp. The logic here is a bit of a hack since it's based on the command
# name. Ideally, we would detect whether a particular command is part of a subdecode block
# in the decoding script.
if not api_name.startswith("vkCmd") and api_name != "vkBeginCommandBufferAsyncGOOGLE":
self.module.append(' printer.write_int("seqno: ", 4, indent)\n')
for param in api.parameters:
# Add any structs that this API uses to the list of structs to write decoding logic for
if self.typeInfo.isCompoundType(param.typeName):
self.structs.add(param.typeName)
# Don't try to print the pData field of vkQueueFlushCommandsGOOGLE, those are the
# commands processed as part of the subdecode pass
if api.name == "vkQueueFlushCommandsGOOGLE" and param.paramName == "pData":
continue
# Write out decoding logic for that parameter
self.process_type(param)
# Finally, add a return statement. This is needed in case the API has no parameters.
self.module.append(' return\n\n')
def process_structs(self):
"""Writes decoding logic for all the structs that we use"""
# self.structs now contains all the structs used directly by the Vulkan APIs we use.
# Recursively expand this set to add all the structs used by these structs.
copy = self.structs.copy()
self.structs.clear()
for struct_name in copy:
self.expand_needed_structs(struct_name)
# Now we have the full list of structs that we need to write decoding logic for.
# Write a decoder for each of them
for struct_name in sorted(self.structs):
struct = self.typeInfo.structs[struct_name]
self.module.append('def struct_{}(printer, indent: int):\n'.format(struct_name))
for member in self.get_members(struct):
self.process_type(member)
self.module.append('\n')
def expand_needed_structs(self, struct_name: str):
"""
Recursively adds all the structs used by a given struct to the list of structs to process
"""
if struct_name in self.structs:
return
self.structs.add(struct_name)
struct = self.typeInfo.structs[struct_name]
for member in self.get_members(struct):
if self.typeInfo.isCompoundType(member.typeName):
self.expand_needed_structs(member.typeName)
def get_members(self, struct: VulkanCompoundType):
"""
Returns the members of a struct/union that we need to process.
For structs, returns the list of all members
For unions, returns a list with just the first member.
"""
return struct.members[0:1] if struct.isUnion else struct.members
def process_type(self, type: VulkanType):
"""
Writes decoding logic for a single Vulkan type. This could be the parameter in a Vulkan API,
or a struct member.
"""
if type.typeName == "VkStructureType":
self.module.append(
' printer.write_stype_and_pnext("{}", indent)\n'.format(
type.parent.structEnumExpr))
return
if type.isNextPointer():
return
if type.paramName == "commandBuffer":
if type.parent.name != "vkQueueFlushCommandsGOOGLE":
return
# Enums
if type.isEnum(self.typeInfo):
self.needed_enums.add(type.typeName)
self.module.append(
' printer.write_enum("{}", {}, indent)\n'.format(
type.paramName, type.typeName))
return
# Bitmasks
if type.isBitmask(self.typeInfo):
enum_type = self.typeInfo.bitmasks.get(type.typeName)
if enum_type:
self.needed_enums.add(enum_type)
self.module.append(
' printer.write_flags("{}", {}, indent)\n'.format(
type.paramName, enum_type))
return
# else, fall through and let the primitive type logic handle it
# Structs or unions
if self.typeInfo.isCompoundType(type.typeName):
self.module.append(
' printer.write_struct("{name}", struct_{type}, {optional}, {count}, indent)\n'
.format(name=type.paramName,
type=type.typeName,
optional=type.isOptionalPointer(),
count=self.get_length_expression(type)))
return
# Null-terminated strings
if type.isString():
self.module.append(' printer.write_string("{}", None, indent)\n'.format(
type.paramName))
return
# Arrays of primitive types
if type.staticArrExpr and type.primitiveEncodingSize and type.primitiveEncodingSize <= 8:
# Array sizes are specified either as a number, or as an enum value
array_size = int(type.staticArrExpr) if type.staticArrExpr.isdigit() \
else self.typeInfo.enumValues.get(type.staticArrExpr)
assert array_size is not None, type.staticArrExpr
if type.typeName == "char":
self.module.append(
' printer.write_string("{}", {}, indent)\n'.format(
type.paramName, array_size))
elif type.typeName == "float":
self.module.append(
' printer.write_float("{}", indent, count={})\n'
.format(type.paramName, array_size))
else:
self.module.append(
' printer.write_int("{name}", {int_size}, indent, signed={signed}, count={array_size})\n'
.format(name=type.paramName,
array_size=array_size,
int_size=type.primitiveEncodingSize,
signed=type.isSigned()))
return
# Pointers
if type.pointerIndirectionLevels > 0:
# Assume that all uint32* are always serialized directly rather than passed by pointers.
# This is probably not always true (e.g. out params) - fix this as needed.
size = 4 if type.primitiveEncodingSize == 4 else 8
self.module.append(
' {name} = printer.write_int("{name}", {size}, indent, optional={opt}, count={count}, big_endian={big_endian})\n'
.format(name=type.paramName,
size=size,
opt=type.isOptionalPointer(),
count=self.get_length_expression(type),
big_endian=self.using_big_endian(type)))
return
# Primitive types (ints, floats)
if type.isSimpleValueType(self.typeInfo) and type.primitiveEncodingSize:
if type.typeName == "float":
self.module.append(
' printer.write_float("{name}", indent)\n'.format(name=type.paramName))
else:
self.module.append(
' {name} = printer.write_int("{name}", {size}, indent, signed={signed}, big_endian={big_endian})\n'.format(
name=type.paramName,
size=type.primitiveEncodingSize,
signed=type.isSigned(),
big_endian=self.using_big_endian(type))
)
return
raise NotImplementedError(
"No decoding logic for {} {}".format(type.typeName, type.paramName))
def using_big_endian(self, type: VulkanType):
"""For some reason gfxstream serializes some types as big endian"""
return type.typeName == "size_t"
def get_length_expression(self, type: VulkanType) -> Optional[str]:
"""Returns the length expression for a given type"""
if type.lenExpr is None:
return None
if type.lenExpr.isalpha():
return type.lenExpr
# There are a couple of instances in the spec where we use a math expression to express the
# length (e.g. VkPipelineMultisampleStateCreateInfo). CodeGen().generalLengthAccess() has
# logic o parse these expressions correctly, but for now,we just use a simple lookup table.
known_expressions = {
r"latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]":
"int(rasterizationSamples / 32)",
r"latexmath:[\textrm{codeSize} \over 4]": "int(codeSize / 4)",
r"null-terminated": None
}
if type.lenExpr in known_expressions:
return known_expressions[type.lenExpr]
raise NotImplementedError("Unknown length expression: " + type.lenExpr)
def process_enums(self):
"""
For each Vulkan enum that we use, write out a python dictionary mapping the enum values back
to the enum name as a string
"""
for enum_name in sorted(self.needed_enums):
self.module.append('{} = {{\n'.format(enum_name))
for identifier in self.all_enums[enum_name]:
value = self.typeInfo.enumValues.get(identifier)
if value is not None and isinstance(value, int):
self.module.append(' {}: "{}",\n'.format(value, identifier))
self.module.append('}\n\n')

View file

@ -0,0 +1,2 @@
from .vulkantypes import *
from .codegen import *

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,696 @@
# 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
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM
from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
class VulkanCountingCodegen(VulkanTypeIterator):
def __init__(self, cgen, featureBitsVar, toCountVar, countVar, rootTypeVar, prefix, forApiOutput=False, mapHandles=True, handleMapOverwrites=False, doFiltering=True):
self.cgen = cgen
self.featureBitsVar = featureBitsVar
self.toCountVar = toCountVar
self.rootTypeVar = rootTypeVar
self.countVar = countVar
self.prefix = prefix
self.forApiOutput = forApiOutput
self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = True)
self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = False)
self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = False)
self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.toCountVar)
self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName = self.toCountVar)
self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.toCountVar)
self.checked = False
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()
return res
def makeCastExpr(self, vulkanType):
return "(%s)" % (
self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
def genCount(self, sizeExpr):
self.cgen.stmt("*%s += %s" % (self.countVar, sizeExpr))
def genPrimitiveStreamCall(self, vulkanType):
self.genCount(str(self.cgen.countPrimitive(
self.typeInfo,
vulkanType)))
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.handleMapOverwrites:
# self.cgen.stmt(
# "static_assert(8 == sizeof(%s), \"handle map overwrite requres %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.genCount("8 * %s" % lenAccess)
else:
# self.cgen.stmt(
# "%s->handleMapping()->mapHandles_%s_u64(%s, %s, %s)" %
# (self.streamVarName, vulkanType.typeName,
# access,
# handle64VarAccess, lenAccess))
self.genCount(handle64Bytes)
if lenAccess != "1":
self.cgen.endIf()
def doAllocSpace(self, vulkanType):
pass
def getOptionalStringFeatureExpr(self, vulkanType):
feature = vulkanType.getProtectStreamFeature()
if feature is None:
return None
return "%s & %s" % (self.featureBitsVar, feature)
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")
checkAccess = self.exprAccessor(vulkanType)
addrExpr = "&" + checkAccess
sizeExpr = self.cgen.sizeofExpr(vulkanType)
if featureExpr is not None:
self.cgen.beginIf(featureExpr)
self.genPrimitiveStreamCall(
vulkanType)
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 & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.featureBitsVar)
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 & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.featureBitsVar
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.featureBitsVar,
self.rootTypeVar, accessWithCast, self.countVar]
for (bindName, localName) in vulkanType.binds.items():
callParams.append(self.getEnvAccessExpr(localName))
self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
callParams)
if lenAccess is not None:
self.cgen.endFor()
if lenAccessGuard is not None:
self.cgen.endIf()
self.endFilterGuard(vulkanType)
def onString(self, vulkanType):
access = self.exprAccessor(vulkanType)
self.genCount("sizeof(uint32_t) + (%s ? strlen(%s) : 0)" % (access, access))
def onStringArray(self, vulkanType):
access = self.exprAccessor(vulkanType)
lenAccess = self.lenAccessor(vulkanType)
lenAccessGuard = self.lenAccessorGuard(vulkanType)
self.genCount("sizeof(uint32_t)")
if lenAccessGuard is not None:
self.cgen.beginIf(lenAccessGuard)
self.cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
self.cgen.stmt("size_t l = %s[i] ? strlen(%s[i]) : 0" % (access, access))
self.genCount("sizeof(uint32_t) + (%s[i] ? strlen(%s[i]) : 0)" % (access, access))
self.cgen.endFor()
if lenAccessGuard is not None:
self.cgen.endIf()
def onStaticArr(self, vulkanType):
access = self.exprValueAccessor(vulkanType)
lenAccess = self.lenAccessor(vulkanType)
lenAccessGuard = self.lenAccessorGuard(vulkanType)
if lenAccessGuard is not None:
self.cgen.beginIf(lenAccessGuard)
finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType))
if lenAccessGuard is not None:
self.cgen.endIf()
self.genCount(finalLenExpr)
def onStructExtension(self, vulkanType):
sTypeParam = copy(vulkanType)
sTypeParam.paramName = "sType"
access = self.exprAccessor(vulkanType)
sizeVar = "%s_size" % vulkanType.paramName
castedAccessExpr = access
sTypeAccess = self.exprAccessor(sTypeParam)
self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" %
self.rootTypeVar)
self.cgen.stmt("%s = %s" % (self.rootTypeVar, sTypeAccess))
self.cgen.endIf()
self.cgen.funcCall(None, self.prefix + "extension_struct",
[self.featureBitsVar, self.rootTypeVar, castedAccessExpr, self.countVar])
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())
self.cgen.endFor()
if lenAccessGuard is not None:
self.cgen.endIf()
else:
self.genPrimitiveStreamCall(vulkanType.getForValueAccess())
else:
if lenAccess is not None:
needLenAccessGuard = True
finalLenExpr = "%s * %s" % (
lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
else:
needLenAccessGuard = False
finalLenExpr = "%s" % (
self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
if needLenAccessGuard and lenAccessGuard is not None:
self.cgen.beginIf(lenAccessGuard)
self.genCount(finalLenExpr)
if needLenAccessGuard and lenAccessGuard is not None:
self.cgen.endIf()
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)
else:
access = self.exprAccessor(vulkanType)
self.genCount(self.cgen.sizeofExpr(vulkanType))
self.endFilterGuard(vulkanType)
def streamLetParameter(self, structInfo, letParamInfo):
filterFeature = "%s & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % (self.featureBitsVar)
self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName))
self.cgen.beginIf(filterFeature)
bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"]
self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment)))
self.genPrimitiveStreamCall(letParamInfo)
self.cgen.endIf()
class VulkanCounting(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.featureBitsVar = "featureBits"
self.featureBitsVarType = makeVulkanTypeSimple(False, "uint32_t", 0, self.featureBitsVar)
self.countingPrefix = "count_"
self.countVars = ["toCount", "count"]
self.countVarType = makeVulkanTypeSimple(False, "size_t", 1, self.countVars[1])
self.voidType = makeVulkanTypeSimple(False, "void", 0)
self.rootTypeVar = ROOT_TYPE_VAR_NAME
self.countingCodegen = \
VulkanCountingCodegen(
self.codegen,
self.featureBitsVar,
self.countVars[0],
self.countVars[1],
self.rootTypeVar,
self.countingPrefix)
self.knownDefs = {}
self.extensionCountingPrototype = \
VulkanAPI(self.countingPrefix + "extension_struct",
self.voidType,
[self.featureBitsVarType,
ROOT_TYPE_PARAM,
STRUCT_EXTENSION_PARAM,
self.countVarType])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
self.module.appendImpl(self.codegen.makeFuncDecl(
self.extensionCountingPrototype))
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:
# TODO(liyl): might not work if freeParams != []
self.module.appendHeader(
self.codegen.makeFuncAlias(self.countingPrefix + name,
self.countingPrefix + alias))
if category in ["struct", "union"] and not alias:
structInfo = self.typeInfo.structs[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))
typeFromName = \
lambda varname: \
makeVulkanTypeSimple(True, name, 1, varname)
countingParams = \
[makeVulkanTypeSimple(False, "uint32_t", 0, self.featureBitsVar),
ROOT_TYPE_PARAM,
typeFromName(self.countVars[0]),
makeVulkanTypeSimple(False, "size_t", 1, self.countVars[1])]
countingPrototype = \
VulkanAPI(self.countingPrefix + name,
self.voidType,
countingParams + freeParams)
countingPrototypeNoFilter = \
VulkanAPI(self.countingPrefix + name,
self.voidType,
countingParams)
def structCountingDef(cgen):
self.countingCodegen.cgen = cgen
self.countingCodegen.currentStructInfo = structInfo
cgen.stmt("(void)%s" % self.featureBitsVar);
cgen.stmt("(void)%s" % self.rootTypeVar);
cgen.stmt("(void)%s" % self.countVars[0]);
cgen.stmt("(void)%s" % self.countVars[1]);
if category == "struct":
# marshal 'let' parameters first
for letp in letParams:
self.countingCodegen.streamLetParameter(self.typeInfo, letp)
for member in structInfo.members:
iterateVulkanType(self.typeInfo, member, self.countingCodegen)
if category == "union":
iterateVulkanType(self.typeInfo, structInfo.members[0], self.countingCodegen)
def structCountingDefNoFilter(cgen):
self.countingCodegen.cgen = cgen
self.countingCodegen.currentStructInfo = structInfo
self.countingCodegen.doFiltering = False
cgen.stmt("(void)%s" % self.featureBitsVar);
cgen.stmt("(void)%s" % self.rootTypeVar);
cgen.stmt("(void)%s" % self.countVars[0]);
cgen.stmt("(void)%s" % self.countVars[1]);
if category == "struct":
# marshal 'let' parameters first
for letp in letParams:
self.countingCodegen.streamLetParameter(self.typeInfo, letp)
for member in structInfo.members:
iterateVulkanType(self.typeInfo, member, self.countingCodegen)
if category == "union":
iterateVulkanType(self.typeInfo, structInfo.members[0], self.countingCodegen)
self.countingCodegen.doFiltering = True
self.module.appendHeader(
self.codegen.makeFuncDecl(countingPrototype))
self.module.appendImpl(
self.codegen.makeFuncImpl(countingPrototype, structCountingDef))
if freeParams != []:
self.module.appendHeader(
self.cgenHeader.makeFuncDecl(countingPrototypeNoFilter))
self.module.appendImpl(
self.cgenImpl.makeFuncImpl(
countingPrototypeNoFilter, structCountingDefNoFilter))
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
def doExtensionStructCountCodegen(self, cgen, extParam, forEach, funcproto):
accessVar = "structAccess"
sizeVar = "currExtSize"
cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName))
cgen.stmt("size_t %s = %s(%s, %s, %s)" % (sizeVar, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME,
self.featureBitsVar, 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, [
self.featureBitsVar, ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar, self.countVars[1]])
cgen.stmt("return")
cgen.endIf()
cgen.beginElse()
cgen.line("// known or null extension struct")
cgen.stmt("*%s += sizeof(uint32_t)" % self.countVars[1])
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()
cgen.stmt("*%s += sizeof(VkStructureType)" % self.countVars[1])
def fatalDefault(cgen):
cgen.line("// fatal; the switch is only taken if the extension struct is known");
cgen.stmt("abort()")
pass
self.emitForEachStructExtension(
cgen,
makeVulkanTypeSimple(False, "void", 0, "void"),
extParam,
forEach,
defaultEmit=fatalDefault,
rootTypeVar=ROOT_TYPE_PARAM)
def onEnd(self,):
VulkanWrapperGenerator.onEnd(self)
def forEachExtensionCounting(ext, castedAccess, cgen):
cgen.funcCall(None, self.countingPrefix + ext.name,
[self.featureBitsVar, self.rootTypeVar, castedAccess, self.countVars[1]])
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.extensionCountingPrototype,
lambda cgen: self.doExtensionStructCountCodegen(
cgen,
STRUCT_EXTENSION_PARAM,
forEachExtensionCounting,
self.extensionCountingPrototype)))

View file

@ -0,0 +1,946 @@
from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeInfo,\
VulkanType
from .marshaling import VulkanMarshalingCodegen
from .reservedmarshaling import VulkanReservedMarshalingCodegen
from .transform import TransformCodegen
from .wrapperdefs import API_PREFIX_MARSHAL
from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
from .wrapperdefs import MAX_PACKET_LENGTH
from .wrapperdefs import VULKAN_STREAM_TYPE
from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
from .wrapperdefs import RELAXED_APIS
SKIPPED_DECODER_DELETES = [
"vkFreeDescriptorSets",
]
DELAYED_DECODER_DELETES = [
"vkDestroyPipelineLayout",
]
global_state_prefix = "m_state->on_"
decoder_decl_preamble = """
namespace gfxstream {
class IOStream;
class ProcessResources;
} // namespace gfxstream
namespace gfxstream {
namespace vk {
class VkDecoder {
public:
VkDecoder();
~VkDecoder();
void setForSnapshotLoad(bool forSnapshotLoad);
size_t decode(void* buf, size_t bufsize, IOStream* stream,
const ProcessResources* processResources, const VkDecoderContext&);
private:
class Impl;
std::unique_ptr<Impl> mImpl;
};
} // namespace vk
} // namespace gfxstream
"""
decoder_impl_preamble ="""
namespace gfxstream {
namespace vk {
using android::base::MetricEventBadPacketLength;
using android::base::MetricEventDuplicateSequenceNum;
class VkDecoder::Impl {
public:
Impl() : m_logCalls(android::base::getEnvironmentVariable("ANDROID_EMU_VK_LOG_CALLS") == "1"),
m_vk(vkDispatch()),
m_state(VkDecoderGlobalState::get()),
m_boxedHandleUnwrapMapping(m_state),
m_boxedHandleCreateMapping(m_state),
m_boxedHandleDestroyMapping(m_state),
m_boxedHandleUnwrapAndDeleteMapping(m_state),
m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state),
m_prevSeqno(std::nullopt) {}
%s* stream() { return &m_vkStream; }
VulkanMemReadingStream* readStream() { return &m_vkMemReadingStream; }
void setForSnapshotLoad(bool forSnapshotLoad) {
m_forSnapshotLoad = forSnapshotLoad;
}
size_t decode(void* buf, size_t bufsize, IOStream* stream,
const ProcessResources* processResources, const VkDecoderContext&);
private:
bool m_logCalls;
bool m_forSnapshotLoad = false;
VulkanDispatch* m_vk;
VkDecoderGlobalState* m_state;
%s m_vkStream { nullptr };
VulkanMemReadingStream m_vkMemReadingStream { nullptr };
BoxedHandleUnwrapMapping m_boxedHandleUnwrapMapping;
BoxedHandleCreateMapping m_boxedHandleCreateMapping;
BoxedHandleDestroyMapping m_boxedHandleDestroyMapping;
BoxedHandleUnwrapAndDeleteMapping m_boxedHandleUnwrapAndDeleteMapping;
android::base::BumpPool m_pool;
BoxedHandleUnwrapAndDeletePreserveBoxedMapping m_boxedHandleUnwrapAndDeletePreserveBoxedMapping;
std::optional<uint32_t> m_prevSeqno;
};
VkDecoder::VkDecoder() :
mImpl(new VkDecoder::Impl()) { }
VkDecoder::~VkDecoder() = default;
void VkDecoder::setForSnapshotLoad(bool forSnapshotLoad) {
mImpl->setForSnapshotLoad(forSnapshotLoad);
}
size_t VkDecoder::decode(void* buf, size_t bufsize, IOStream* stream,
const ProcessResources* processResources,
const VkDecoderContext& context) {
return mImpl->decode(buf, bufsize, stream, processResources, context);
}
// VkDecoder::Impl::decode to follow
""" % (VULKAN_STREAM_TYPE, VULKAN_STREAM_TYPE)
decoder_impl_postamble = """
} // namespace vk
} // namespace gfxstream
"""
READ_STREAM = "vkReadStream"
WRITE_STREAM = "vkStream"
# Driver workarounds for APIs that don't work well multithreaded
driver_workarounds_global_lock_apis = [ \
"vkCreatePipelineLayout",
"vkDestroyPipelineLayout",
]
def emit_param_decl_for_reading(param, cgen):
if param.staticArrExpr:
cgen.stmt(
cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
else:
cgen.stmt(
cgen.makeRichCTypeDecl(param))
def emit_unmarshal(typeInfo, param, cgen, output = False, destroy = False, noUnbox = False):
if destroy:
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"",
direction="read",
dynAlloc=True))
lenAccess = cgen.generalLengthAccess(param)
lenAccessGuard = cgen.generalLengthAccessGuard(param)
if None == lenAccess or "1" == lenAccess:
cgen.stmt("boxed_%s_preserve = %s" % (param.paramName, param.paramName))
cgen.stmt("%s = unbox_%s(%s)" % (param.paramName, param.typeName, param.paramName))
else:
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
cgen.stmt("boxed_%s_preserve[i] = %s[i]" % (param.paramName, param.paramName))
cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName, param.paramName, param.typeName, param.paramName))
cgen.endFor()
if lenAccessGuard is not None:
cgen.endIf()
else:
if noUnbox:
cgen.line("// No unbox for %s" % (param.paramName))
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"" if (output or noUnbox) else "unbox_",
direction="read",
dynAlloc=True))
def emit_dispatch_unmarshal(typeInfo: VulkanTypeInfo, param: VulkanType, cgen, globalWrapped):
cgen.stmt("// Begin {} wrapped dispatchable handle unboxing for {}".format(
"global" if globalWrapped else "non",
param.paramName))
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"",
direction="read",
dynAlloc=True))
if not globalWrapped:
cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
(param.paramName, param.typeName, param.paramName))
cgen.stmt("auto vk = dispatch_%s(%s)" %
(param.typeName, param.paramName))
cgen.stmt("// End manual dispatchable handle unboxing for %s" % param.paramName)
def emit_transform(typeInfo, param, cgen, variant="tohost"):
res = iterateVulkanType(typeInfo, param, TransformCodegen(
cgen, param.paramName, "m_state", "transform_%s_" % variant, variant))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_marshal(typeInfo, param, cgen, handleMapOverwrites=False):
iterateVulkanType(typeInfo, param, VulkanMarshalingCodegen(
cgen,
WRITE_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
API_PREFIX_MARSHAL,
direction="write",
handleMapOverwrites=handleMapOverwrites))
class DecodingParameters(object):
def __init__(self, api: VulkanAPI):
self.params: list[VulkanType] = []
self.toRead: list[VulkanType] = []
self.toWrite: list[VulkanType] = []
for i, param in enumerate(api.parameters):
if i == 0 and param.isDispatchableHandleType():
param.dispatchHandle = True
if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
param.nonDispatchableHandleCreate = True
if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
param.nonDispatchableHandleDestroy = True
if param.isDispatchableHandleType() and param.isCreatedBy(api):
param.dispatchableHandleCreate = True
if param.isDispatchableHandleType() and param.isDestroyedBy(api):
param.dispatchableHandleDestroy = True
self.toRead.append(param)
if param.possiblyOutput():
self.toWrite.append(param)
self.params.append(param)
def emit_call_log(api, cgen):
decodingParams = DecodingParameters(api)
paramsToRead = decodingParams.toRead
cgen.beginIf("m_logCalls")
paramLogFormat = ""
paramLogArgs = []
for p in paramsToRead:
paramLogFormat += "0x%llx "
for p in paramsToRead:
paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
cgen.stmt("fprintf(stderr, \"stream %%p: call %s %s\\n\", ioStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
cgen.endIf()
def emit_decode_parameters(typeInfo: VulkanTypeInfo, api: VulkanAPI, cgen, globalWrapped=False):
decodingParams = DecodingParameters(api)
paramsToRead = decodingParams.toRead
for p in paramsToRead:
emit_param_decl_for_reading(p, cgen)
for i, p in enumerate(paramsToRead):
lenAccess = cgen.generalLengthAccess(p)
if p.dispatchHandle:
emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
else:
destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
noUnbox = api.name in ["vkQueueFlushCommandsGOOGLE", "vkQueueFlushCommandsFromAuxMemoryGOOGLE"] and p.paramName == "commandBuffer"
if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
destroy = True
cgen.stmt("// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
if None == lenAccess or "1" == lenAccess:
cgen.stmt("%s boxed_%s_preserve" % (p.typeName, p.paramName))
else:
cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" % (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
if p.possiblyOutput():
cgen.stmt("// Begin manual dispatchable handle unboxing for %s" % p.paramName)
cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
emit_unmarshal(typeInfo, p, cgen, output = p.possiblyOutput(), destroy = destroy, noUnbox = noUnbox)
for p in paramsToRead:
emit_transform(typeInfo, p, cgen, variant="tohost")
emit_call_log(api, cgen)
def emit_dispatch_call(api, cgen):
decodingParams = DecodingParameters(api)
customParams = []
delay = api.name in DELAYED_DECODER_DELETES
for i, p in enumerate(api.parameters):
customParam = p.paramName
if decodingParams.params[i].dispatchHandle:
customParam = "unboxed_%s" % p.paramName
customParams.append(customParam)
if delay:
cgen.line("std::function<void()> delayed_remove_callback = [vk, %s]() {" % ", ".join(customParams))
if api.name in driver_workarounds_global_lock_apis:
if delay:
cgen.stmt("auto state = VkDecoderGlobalState::get()")
cgen.stmt("// state already locked")
else:
cgen.stmt("m_state->lock()")
cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams, \
globalStatePrefix=global_state_prefix, checkForDeviceLost=True,
checkForOutOfMemory=True)
if api.name in driver_workarounds_global_lock_apis:
if not delay:
cgen.stmt("m_state->unlock()")
# for delayed remove, state is already locked, so we do not need to
# unlock
if delay:
cgen.line("};")
def emit_global_state_wrapped_call(api, cgen, context):
if api.name in DELAYED_DECODER_DELETES:
print("Error: Cannot generate a global state wrapped call that is also a delayed delete (yet)");
raise
customParams = ["&m_pool"] + list(map(lambda p: p.paramName, api.parameters))
if context:
customParams += ["context"]
cgen.vkApiCall(api, customPrefix=global_state_prefix, \
customParameters=customParams, globalStatePrefix=global_state_prefix, \
checkForDeviceLost=True, checkForOutOfMemory=True)
def emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=True):
decodingParams = DecodingParameters(api)
paramsToWrite = decodingParams.toWrite
cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
handleMapOverwrites = False
for p in paramsToWrite:
emit_transform(typeInfo, p, cgen, variant="fromhost")
handleMapOverwrites = False
if p.nonDispatchableHandleCreate or p.dispatchableHandleCreate:
handleMapOverwrites = True
if autobox and p.nonDispatchableHandleCreate:
cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
cgen.stmt("if (%s == VK_SUCCESS) %s->setHandleMapping(&m_boxedHandleCreateMapping)" % \
(api.getRetVarExpr(), WRITE_STREAM))
if (not autobox) and p.nonDispatchableHandleCreate:
cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
emit_marshal(typeInfo, p, cgen, handleMapOverwrites=handleMapOverwrites)
if autobox and p.nonDispatchableHandleCreate:
cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
if (not autobox) and p.nonDispatchableHandleCreate:
cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
def emit_decode_return_writeback(api, cgen):
retTypeName = api.getRetTypeExpr()
if retTypeName != "void":
retVar = api.getRetVarExpr()
cgen.stmt("%s->write(&%s, %s)" %
(WRITE_STREAM, retVar, cgen.sizeofExpr(api.retType)))
def emit_decode_finish(api, cgen):
decodingParams = DecodingParameters(api)
retTypeName = api.getRetTypeExpr()
paramsToWrite = decodingParams.toWrite
if retTypeName != "void" or len(paramsToWrite) != 0:
cgen.stmt("%s->commitWrite()" % WRITE_STREAM)
def emit_destroyed_handle_cleanup(api, cgen):
decodingParams = DecodingParameters(api)
paramsToRead = decodingParams.toRead
skipDelete = api.name in SKIPPED_DECODER_DELETES
if skipDelete:
cgen.line("// Skipping handle cleanup for %s" % api.name)
return
for p in paramsToRead:
if p.dispatchHandle:
pass
else:
lenAccess = cgen.generalLengthAccess(p)
lenAccessGuard = cgen.generalLengthAccess(p)
destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
if destroy:
if None == lenAccess or "1" == lenAccess:
if api.name in DELAYED_DECODER_DELETES:
cgen.stmt("delayed_delete_%s(boxed_%s_preserve, unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
else:
cgen.stmt("delete_%s(boxed_%s_preserve)" % (p.typeName, p.paramName))
else:
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
if api.name in DELAYED_DECODER_DELETES:
cgen.stmt("delayed_delete_%s(boxed_%s_preserve[i], unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
else:
cgen.stmt("delete_%s(boxed_%s_preserve[i])" % (p.typeName, p.paramName))
cgen.endFor()
if lenAccessGuard is not None:
cgen.endIf()
def emit_pool_free(cgen):
cgen.stmt("%s->clearPool()" % READ_STREAM)
def emit_seqno_incr(api, cgen):
cgen.stmt("if (queueSubmitWithCommandsEnabled) seqnoPtr->fetch_add(1, std::memory_order_seq_cst)")
def emit_snapshot(typeInfo, api, cgen):
cgen.stmt("%s->setReadPos((uintptr_t)(*readStreamPtrPtr) - (uintptr_t)snapshotTraceBegin)" % READ_STREAM)
cgen.stmt("size_t snapshotTraceBytes = %s->endTrace()" % READ_STREAM)
additionalParams = [ \
makeVulkanTypeSimple(True, "uint8_t", 1, "snapshotTraceBegin"),
makeVulkanTypeSimple(False, "size_t", 0, "snapshotTraceBytes"),
makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "&m_pool"),
]
retTypeName = api.getRetTypeExpr()
if retTypeName != "void":
retVar = api.getRetVarExpr()
additionalParams.append(makeVulkanTypeSimple(False, retTypeName, 0, retVar))
paramsForSnapshot = []
decodingParams = DecodingParameters(api)
for p in decodingParams.toRead:
if p.nonDispatchableHandleDestroy or (not p.dispatchHandle and p.dispatchableHandleDestroy):
paramsForSnapshot.append(p.withModifiedName("boxed_%s_preserve" % p.paramName))
else:
paramsForSnapshot.append(p)
customParams = additionalParams + paramsForSnapshot
apiForSnapshot = \
api.withCustomReturnType(makeVulkanTypeSimple(False, "void", 0, "void")). \
withCustomParameters(customParams)
cgen.beginIf("m_state->snapshotsEnabled()")
cgen.vkApiCall(apiForSnapshot, customPrefix="m_state->snapshot()->")
cgen.endIf()
def emit_decoding(typeInfo, api, cgen, globalWrapped=False, context=False):
isAcquire = api.name in RELAXED_APIS
emit_decode_parameters(typeInfo, api, cgen, globalWrapped)
if isAcquire:
emit_seqno_incr(api, cgen)
if globalWrapped:
emit_global_state_wrapped_call(api, cgen, context)
else:
emit_dispatch_call(api, cgen)
emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=not globalWrapped)
emit_decode_return_writeback(api, cgen)
emit_decode_finish(api, cgen)
emit_snapshot(typeInfo, api, cgen)
emit_destroyed_handle_cleanup(api, cgen)
emit_pool_free(cgen)
if not isAcquire:
emit_seqno_incr(api, cgen)
def emit_default_decoding(typeInfo, api, cgen):
emit_decoding(typeInfo, api, cgen)
def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
emit_decoding(typeInfo, api, cgen, globalWrapped=True)
def emit_global_state_wrapped_decoding_with_context(typeInfo, api, cgen):
emit_decoding(typeInfo, api, cgen, globalWrapped=True, context=True)
## Custom decoding definitions##################################################
def decode_vkFlushMappedMemoryRanges(typeInfo: VulkanTypeInfo, api, cgen):
emit_decode_parameters(typeInfo, api, cgen)
cgen.beginIf("!m_state->usingDirectMapping()")
cgen.stmt("// This is to deal with a deficiency in the encoder,");
cgen.stmt("// where usingDirectMapping fails to set the proper packet size,");
cgen.stmt("// meaning we can read off the end of the packet.");
cgen.stmt("uint64_t sizeLeft = end - *readStreamPtrPtr")
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.beginIf("sizeLeft < sizeof(uint64_t)")
cgen.beginIf("m_prevSeqno")
cgen.stmt("m_prevSeqno = m_prevSeqno.value() - 1")
cgen.endIf()
cgen.stmt("return ptr - (unsigned char*)buf;")
cgen.endIf()
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = pMemoryRanges[i].memory")
cgen.stmt("auto size = pMemoryRanges[i].size")
cgen.stmt("auto offset = pMemoryRanges[i].offset")
cgen.stmt("uint64_t readStream = 0")
cgen.stmt("memcpy(&readStream, *readStreamPtrPtr, sizeof(uint64_t)); *readStreamPtrPtr += sizeof(uint64_t)")
cgen.stmt("sizeLeft -= sizeof(uint64_t)")
cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
cgen.stmt("if (!hostPtr && readStream > 0) GFXSTREAM_ABORT(::emugl::FatalError(::emugl::ABORT_REASON_OTHER))")
cgen.stmt("if (!hostPtr) continue")
cgen.beginIf("sizeLeft < readStream")
cgen.beginIf("m_prevSeqno")
cgen.stmt("m_prevSeqno = m_prevSeqno.value() - 1")
cgen.endIf()
cgen.stmt("return ptr - (unsigned char*)buf;")
cgen.endIf()
cgen.stmt("sizeLeft -= readStream")
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("memcpy(targetRange, *readStreamPtrPtr, readStream); *readStreamPtrPtr += readStream")
cgen.stmt("packetLen += 8 + readStream")
cgen.endFor()
cgen.endIf()
emit_dispatch_call(api, cgen)
emit_decode_parameters_writeback(typeInfo, api, cgen)
emit_decode_return_writeback(api, cgen)
emit_decode_finish(api, cgen)
emit_snapshot(typeInfo, api, cgen);
emit_pool_free(cgen)
emit_seqno_incr(api, cgen)
def decode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
emit_decode_parameters(typeInfo, api, cgen)
emit_dispatch_call(api, cgen)
emit_decode_parameters_writeback(typeInfo, api, cgen)
emit_decode_return_writeback(api, cgen)
cgen.beginIf("!m_state->usingDirectMapping()")
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = range.memory")
cgen.stmt("auto size = range.size")
cgen.stmt("auto offset = range.offset")
cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? m_state->getDeviceMemorySize(memory) : size")
cgen.stmt("uint64_t writeStream = 0")
cgen.stmt("if (!hostPtr) { %s->write(&writeStream, sizeof(uint64_t)); continue; }" % WRITE_STREAM)
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("writeStream = actualSize")
cgen.stmt("%s->write(&writeStream, sizeof(uint64_t))" % WRITE_STREAM)
cgen.stmt("%s->write(targetRange, actualSize)" % WRITE_STREAM)
cgen.endFor()
cgen.endIf()
emit_decode_finish(api, cgen)
emit_snapshot(typeInfo, api, cgen);
emit_pool_free(cgen)
emit_seqno_incr(api, cgen)
def decode_unsupported_api(typeInfo, api, cgen):
cgen.line(f"// Decoding {api.name} is not supported. This should not run.")
cgen.stmt(f"fprintf(stderr, \"stream %p: fatal: decoding unsupported API {api.name}\\n\", ioStream)");
cgen.stmt("__builtin_trap()")
custom_decodes = {
"vkEnumerateInstanceVersion" : emit_global_state_wrapped_decoding,
"vkCreateInstance" : emit_global_state_wrapped_decoding,
"vkDestroyInstance" : emit_global_state_wrapped_decoding,
"vkEnumeratePhysicalDevices" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFeatures" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFeatures2" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFeatures2KHR" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFormatProperties" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFormatProperties2" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceFormatProperties2KHR" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceImageFormatProperties" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceImageFormatProperties2" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceImageFormatProperties2KHR" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceProperties" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceProperties2" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceProperties2KHR" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceMemoryProperties" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceMemoryProperties2" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceMemoryProperties2KHR" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceExternalSemaphoreProperties" : emit_global_state_wrapped_decoding,
"vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : emit_global_state_wrapped_decoding,
"vkEnumerateDeviceExtensionProperties" : emit_global_state_wrapped_decoding,
"vkCreateBuffer" : emit_global_state_wrapped_decoding,
"vkDestroyBuffer" : emit_global_state_wrapped_decoding,
"vkBindBufferMemory" : emit_global_state_wrapped_decoding,
"vkBindBufferMemory2" : emit_global_state_wrapped_decoding,
"vkBindBufferMemory2KHR" : emit_global_state_wrapped_decoding,
"vkCreateDevice" : emit_global_state_wrapped_decoding,
"vkGetDeviceQueue" : emit_global_state_wrapped_decoding,
"vkDestroyDevice" : emit_global_state_wrapped_decoding,
"vkGetDeviceQueue2" : emit_global_state_wrapped_decoding,
"vkBindImageMemory" : emit_global_state_wrapped_decoding,
"vkBindImageMemory2" : emit_global_state_wrapped_decoding,
"vkBindImageMemory2KHR" : emit_global_state_wrapped_decoding,
"vkCreateImage" : emit_global_state_wrapped_decoding,
"vkCreateImageView" : emit_global_state_wrapped_decoding,
"vkCreateSampler" : emit_global_state_wrapped_decoding,
"vkDestroyImage" : emit_global_state_wrapped_decoding,
"vkDestroyImageView" : emit_global_state_wrapped_decoding,
"vkDestroySampler" : emit_global_state_wrapped_decoding,
"vkCmdCopyBufferToImage" : emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage" : emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer" : emit_global_state_wrapped_decoding,
"vkCmdCopyBufferToImage2" : emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage2" : emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer2" : emit_global_state_wrapped_decoding,
"vkGetImageMemoryRequirements" : emit_global_state_wrapped_decoding,
"vkGetImageMemoryRequirements2" : emit_global_state_wrapped_decoding,
"vkGetImageMemoryRequirements2KHR" : emit_global_state_wrapped_decoding,
"vkGetBufferMemoryRequirements" : emit_global_state_wrapped_decoding,
"vkGetBufferMemoryRequirements2": emit_global_state_wrapped_decoding,
"vkGetBufferMemoryRequirements2KHR": emit_global_state_wrapped_decoding,
"vkCreateDescriptorSetLayout" : emit_global_state_wrapped_decoding,
"vkDestroyDescriptorSetLayout" : emit_global_state_wrapped_decoding,
"vkCreateDescriptorPool" : emit_global_state_wrapped_decoding,
"vkDestroyDescriptorPool" : emit_global_state_wrapped_decoding,
"vkResetDescriptorPool" : emit_global_state_wrapped_decoding,
"vkAllocateDescriptorSets" : emit_global_state_wrapped_decoding,
"vkFreeDescriptorSets" : emit_global_state_wrapped_decoding,
"vkUpdateDescriptorSets" : emit_global_state_wrapped_decoding,
"vkCreateShaderModule": emit_global_state_wrapped_decoding,
"vkDestroyShaderModule": emit_global_state_wrapped_decoding,
"vkCreatePipelineCache": emit_global_state_wrapped_decoding,
"vkDestroyPipelineCache": emit_global_state_wrapped_decoding,
"vkCreateGraphicsPipelines": emit_global_state_wrapped_decoding,
"vkDestroyPipeline": emit_global_state_wrapped_decoding,
"vkAllocateMemory" : emit_global_state_wrapped_decoding,
"vkFreeMemory" : emit_global_state_wrapped_decoding,
"vkMapMemory" : emit_global_state_wrapped_decoding,
"vkUnmapMemory" : emit_global_state_wrapped_decoding,
"vkFlushMappedMemoryRanges" : decode_vkFlushMappedMemoryRanges,
"vkInvalidateMappedMemoryRanges" : decode_vkInvalidateMappedMemoryRanges,
"vkAllocateCommandBuffers" : emit_global_state_wrapped_decoding,
"vkCmdExecuteCommands" : emit_global_state_wrapped_decoding,
"vkQueueSubmit" : emit_global_state_wrapped_decoding,
"vkQueueSubmit2" : emit_global_state_wrapped_decoding,
"vkQueueWaitIdle" : emit_global_state_wrapped_decoding,
"vkBeginCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
"vkEndCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
"vkResetCommandBuffer" : emit_global_state_wrapped_decoding,
"vkFreeCommandBuffers" : emit_global_state_wrapped_decoding,
"vkCreateCommandPool" : emit_global_state_wrapped_decoding,
"vkDestroyCommandPool" : emit_global_state_wrapped_decoding,
"vkResetCommandPool" : emit_global_state_wrapped_decoding,
"vkCmdPipelineBarrier" : emit_global_state_wrapped_decoding,
"vkCmdBindPipeline" : emit_global_state_wrapped_decoding,
"vkCmdBindDescriptorSets" : emit_global_state_wrapped_decoding,
"vkCreateRenderPass" : emit_global_state_wrapped_decoding,
"vkCreateRenderPass2" : emit_global_state_wrapped_decoding,
"vkCreateRenderPass2KHR" : emit_global_state_wrapped_decoding,
"vkDestroyRenderPass" : emit_global_state_wrapped_decoding,
"vkCreateFramebuffer" : emit_global_state_wrapped_decoding,
"vkDestroyFramebuffer" : emit_global_state_wrapped_decoding,
"vkCreateSamplerYcbcrConversion": emit_global_state_wrapped_decoding,
"vkDestroySamplerYcbcrConversion": emit_global_state_wrapped_decoding,
# VK_ANDROID_native_buffer
"vkGetSwapchainGrallocUsageANDROID" : emit_global_state_wrapped_decoding,
"vkGetSwapchainGrallocUsage2ANDROID" : emit_global_state_wrapped_decoding,
"vkAcquireImageANDROID" : emit_global_state_wrapped_decoding,
"vkQueueSignalReleaseImageANDROID" : emit_global_state_wrapped_decoding,
"vkCreateSemaphore" : emit_global_state_wrapped_decoding,
"vkGetSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
"vkImportSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
"vkDestroySemaphore" : emit_global_state_wrapped_decoding,
"vkCreateFence" : emit_global_state_wrapped_decoding,
"vkResetFences" : emit_global_state_wrapped_decoding,
"vkDestroyFence" : emit_global_state_wrapped_decoding,
# VK_GOOGLE_gfxstream
"vkFreeMemorySyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkMapMemoryIntoAddressSpaceGOOGLE" : emit_global_state_wrapped_decoding,
"vkGetMemoryHostAddressInfoGOOGLE" : emit_global_state_wrapped_decoding,
"vkGetBlobGOOGLE" : emit_global_state_wrapped_decoding,
# Descriptor update templates
"vkCreateDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
"vkCreateDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
"vkDestroyDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
"vkDestroyDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
"vkUpdateDescriptorSetWithTemplateSizedGOOGLE" : emit_global_state_wrapped_decoding,
"vkUpdateDescriptorSetWithTemplateSized2GOOGLE" : emit_global_state_wrapped_decoding,
# VK_GOOGLE_gfxstream
"vkBeginCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
"vkEndCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
"vkResetCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkCommandBufferHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkCreateImageWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
"vkCreateBufferWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueSubmitAsyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueSubmitAsync2GOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueWaitIdleAsyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueBindSparseAsyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkGetLinearImageLayoutGOOGLE" : emit_global_state_wrapped_decoding,
"vkGetLinearImageLayout2GOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueFlushCommandsGOOGLE" : emit_global_state_wrapped_decoding_with_context,
"vkQueueFlushCommandsFromAuxMemoryGOOGLE" : emit_global_state_wrapped_decoding_with_context,
"vkQueueCommitDescriptorSetUpdatesGOOGLE" : emit_global_state_wrapped_decoding,
"vkCollectDescriptorPoolIdsGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueSignalReleaseImageANDROIDAsyncGOOGLE" : emit_global_state_wrapped_decoding,
"vkQueueBindSparse" : emit_global_state_wrapped_decoding,
# VK_KHR_xcb_surface
"vkCreateXcbSurfaceKHR": decode_unsupported_api,
"vkGetPhysicalDeviceXcbPresentationSupportKHR": decode_unsupported_api,
# VK_EXT_metal_surface
"vkCreateMetalSurfaceEXT": decode_unsupported_api,
# VK_KHR_sampler_ycbcr_conversion
"vkCreateSamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
"vkDestroySamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
#VK_KHR_copy_commands2
"vkCmdCopyBufferToImage2KHR" : emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage2KHR" : emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer2KHR" : emit_global_state_wrapped_decoding,
}
class VulkanDecoder(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo: VulkanTypeInfo = typeInfo
self.cgen = CodeGen()
def onBegin(self,):
self.module.appendImpl(
"#define MAX_PACKET_LENGTH %s\n" % MAX_PACKET_LENGTH)
self.module.appendHeader(decoder_decl_preamble)
self.module.appendImpl(decoder_impl_preamble)
self.module.appendImpl(
"""
size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream,
const ProcessResources* processResources,
const VkDecoderContext& context)
""")
self.cgen.beginBlock() # function body
self.cgen.stmt("const char* processName = context.processName")
self.cgen.stmt("auto& gfx_logger = *context.gfxApiLogger")
self.cgen.stmt("auto* healthMonitor = context.healthMonitor")
self.cgen.stmt("auto& metricsLogger = *context.metricsLogger")
self.cgen.stmt("if (len < 8) return 0")
self.cgen.stmt("bool queueSubmitWithCommandsEnabled = feature_is_enabled(kFeature_VulkanQueueSubmitWithCommands)")
self.cgen.stmt("unsigned char *ptr = (unsigned char *)buf")
self.cgen.stmt("const unsigned char* const end = (const unsigned char*)buf + len")
self.cgen.beginIf("m_forSnapshotLoad")
self.cgen.stmt("ptr += m_state->setCreatedHandlesForSnapshotLoad(ptr)");
self.cgen.endIf()
self.cgen.line("while (end - ptr >= 8)")
self.cgen.beginBlock() # while loop
self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
self.cgen.stmt("uint32_t packetLen = *(uint32_t *)(ptr + 4)")
self.cgen.line("""
// packetLen should be at least 8 (op code and packet length) and should not be excessively large
if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
WARN("Bad packet length %d detected, decode may fail", packetLen);
metricsLogger.logMetricEvent(MetricEventBadPacketLength{ .len = packetLen });
}
""")
self.cgen.stmt("if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
self.cgen.stmt("gfx_logger.record(ptr, std::min(size_t(packetLen + 8), size_t(end - ptr)))")
self.cgen.stmt("stream()->setStream(ioStream)")
self.cgen.stmt("VulkanStream* %s = stream()" % WRITE_STREAM)
self.cgen.stmt("VulkanMemReadingStream* %s = readStream()" % READ_STREAM)
self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
self.cgen.stmt("uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
self.cgen.stmt("uint8_t* snapshotTraceBegin = %s->beginTrace()" % READ_STREAM)
self.cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % READ_STREAM)
self.cgen.line("""
std::unique_ptr<EventHangMetadata::HangAnnotations> executionData =
std::make_unique<EventHangMetadata::HangAnnotations>();
if (healthMonitor) {
executionData->insert(
{{"packet_length", std::to_string(packetLen)},
{"opcode", std::to_string(opcode)}});
if (processName) {
executionData->insert(
{{"renderthread_guest_process", std::string(processName)}});
}
if (m_prevSeqno) {
executionData->insert({{"previous_seqno", std::to_string(m_prevSeqno.value())}});
}
}
std::atomic<uint32_t>* seqnoPtr = processResources ?
processResources->getSequenceNumberPtr() : nullptr;
if (queueSubmitWithCommandsEnabled && ((opcode >= OP_vkFirst && opcode < OP_vkLast) || (opcode >= OP_vkFirst_old && opcode < OP_vkLast_old))) {
uint32_t seqno;
memcpy(&seqno, *readStreamPtrPtr, sizeof(uint32_t)); *readStreamPtrPtr += sizeof(uint32_t);
if (healthMonitor) executionData->insert({{"seqno", std::to_string(seqno)}});
if (m_prevSeqno && seqno == m_prevSeqno.value()) {
WARN(
"Seqno %d is the same as previously processed on thread %d. It might be a "
"duplicate command.",
seqno, getCurrentThreadId());
metricsLogger.logMetricEvent(MetricEventDuplicateSequenceNum{ .opcode = opcode });
}
if (seqnoPtr && !m_forSnapshotLoad) {
{
auto seqnoWatchdog =
WATCHDOG_BUILDER(healthMonitor,
"RenderThread seqno loop")
.setHangType(EventHangMetadata::HangType::kRenderThread)
.setAnnotations(std::make_unique<EventHangMetadata::HangAnnotations>(*executionData))
/* Data gathered if this hangs*/
.setOnHangCallback([=]() {
auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
annotations->insert({{"seqnoPtr", std::to_string(seqnoPtr->load(std::memory_order_seq_cst))}});
return annotations;
})
.build();
while ((seqno - seqnoPtr->load(std::memory_order_seq_cst) != 1)) {
#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
_mm_pause();
#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
__asm__ __volatile__("pause;");
#endif
}
m_prevSeqno = seqno;
}
}
}
""")
self.cgen.line("""
gfx_logger.recordCommandExecution();
""")
self.cgen.line("""
auto executionWatchdog =
WATCHDOG_BUILDER(healthMonitor, "RenderThread VkDecoder command execution")
.setHangType(EventHangMetadata::HangType::kRenderThread)
.setAnnotations(std::move(executionData))
.build();
""")
self.cgen.stmt("auto vk = m_vk")
self.cgen.line("switch (opcode)")
self.cgen.beginBlock() # switch stmt
self.module.appendImpl(self.cgen.swapCode())
def onGenCmd(self, cmdinfo, name, alias):
typeInfo = self.typeInfo
cgen = self.cgen
api: VulkanAPI = typeInfo.apis[name]
cgen.line("case OP_%s:" % name)
cgen.beginBlock()
cgen.stmt("android::base::beginTrace(\"%s decode\")" % name)
if api.name in custom_decodes.keys():
custom_decodes[api.name](typeInfo, api, cgen)
else:
emit_default_decoding(typeInfo, api, cgen)
cgen.stmt("android::base::endTrace()")
cgen.stmt("break")
cgen.endBlock()
self.module.appendImpl(self.cgen.swapCode())
def onEnd(self,):
self.cgen.line("default:")
self.cgen.beginBlock()
self.cgen.stmt("m_pool.freeAll()")
self.cgen.stmt("return ptr - (unsigned char *)buf")
self.cgen.endBlock()
self.cgen.endBlock() # switch stmt
self.cgen.stmt("ptr += packetLen")
self.cgen.endBlock() # while loop
self.cgen.beginIf("m_forSnapshotLoad")
self.cgen.stmt("m_state->clearCreatedHandlesForSnapshotLoad()");
self.cgen.endIf()
self.cgen.stmt("m_pool.freeAll()")
self.cgen.stmt("return ptr - (unsigned char*)buf;")
self.cgen.endBlock() # function body
self.module.appendImpl(self.cgen.swapCode())
self.module.appendImpl(decoder_impl_postamble)

View file

@ -0,0 +1,267 @@
from .common.codegen import CodeGen, VulkanWrapperGenerator, VulkanAPIWrapper
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, DISPATCHABLE_HANDLE_TYPES, NON_DISPATCHABLE_HANDLE_TYPES
from .transform import TransformCodegen, genTransformsForVulkanType
from .wrapperdefs import API_PREFIX_MARSHAL
from .wrapperdefs import API_PREFIX_UNMARSHAL
from .wrapperdefs import VULKAN_STREAM_TYPE
from copy import copy
decoder_snapshot_decl_preamble = """
namespace android {
namespace base {
class BumpPool;
class Stream;
} // namespace base {
} // namespace android {
class VkDecoderSnapshot {
public:
VkDecoderSnapshot();
~VkDecoderSnapshot();
void save(android::base::Stream* stream);
void load(android::base::Stream* stream, emugl::GfxApiLogger& gfx_logger,
emugl::HealthMonitor<>* healthMonitor);
"""
decoder_snapshot_decl_postamble = """
private:
class Impl;
std::unique_ptr<Impl> mImpl;
};
"""
decoder_snapshot_impl_preamble ="""
using namespace gfxstream::vk;
using emugl::GfxApiLogger;
using emugl::HealthMonitor;
class VkDecoderSnapshot::Impl {
public:
Impl() { }
void save(android::base::Stream* stream) {
mReconstruction.save(stream);
}
void load(android::base::Stream* stream, GfxApiLogger& gfx_logger,
HealthMonitor<>* healthMonitor) {
mReconstruction.load(stream, gfx_logger, healthMonitor);
}
"""
decoder_snapshot_impl_postamble = """
private:
android::base::Lock mLock;
VkReconstruction mReconstruction;
};
VkDecoderSnapshot::VkDecoderSnapshot() :
mImpl(new VkDecoderSnapshot::Impl()) { }
void VkDecoderSnapshot::save(android::base::Stream* stream) {
mImpl->save(stream);
}
void VkDecoderSnapshot::load(android::base::Stream* stream, GfxApiLogger& gfx_logger,
HealthMonitor<>* healthMonitor) {
mImpl->load(stream, gfx_logger, healthMonitor);
}
VkDecoderSnapshot::~VkDecoderSnapshot() = default;
"""
AUXILIARY_SNAPSHOT_API_BASE_PARAM_COUNT = 3
AUXILIARY_SNAPSHOT_API_PARAM_NAMES = [
"input_result",
]
# Vulkan handle dependencies.
# (a, b): a depends on b
SNAPSHOT_HANDLE_DEPENDENCIES = [
# Dispatchable handle types
("VkCommandBuffer", "VkCommandPool"),
("VkCommandPool", "VkDevice"),
("VkQueue", "VkDevice"),
("VkDevice", "VkPhysicalDevice"),
("VkPhysicalDevice", "VkInstance")] + \
list(map(lambda handleType : (handleType, "VkDevice"), NON_DISPATCHABLE_HANDLE_TYPES))
handleDependenciesDict = dict(SNAPSHOT_HANDLE_DEPENDENCIES)
def extract_deps_vkAllocateCommandBuffers(param, access, lenExpr, api, cgen):
cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
(access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkCommandPool(pAllocateInfo->commandPool)"))
specialCaseDependencyExtractors = {
"vkAllocateCommandBuffers" : extract_deps_vkAllocateCommandBuffers,
}
apiSequences = {
"vkAllocateMemory" : ["vkAllocateMemory", "vkMapMemoryIntoAddressSpaceGOOGLE"]
}
apiModifies = {
"vkMapMemoryIntoAddressSpaceGOOGLE" : ["memory"],
}
def is_modify_operation(api, param):
if api.name in apiModifies:
if param.paramName in apiModifies[api.name]:
return True
return False
def emit_impl(typeInfo, api, cgen):
cgen.line("// TODO: Implement")
for p in api.parameters:
if not (p.isHandleType):
continue
lenExpr = cgen.generalLengthAccess(p)
lenAccessGuard = cgen.generalLengthAccessGuard(p)
if lenExpr is None:
lenExpr = "1"
if p.pointerIndirectionLevels > 0:
access = p.paramName
else:
access = "(&%s)" % p.paramName
if p.isCreatedBy(api):
cgen.stmt("android::base::AutoLock lock(mLock)")
cgen.line("// %s create" % p.paramName)
cgen.stmt("mReconstruction.addHandles((const uint64_t*)%s, %s)" % (access, lenExpr));
if p.typeName in handleDependenciesDict:
dependsOnType = handleDependenciesDict[p.typeName];
for p2 in api.parameters:
if p2.typeName == dependsOnType:
cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % (access, lenExpr, p2.paramName))
if api.name in specialCaseDependencyExtractors:
specialCaseDependencyExtractors[api.name](p, access, lenExpr, api, cgen)
cgen.stmt("if (!%s) return" % access)
cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
cgen.stmt("mReconstruction.setApiTrace(apiInfo, OP_%s, snapshotTraceBegin, snapshotTraceBytes)" % api.name)
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.stmt("mReconstruction.forEachHandleAddApi((const uint64_t*)%s, %s, apiHandle)" % (access, lenExpr))
cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiHandle, (const uint64_t*)%s, %s)" % (access, lenExpr))
if lenAccessGuard is not None:
cgen.endIf()
if p.isDestroyedBy(api):
cgen.stmt("android::base::AutoLock lock(mLock)")
cgen.line("// %s destroy" % p.paramName)
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.stmt("mReconstruction.removeHandles((const uint64_t*)%s, %s)" % (access, lenExpr));
if lenAccessGuard is not None:
cgen.endIf()
if is_modify_operation(api, p):
cgen.stmt("android::base::AutoLock lock(mLock)")
cgen.line("// %s modify" % p.paramName)
cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
cgen.stmt("mReconstruction.setApiTrace(apiInfo, OP_%s, snapshotTraceBegin, snapshotTraceBytes)" % api.name)
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.beginFor("uint32_t i = 0", "i < %s" % lenExpr, "++i")
if p.isNonDispatchableHandleType():
cgen.stmt("%s boxed = unboxed_to_boxed_non_dispatchable_%s(%s[i])" % (p.typeName, p.typeName, access))
else:
cgen.stmt("%s boxed = unboxed_to_boxed_%s(%s[i])" % (p.typeName, p.typeName, access))
cgen.stmt("mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiHandle)")
cgen.endFor()
if lenAccessGuard is not None:
cgen.endIf()
def emit_passthrough_to_impl(typeInfo, api, cgen):
cgen.vkApiCall(api, customPrefix = "mImpl->")
class VulkanDecoderSnapshot(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
self.cgenHeader = CodeGen()
self.cgenHeader.incrIndent()
self.cgenImpl = CodeGen()
self.currentFeature = None
self.feature_apis = []
def onBegin(self,):
self.module.appendHeader(decoder_snapshot_decl_preamble)
self.module.appendImpl(decoder_snapshot_impl_preamble)
def onBeginFeature(self, featureName, featureType):
VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType)
self.currentFeature = featureName
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
api = self.typeInfo.apis[name]
additionalParams = [ \
makeVulkanTypeSimple(True, "uint8_t", 1, "snapshotTraceBegin"),
makeVulkanTypeSimple(False, "size_t", 0, "snapshotTraceBytes"),
makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "pool"),]
if api.retType.typeName != "void":
additionalParams.append( \
makeVulkanTypeSimple(False, api.retType.typeName, 0, "input_result"))
apiForSnapshot = \
api.withCustomParameters( \
additionalParams + \
api.parameters).withCustomReturnType( \
makeVulkanTypeSimple(False, "void", 0, "void"))
self.feature_apis.append((self.currentFeature, apiForSnapshot))
self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(apiForSnapshot))
self.module.appendHeader(self.cgenHeader.swapCode())
self.cgenImpl.emitFuncImpl( \
apiForSnapshot, lambda cgen: emit_impl(self.typeInfo, apiForSnapshot, cgen))
self.module.appendImpl(self.cgenImpl.swapCode())
def onEnd(self,):
self.module.appendHeader(decoder_snapshot_decl_postamble)
self.module.appendImpl(decoder_snapshot_impl_postamble)
self.cgenHeader.decrIndent()
for feature, api in self.feature_apis:
if feature is not None:
self.cgenImpl.line("#ifdef %s" % feature)
apiImplShell = \
api.withModifiedName("VkDecoderSnapshot::" + api.name)
self.cgenImpl.emitFuncImpl( \
apiImplShell, lambda cgen: emit_passthrough_to_impl(self.typeInfo, api, cgen))
if feature is not None:
self.cgenImpl.line("#endif")
self.module.appendImpl(self.cgenImpl.swapCode())

View file

@ -0,0 +1,383 @@
# 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<const vk_struct_common*>(%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)))

View file

@ -0,0 +1,501 @@
# 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
from .wrapperdefs import VulkanWrapperGenerator
# No real good way to automatically infer the most important Vulkan API
# functions as it relates to which getProcAddress function to use, plus
# we might want to control which function to use depending on our
# performance needs.
# This is based on the minimum set of functions needed to be directly
# queried with dlsym and not returning null.
getProcAddrFuncs = [
"vkGetInstanceProcAddr",
"vkDestroyInstance",
"vkEnumeratePhysicalDevices",
"vkGetPhysicalDeviceFeatures",
"vkGetPhysicalDeviceFormatProperties",
"vkGetPhysicalDeviceImageFormatProperties",
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceQueueFamilyProperties",
"vkGetPhysicalDeviceMemoryProperties",
"vkCreateDevice",
"vkDestroyDevice",
"vkEnumerateDeviceExtensionProperties",
"vkEnumerateDeviceLayerProperties",
]
# Some methods can only be found using dlsym() while we cannot get the function
# address using vkGetInstProcAddr() or vkGetDeviceProcAddr(). These function
# pointers should only be initialized when setting up the dispatch from system
# loader.
getProcAddrOnlyFuncs = [
"vkGetMTLDeviceMVK",
"vkSetMTLTextureMVK",
"vkGetMTLTextureMVK",
"vkGetMTLBufferMVK",
"vkUseIOSurfaceMVK",
"vkGetIOSurfaceMVK",
]
getInstanceProcAddrNoInstanceFuncs = [
"vkCreateInstance",
"vkEnumerateInstanceExtensionProperties",
"vkEnumerateInstanceLayerProperties",
]
getInstanceProcAddrFuncs = [
"vkGetDeviceProcAddr",
"vkCreateSwapchainKHR",
"vkDestroySwapchainKHR",
"vkGetSwapchainImagesKHR",
"vkAcquireNextImageKHR",
"vkQueuePresentKHR",
"vkCreateMacOSSurfaceMVK",
"vkCreateWin32SurfaceKHR",
"vkGetPhysicalDeviceWin32PresentationSupportKHR",
"vkCreateXlibSurfaceKHR",
"vkGetPhysicalDeviceXlibPresentationSupportKHR",
"vkCreateXcbSurfaceKHR",
"vkGetPhysicalDeviceXcbPresentationSupportKHR",
"vkGetPhysicalDeviceSparseImageFormatProperties",
"vkEnumerateInstanceVersion",
"vkEnumeratePhysicalDeviceGroups",
"vkGetPhysicalDeviceFeatures2",
"vkGetPhysicalDeviceProperties2",
"vkGetPhysicalDeviceFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceQueueFamilyProperties2",
"vkGetPhysicalDeviceMemoryProperties2",
"vkGetPhysicalDeviceSparseImageFormatProperties2",
"vkGetPhysicalDeviceExternalBufferProperties",
"vkGetPhysicalDeviceExternalFenceProperties",
"vkGetPhysicalDeviceExternalSemaphoreProperties",
]
# Implicitly, everything else is going to be obtained
# with vkGetDeviceProcAddr,
# unless it has instance in the arg.
def isGetProcAddressAPI(vulkanApi):
return vulkanApi.name in getProcAddrFuncs
def isGetProcAddressOnlyAPI(vulkanApi):
return vulkanApi.name in getProcAddrOnlyFuncs
def isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
return vulkanApi.name in getInstanceProcAddrNoInstanceFuncs
def isGetInstanceProcAddressAPI(vulkanApi):
if vulkanApi.name in getInstanceProcAddrFuncs:
return True
if vulkanApi.parameters[0].typeName == "VkInstance":
return True
return False
def isGetDeviceProcAddressAPI(vulkanApi):
if isGetProcAddressAPI(vulkanApi):
return False
if isGetProcAddressOnlyAPI(vulkanApi):
return False
if isGetInstanceProcAddressAPI(vulkanApi):
return False
return True
def inferProcAddressFuncType(vulkanApi):
if isGetProcAddressAPI(vulkanApi):
return "global"
if isGetProcAddressOnlyAPI(vulkanApi):
return "global-only"
if isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
return "global-instance"
if isGetInstanceProcAddressAPI(vulkanApi):
return "instance"
return "device"
# VulkanDispatch defines a struct, VulkanDispatch,
# that is populated by function pointers from the Vulkan
# loader. No attempt is made to do something different
# for instance vs device functions.
class VulkanDispatch(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.apisToGet = {}
self.cgenHeader = CodeGen()
self.cgenImpl = CodeGen()
self.typeInfo = typeInfo
self.currentFeature = ""
self.featureForCodegen = ""
def onBegin(self):
# The first way is to use just the loader to get symbols. This doesn't
# necessarily work with extensions because at that point the dispatch
# table needs to be specific to a particular Vulkan instance or device.
self.cgenHeader.line("""
void init_vulkan_dispatch_from_system_loader(
DlOpenFunc dlOpenFunc,
DlSymFunc dlSymFunc,
VulkanDispatch* dispatch_out);
""")
# The second way is to initialize the table from a given Vulkan
# instance or device. Provided the instance or device was created with
# the right extensions, we can obtain function pointers to extension
# functions this way.
self.cgenHeader.line("""
void init_vulkan_dispatch_from_instance(
VulkanDispatch* vk,
VkInstance instance,
VulkanDispatch* dispatch_out);
""")
self.cgenHeader.line("""
void init_vulkan_dispatch_from_device(
VulkanDispatch* vk,
VkDevice device,
VulkanDispatch* dispatch_out);
""")
# After populating a VulkanDispatch with the above methods,
# it can be useful to check whether the Vulkan 1.0 or 1.1 methods
# are all there.
def emit_feature_check_decl(cgen, tag, featureToCheck):
cgen.line("""
bool vulkan_dispatch_check_%s_%s(
const VulkanDispatch* vk);
""" % (tag, featureToCheck))
emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_0")
emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_1")
emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_0")
emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_1")
self.cgenHeader.line("struct VulkanDispatch {")
self.module.appendHeader(self.cgenHeader.swapCode())
def syncFeatureQuiet(self, cgen, feature):
if self.featureForCodegen != feature:
if feature == "":
self.featureForCodegen = feature
return
self.featureForCodegen = feature
def syncFeature(self, cgen, feature):
if self.featureForCodegen != feature:
if feature == "":
cgen.leftline("#endif")
self.featureForCodegen = feature
return
if self.featureForCodegen != "":
cgen.leftline("#endif")
cgen.leftline("#ifdef %s" % feature)
self.featureForCodegen = feature
def makeDlsymCall(self, cgen, apiname, typedecl):
cgen.stmt( \
"out->%s = (%s)dlSymFunc(lib, \"%s\")" % \
(apiname, typedecl, apiname))
def makeGetInstanceProcAddrCall(self, cgen, dispatch, instance, apiname, typedecl):
cgen.stmt( \
"out->%s = (%s)%s->vkGetInstanceProcAddr(%s, \"%s\")" % \
(apiname, typedecl, dispatch, instance, apiname))
def makeGetDeviceProcAddrCall(self, cgen, dispatch, device, apiname, typedecl):
cgen.stmt( \
"out->%s = (%s)%s->vkGetDeviceProcAddr(%s, \"%s\")" % \
(apiname, typedecl, dispatch, device, apiname))
def onEnd(self):
self.cgenHeader.line("};")
self.module.appendHeader(self.cgenHeader.swapCode())
# Getting dispatch tables from the loader
self.cgenImpl.line("""
void init_vulkan_dispatch_from_system_loader(
DlOpenFunc dlOpenFunc,
DlSymFunc dlSymFunc,
VulkanDispatch* out)""")
self.cgenImpl.beginBlock()
self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
self.cgenImpl.stmt("void* lib = dlOpenFunc()")
self.cgenImpl.stmt("if (!lib) return")
apis = \
self.apisToGet["global"] + \
self.apisToGet["global-instance"] + \
self.apisToGet["instance"] + \
self.apisToGet["device"]
if "global-only" in self.apisToGet:
apis = apis + self.apisToGet["global-only"]
for vulkanApi, typeDecl, feature in apis:
self.syncFeature(self.cgenImpl, feature)
self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.endBlock()
# Getting instance dispatch tables
self.cgenImpl.line("""
void init_vulkan_dispatch_from_instance(
VulkanDispatch* vk,
VkInstance instance,
VulkanDispatch* out)""")
self.cgenImpl.beginBlock()
self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
apis = \
self.apisToGet["global"] + \
self.apisToGet["global-instance"] + \
self.apisToGet["instance"] + \
self.apisToGet["device"]
for vulkanApi, typeDecl, feature in apis:
self.syncFeature(self.cgenImpl, feature)
self.makeGetInstanceProcAddrCall(
self.cgenImpl, "vk", "instance", vulkanApi.name, typeDecl)
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.endBlock()
# Getting device dispatch tables
self.cgenImpl.line("""
void init_vulkan_dispatch_from_device(
VulkanDispatch* vk,
VkDevice device,
VulkanDispatch* out)""")
self.cgenImpl.beginBlock()
self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
apis = \
self.apisToGet["global"] + \
self.apisToGet["global-instance"] + \
self.apisToGet["instance"] + \
self.apisToGet["device"]
for vulkanApi, typeDecl, feature in apis:
self.syncFeature(self.cgenImpl, feature)
self.makeGetDeviceProcAddrCall(
self.cgenImpl, "vk", "device", vulkanApi.name, typeDecl)
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.endBlock()
# Check Vulkan 1.0 / 1.1 functions
def emit_check_impl(cgen, dispatchVar, feature, featureToCheck, apiName):
if feature == featureToCheck:
cgen.beginIf("!%s->%s" % (dispatchVar, apiName))
cgen.stmt("fprintf(stderr, \"%s check failed: %s not found\\n\")" % (featureToCheck, apiName))
cgen.stmt("good = false")
cgen.endIf()
def emit_feature_check_impl(context, cgen, tag, featureToCheck, apis):
cgen.line("""
bool vulkan_dispatch_check_%s_%s(
const VulkanDispatch* vk)
""" % (tag, featureToCheck))
cgen.beginBlock()
cgen.stmt("bool good = true")
for vulkanApi, typeDecl, feature in apis:
context.syncFeatureQuiet(self.cgenImpl, feature)
emit_check_impl(cgen, "vk", feature, featureToCheck, vulkanApi.name)
context.syncFeatureQuiet(self.cgenImpl, "")
cgen.stmt("return good")
cgen.endBlock()
instanceApis = self.apisToGet["global-instance"] + self.apisToGet["instance"]
emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_0", instanceApis)
emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_1", instanceApis)
emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_0", self.apisToGet["device"])
emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_1", self.apisToGet["device"])
self.module.appendImpl(self.cgenImpl.swapCode())
def onBeginFeature(self, featureName, featureType):
self.currentFeature = featureName
def onGenType(self, typeXml, name, alias):
VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
vulkanApi = self.typeInfo.apis[name]
typeDecl = "PFN_%s" % name
procAddressType = inferProcAddressFuncType(vulkanApi)
self.cgenHeader.stmt("%s %s" % (typeDecl, name));
self.module.appendHeader(self.cgenHeader.swapCode())
current = self.apisToGet.get(procAddressType, [])
if current == []:
self.apisToGet[procAddressType] = current
current.append((vulkanApi, typeDecl, self.currentFeature))
# VulkanDispatchFast allows one to get the optimal function pointers
# for a given Vulkan API call, in order to improve performance.
#
# We can optionally query VkDevices to get function pointers that are
# closer to the ICD and have fewer levels of indirection from the loader
# to get there.
# See
# https://github.com/KhronosGroup/Vulkan-Loader/blob/master/loader/LoaderAndLayerInterface.md
# for more info.
#
# This requires the calling C++ code to provide functions to
# generate the desired instances and devices, otherwise we won't know
# which instance or device to pass to vkGet(Instance|Device)ProcAddr,
# so it does push more complexity to the user.
class VulkanDispatchFast(VulkanDispatch):
def __init__(self, module, typeInfo):
VulkanDispatch.__init__(self, module, typeInfo)
def onBegin(self):
self.cgenHeader.line("""
void init_vulkan_dispatch_from_system_loader(
DlOpenFunc dlOpenFunc,
DlSymFunc dlSymFunc,
InstanceGetter instanceGetter,
DeviceGetter deviceGetter,
VulkanDispatch* dispatch_out);
""")
self.cgenHeader.line("struct VulkanDispatch {")
self.cgenHeader.line("VkInstance instance;")
self.cgenHeader.line("VkPhysicalDevice physicalDevice;")
self.cgenHeader.line("uint32_t physicalDeviceQueueFamilyInfoCount;")
self.cgenHeader.line("VkQueueFamilyProperties* physicalDeviceQueueFamilyInfos;")
self.cgenHeader.line("VkDevice device;")
self.cgenHeader.line("bool presentCapable;")
self.module.appendHeader(self.cgenHeader.swapCode())
def makeGetProcAddr(self, cgen, dispatchLevel, dispatch, apiname, typedecl):
if dispatchLevel == "instance":
funcname = "vkGetInstanceProcAddr"
elif dispatchLevel == "device":
funcname = "vkGetDeviceProcAddr"
else:
raise
cgen.stmt( \
"out->%s = (%s)out->%s(%s, \"%s\")" % \
(apiname, typedecl, funcname, dispatch, apiname))
def onEnd(self):
self.cgenHeader.line("};")
self.module.appendHeader(self.cgenHeader.swapCode())
self.cgenImpl.line("""
void init_vulkan_dispatch_from_system_loader(
DlOpenFunc dlOpenFunc,
DlSymFunc dlSymFunc,
InstanceGetter instanceGetter,
DeviceGetter deviceGetter,
VulkanDispatch* out)""")
self.cgenImpl.beginBlock()
self.cgenImpl.stmt("out->instance = nullptr")
self.cgenImpl.stmt("out->physicalDevice = nullptr")
self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfoCount = 0")
self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = nullptr")
self.cgenImpl.stmt("out->device = nullptr")
self.cgenImpl.stmt("out->presentCapable = false")
self.cgenImpl.stmt("void* lib = dlOpenFunc()")
self.cgenImpl.stmt("if (!lib) return")
for vulkanApi, typeDecl, feature in self.apisToGet["global"]:
self.syncFeature(self.cgenImpl, feature)
self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.stmt("if (!out->vkGetInstanceProcAddr) return")
for vulkanApi, typeDecl, feature in self.apisToGet["global-instance"]:
self.syncFeature(self.cgenImpl, feature)
self.makeGetProcAddr( \
self.cgenImpl, "instance", "nullptr", vulkanApi.name, typeDecl);
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.stmt("if (!instanceGetter(out, &out->instance)) return")
for vulkanApi, typeDecl, feature in self.apisToGet["instance"]:
self.syncFeature(self.cgenImpl, feature)
self.makeGetProcAddr( \
self.cgenImpl, "instance", "out->instance", vulkanApi.name, typeDecl);
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, nullptr, &out->device, &out->presentCapable)) return")
self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = (VkQueueFamilyProperties*)malloc(out->physicalDeviceQueueFamilyInfoCount * sizeof(VkQueueFamilyProperties))");
self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, out->physicalDeviceQueueFamilyInfos, &out->device, &out->presentCapable)) return")
for vulkanApi, typeDecl, feature in self.apisToGet["device"]:
self.syncFeature(self.cgenImpl, feature)
self.makeGetProcAddr( \
self.cgenImpl, "device", "out->device", vulkanApi.name, typeDecl);
self.syncFeature(self.cgenImpl, "")
self.cgenImpl.endBlock()
self.module.appendImpl(self.cgenImpl.swapCode())
def onBeginFeature(self, featureName, featureType):
VulkanDispatch.onBeginFeature(self, featureName, featureType);
def onGenType(self, typeXml, name, alias):
VulkanDispatch.onGenType(self, typeXml, name, alias);
def onGenCmd(self, cmdinfo, name, alias):
VulkanDispatch.onGenCmd(self, cmdinfo, name, alias);

View file

@ -0,0 +1,723 @@
import copy
from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
from .marshaling import VulkanMarshalingCodegen
from .reservedmarshaling import VulkanReservedMarshalingCodegen
from .counting import VulkanCountingCodegen
from .handlemap import HandleMapCodegen
from .deepcopy import DeepcopyCodegen
from .transform import TransformCodegen, genTransformsForVulkanType
from .wrapperdefs import API_PREFIX_RESERVEDMARSHAL
from .wrapperdefs import API_PREFIX_MARSHAL
from .wrapperdefs import API_PREFIX_UNMARSHAL
from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
from .wrapperdefs import VULKAN_STREAM_TYPE_GUEST
encoder_decl_preamble = """
class VkEncoder {
public:
VkEncoder(gfxstream::guest::IOStream* stream, gfxstream::guest::HealthMonitor<>* healthMonitor = nullptr);
~VkEncoder();
#include "VkEncoder.h.inl"
"""
encoder_decl_postamble = """
private:
class Impl;
std::unique_ptr<Impl> mImpl;
gfxstream::guest::HealthMonitor<>* mHealthMonitor;
};
"""
encoder_impl_preamble ="""
using namespace gfxstream::vk;
using gfxstream::guest::AutoLock;
using gfxstream::guest::Lock;
using gfxstream::guest::BumpPool;
#include "VkEncoder.cpp.inl"
#define VALIDATE_RET(retType, success, validate) \\
retType goldfish_vk_validateResult = validate; \\
if (goldfish_vk_validateResult != success) return goldfish_vk_validateResult; \\
#define VALIDATE_VOID(validate) \\
VkResult goldfish_vk_validateResult = validate; \\
if (goldfish_vk_validateResult != VK_SUCCESS) return; \\
"""
STREAM = "stream"
RESOURCES = "sResourceTracker"
POOL = "pool"
ENCODER_PREVALIDATED_APIS = [
"vkFlushMappedMemoryRanges",
"vkInvalidateMappedMemoryRanges",
]
ENCODER_CUSTOM_RESOURCE_PREPROCESS = [
"vkMapMemoryIntoAddressSpaceGOOGLE",
"vkDestroyDevice",
]
ENCODER_CUSTOM_RESOURCE_POSTPROCESS = [
"vkCreateInstance",
"vkCreateDevice",
"vkMapMemoryIntoAddressSpaceGOOGLE",
"vkGetPhysicalDeviceFeatures2",
"vkGetPhysicalDeviceFeatures2KHR",
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceProperties2",
"vkGetPhysicalDeviceProperties2KHR",
"vkCreateDescriptorUpdateTemplate",
"vkCreateDescriptorUpdateTemplateKHR",
"vkGetPhysicalDeviceExternalSemaphoreProperties",
"vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
"vkGetDeviceQueue",
"vkGetDeviceQueue2",
]
ENCODER_EXPLICIT_FLUSHED_APIS = [
"vkEndCommandBufferAsyncGOOGLE",
"vkQueueSubmitAsyncGOOGLE",
"vkQueueBindSparseAsyncGOOGLE",
"vkQueueWaitIdleAsyncGOOGLE",
"vkQueueSignalReleaseImageANDROID",
"vkDestroyDevice",
]
SUCCESS_RET_TYPES = {
"VkResult" : "VK_SUCCESS",
"void" : None,
# TODO: Put up success results for other return types here.
}
ENCODER_THIS_PARAM = makeVulkanTypeSimple(False, "VkEncoder", 1, "this")
# Common components of encoding a Vulkan API call
def make_event_handler_call(
handler_access,
api,
context_param,
input_result_param,
cgen,
suffix=""):
extraParams = [context_param.paramName]
if input_result_param:
extraParams.append(input_result_param)
return cgen.makeCallExpr( \
"%s->on_%s%s" % (handler_access, api.name, suffix),
extraParams + \
[p.paramName for p in api.parameters[:-1]])
def emit_custom_pre_validate(typeInfo, api, cgen):
if api.name in ENCODER_PREVALIDATED_APIS:
callExpr = \
make_event_handler_call( \
"mImpl->validation()", api,
ENCODER_THIS_PARAM,
SUCCESS_RET_TYPES[api.getRetTypeExpr()],
cgen)
if api.getRetTypeExpr() == "void":
cgen.stmt("VALIDATE_VOID(%s)" % callExpr)
else:
cgen.stmt("VALIDATE_RET(%s, %s, %s)" % \
(api.getRetTypeExpr(),
SUCCESS_RET_TYPES[api.getRetTypeExpr()],
callExpr))
def emit_custom_resource_preprocess(typeInfo, api, cgen):
if api.name in ENCODER_CUSTOM_RESOURCE_PREPROCESS:
cgen.stmt( \
make_event_handler_call( \
"sResourceTracker", api,
ENCODER_THIS_PARAM,
SUCCESS_RET_TYPES[api.getRetTypeExpr()],
cgen, suffix="_pre"))
def emit_custom_resource_postprocess(typeInfo, api, cgen):
if api.name in ENCODER_CUSTOM_RESOURCE_POSTPROCESS:
cgen.stmt(make_event_handler_call( \
"sResourceTracker",
api,
ENCODER_THIS_PARAM,
api.getRetVarExpr(),
cgen))
def emit_count_marshal(typeInfo, param, cgen):
res = \
iterateVulkanType(
typeInfo, param,
VulkanCountingCodegen( \
cgen, "sFeatureBits", param.paramName, "countPtr", ROOT_TYPE_DEFAULT_VALUE,
"count_"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_marshal(typeInfo, param, cgen):
forOutput = param.isHandleType() and ("out" in param.inout)
if forOutput:
cgen.stmt("/* is handle, possibly out */")
res = \
iterateVulkanType(
typeInfo, param,
VulkanReservedMarshalingCodegen( \
cgen, "guest", STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName, "streamPtrPtr",
API_PREFIX_RESERVEDMARSHAL,
"" if forOutput else "get_host_u64_",
direction="write"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
if forOutput:
cgen.stmt("/* is handle, possibly out */")
def emit_unmarshal(typeInfo, param, cgen):
iterateVulkanType(
typeInfo, param,
VulkanMarshalingCodegen( \
cgen, STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName,
API_PREFIX_UNMARSHAL, direction="read"))
def emit_deepcopy(typeInfo, param, cgen):
res = \
iterateVulkanType(typeInfo, param, DeepcopyCodegen(
cgen, [param.paramName, "local_" + param.paramName], "pool", ROOT_TYPE_DEFAULT_VALUE, "deepcopy_"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_transform(typeInfo, param, cgen, variant="tohost"):
res = \
iterateVulkanType(typeInfo, param, TransformCodegen( \
cgen, param.paramName, "sResourceTracker", "transform_%s_" % variant, variant))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_handlemap_create(typeInfo, param, cgen):
iterateVulkanType(typeInfo, param, HandleMapCodegen(
cgen, None, "sResourceTracker", "handlemap_",
lambda vtype: typeInfo.isHandleType(vtype.typeName)
))
def custom_encoder_args(api):
params = ["this"]
if api.getRetVarExpr() is not None:
params.append(api.getRetVarExpr())
return params
def emit_handlemap_destroy(typeInfo, param, cgen):
iterateVulkanType(typeInfo, param, HandleMapCodegen(
cgen, None, "sResourceTracker->destroyMapping()", "handlemap_",
lambda vtype: typeInfo.isHandleType(vtype.typeName)
))
class EncodingParameters(object):
def __init__(self, api):
self.localCopied = []
self.toWrite = []
self.toRead = []
self.toCreate = []
self.toDestroy = []
for param in api.parameters:
param.action = None
param.inout = "in"
if param.paramName == "doLock":
continue
if param.possiblyOutput():
param.inout += "out"
self.toWrite.append(param)
self.toRead.append(param)
if param.isCreatedBy(api):
self.toCreate.append(param)
param.action = "create"
else:
if param.paramName == "doLock":
continue
if param.isDestroyedBy(api):
self.toDestroy.append(param)
param.action = "destroy"
localCopyParam = \
param.getForNonConstAccess().withModifiedName( \
"local_" + param.paramName)
self.localCopied.append((param, localCopyParam))
self.toWrite.append(localCopyParam)
def emit_parameter_encode_preamble_write(typeInfo, api, cgen):
emit_custom_pre_validate(typeInfo, api, cgen);
emit_custom_resource_preprocess(typeInfo, api, cgen);
cgen.stmt("auto %s = mImpl->stream()" % STREAM)
cgen.stmt("auto %s = mImpl->pool()" % POOL)
# cgen.stmt("%s->setHandleMapping(%s->unwrapMapping())" % (STREAM, RESOURCES))
encodingParams = EncodingParameters(api)
for (_, localCopyParam) in encodingParams.localCopied:
cgen.stmt(cgen.makeRichCTypeDecl(localCopyParam))
def emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen, customUnwrap=None):
encodingParams = EncodingParameters(api)
for (origParam, localCopyParam) in encodingParams.localCopied:
shouldCustomCopy = \
customUnwrap and \
origParam.paramName in customUnwrap and \
"copyOp" in customUnwrap[origParam.paramName]
shouldCustomMap = \
customUnwrap and \
origParam.paramName in customUnwrap and \
"mapOp" in customUnwrap[origParam.paramName]
if shouldCustomCopy:
customUnwrap[origParam.paramName]["copyOp"](cgen, origParam, localCopyParam)
else:
# if this is a pointer type and we don't do custom copy nor unwrap,
# and the transform doesn't end up doing anything,
# don't deepcopy, just cast it.
avoidDeepcopy = False
if origParam.pointerIndirectionLevels > 0:
testCgen = CodeGen()
genTransformsForVulkanType("sResourceTracker", origParam, lambda p: testCgen.generalAccess(p, parentVarName = None, asPtr = True), lambda p: testCgen.generalLengthAccess(p, parentVarName = None), testCgen)
emit_transform(typeInfo, origParam, testCgen, variant="tohost")
if "" == testCgen.swapCode():
avoidDeepcopy = True
if avoidDeepcopy:
cgen.line("// Avoiding deepcopy for %s" % origParam.paramName)
cgen.stmt("%s = (%s%s)%s" % (localCopyParam.paramName, localCopyParam.typeName, "*" * origParam.pointerIndirectionLevels, origParam.paramName))
else:
emit_deepcopy(typeInfo, origParam, cgen)
for (origParam, localCopyParam) in encodingParams.localCopied:
shouldCustomMap = \
customUnwrap and \
origParam.paramName in customUnwrap and \
"mapOp" in customUnwrap[origParam.paramName]
if shouldCustomMap:
customUnwrap[origParam.paramName]["mapOp"](cgen, origParam, localCopyParam)
else:
if localCopyParam.typeName == "VkAllocationCallbacks":
cgen.stmt("%s = nullptr" % localCopyParam.paramName)
apiForTransform = \
api.withCustomParameters( \
map(lambda p: p[1], \
encodingParams.localCopied))
# Apply transforms if applicable.
# Apply transform to API itself:
genTransformsForVulkanType(
"sResourceTracker",
apiForTransform,
lambda p: cgen.generalAccess(p, parentVarName = None, asPtr = True),
lambda p: cgen.generalLengthAccess(p, parentVarName = None),
cgen)
# For all local copied parameters, run the transforms
for localParam in apiForTransform.parameters:
if "doLock" in localParam.paramName:
continue
emit_transform(typeInfo, localParam, cgen, variant="tohost")
cgen.stmt("size_t count = 0")
cgen.stmt("size_t* countPtr = &count")
cgen.beginBlock()
# Use counting stream to calculate the packet size.
for p in encodingParams.toWrite:
emit_count_marshal(typeInfo, p, cgen)
cgen.endBlock()
def is_cmdbuf_dispatch(api):
return "VkCommandBuffer" == api.parameters[0].typeName
def emit_parameter_encode_write_packet_info(typeInfo, api, cgen):
# Seqno and skipping dispatch serialize are for use with VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT
doSeqno = True
doDispatchSerialize = True
if is_cmdbuf_dispatch(api):
doSeqno = False
doDispatchSerialize = False
if doSeqno:
cgen.stmt("uint32_t packetSize_%s = 4 + 4 + (queueSubmitWithCommandsEnabled ? 4 : 0) + count" % (api.name))
else:
cgen.stmt("uint32_t packetSize_%s = 4 + 4 + count" % (api.name))
cgen.stmt("healthMonitorAnnotation_packetSize = std::make_optional(packetSize_%s)" % (api.name))
if not doDispatchSerialize:
cgen.stmt("if (queueSubmitWithCommandsEnabled) packetSize_%s -= 8" % api.name)
cgen.stmt("uint8_t* streamPtr = %s->reserve(packetSize_%s)" % (STREAM, api.name))
cgen.stmt("uint8_t* packetBeginPtr = streamPtr")
cgen.stmt("uint8_t** streamPtrPtr = &streamPtr")
cgen.stmt("uint32_t opcode_%s = OP_%s" % (api.name, api.name))
if doSeqno:
cgen.stmt("uint32_t seqno; if (queueSubmitWithCommandsEnabled) seqno = ResourceTracker::nextSeqno()")
cgen.stmt("healthMonitorAnnotation_seqno = std::make_optional(seqno)")
cgen.stmt("memcpy(streamPtr, &opcode_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
cgen.stmt("memcpy(streamPtr, &packetSize_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
if doSeqno:
cgen.line("if (queueSubmitWithCommandsEnabled) { memcpy(streamPtr, &seqno, sizeof(uint32_t)); streamPtr += sizeof(uint32_t); }")
def emit_parameter_encode_do_parameter_write(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
dispatchDone = False
for p in encodingParams.toWrite:
if is_cmdbuf_dispatch(api) and not dispatchDone:
cgen.beginIf("!queueSubmitWithCommandsEnabled")
emit_marshal(typeInfo, p, cgen)
cgen.endIf()
else:
emit_marshal(typeInfo, p, cgen)
dispatchDone = True
cgen.beginIf("watchdog")
cgen.stmt("size_t watchdogBufSize = std::min<size_t>(static_cast<size_t>(packetSize_%s), kWatchdogBufferMax)" % (api.name))
cgen.stmt("healthMonitorAnnotation_packetContents.resize(watchdogBufSize)")
cgen.stmt("memcpy(&healthMonitorAnnotation_packetContents[0], packetBeginPtr, watchdogBufSize)")
cgen.endIf()
def emit_parameter_encode_read(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
for p in encodingParams.toRead:
if p.action == "create":
cgen.stmt(
"%s->setHandleMapping(%s->createMapping())" % \
(STREAM, RESOURCES))
emit_unmarshal(typeInfo, p, cgen)
if p.action == "create":
cgen.stmt(
"%s->unsetHandleMapping()" % STREAM)
emit_transform(typeInfo, p, cgen, variant="fromhost")
def emit_post(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
emit_custom_resource_postprocess(typeInfo, api, cgen)
for p in encodingParams.toDestroy:
emit_handlemap_destroy(typeInfo, p, cgen)
doSeqno = True
if is_cmdbuf_dispatch(api):
doSeqno = False
retType = api.getRetTypeExpr()
if api.name in ENCODER_EXPLICIT_FLUSHED_APIS:
cgen.stmt("stream->flush()");
return
if doSeqno:
if retType == "void":
encodingParams = EncodingParameters(api)
if 0 == len(encodingParams.toRead):
cgen.stmt("stream->flush()");
def emit_pool_free(cgen):
cgen.stmt("++encodeCount;")
cgen.beginIf("0 == encodeCount % POOL_CLEAR_INTERVAL")
cgen.stmt("pool->freeAll()")
cgen.stmt("%s->clearPool()" % STREAM)
cgen.endIf()
def emit_return_unmarshal(typeInfo, api, cgen):
retType = api.getRetTypeExpr()
if retType == "void":
return
retVar = api.getRetVarExpr()
cgen.stmt("%s %s = (%s)0" % (retType, retVar, retType))
cgen.stmt("%s->read(&%s, %s)" % \
(STREAM, retVar, cgen.sizeofExpr(api.retType)))
def emit_return(typeInfo, api, cgen):
if api.getRetTypeExpr() == "void":
return
retVar = api.getRetVarExpr()
cgen.stmt("return %s" % retVar)
def emit_lock(cgen):
cgen.stmt("(void)doLock");
cgen.stmt("bool queueSubmitWithCommandsEnabled = sFeatureBits & VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT")
cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->lock()")
def emit_unlock(cgen):
cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->unlock()")
def emit_debug_log(typeInfo, api, cgen):
logFormat = []
logVargs = []
for param in api.parameters:
if param.paramName == "doLock":
continue
paramFormatSpecifier = param.getPrintFormatSpecifier()
if not paramFormatSpecifier:
continue
logFormat.append(param.paramName + ":" + paramFormatSpecifier)
logVargs.append(param.paramName)
logFormatStr = ", ".join(logFormat)
logVargsStr = ", ".join(logVargs)
cgen.stmt("ENCODER_DEBUG_LOG(\"%s(%s)\", %s)" % (api.name, logFormatStr, logVargsStr))
def emit_health_watchdog(api, cgen):
cgen.stmt("std::optional<uint32_t> healthMonitorAnnotation_seqno = std::nullopt")
cgen.stmt("std::optional<uint32_t> healthMonitorAnnotation_packetSize = std::nullopt")
cgen.stmt("std::vector<uint8_t> healthMonitorAnnotation_packetContents")
cgen.line("""
auto watchdog = WATCHDOG_BUILDER(mHealthMonitor, \"%s in VkEncoder\")
.setOnHangCallback([&]() {
auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
if (healthMonitorAnnotation_seqno) {
annotations->insert({{"seqno", std::to_string(healthMonitorAnnotation_seqno.value())}});
}
if (healthMonitorAnnotation_packetSize) {
annotations->insert({{"packetSize", std::to_string(healthMonitorAnnotation_packetSize.value())}});
}
if (!healthMonitorAnnotation_packetContents.empty()) {
annotations->insert(
{{"packetContents", getPacketContents(
&healthMonitorAnnotation_packetContents[0], healthMonitorAnnotation_packetContents.size())}});
}
return std::move(annotations);
})
.build();
"""% (api.name)
)
def emit_default_encoding(typeInfo, api, cgen):
emit_debug_log(typeInfo, api, cgen)
emit_lock(cgen)
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_post(typeInfo, api, cgen)
emit_pool_free(cgen)
emit_unlock(cgen)
emit_return(typeInfo, api, cgen)
## Custom encoding definitions##################################################
def emit_only_goldfish_custom(typeInfo, api, cgen):
emit_lock(cgen)
cgen.vkApiCall( \
api,
customPrefix="sResourceTracker->on_",
customParameters=custom_encoder_args(api) + \
[p.paramName for p in api.parameters[:-1]])
emit_unlock(cgen)
emit_return(typeInfo, api, cgen)
def emit_only_resource_event(typeInfo, api, cgen):
cgen.stmt("(void)doLock");
input_result = None
retExpr = api.getRetVarExpr()
if retExpr:
retType = api.getRetTypeExpr()
input_result = SUCCESS_RET_TYPES[retType]
cgen.stmt("%s %s = (%s)0" % (retType, retExpr, retType))
cgen.stmt(
(("%s = " % retExpr) if retExpr else "") +
make_event_handler_call(
"sResourceTracker",
api,
ENCODER_THIS_PARAM,
input_result, cgen))
if retExpr:
emit_return(typeInfo, api, cgen)
def emit_with_custom_unwrap(custom):
def call(typeInfo, api, cgen):
emit_lock(cgen)
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(
typeInfo, api, cgen, customUnwrap=custom)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_pool_free(cgen)
emit_unlock(cgen)
emit_return(typeInfo, api, cgen)
return call
def encode_vkFlushMappedMemoryRanges(typeInfo, api, cgen):
emit_lock(cgen)
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
def emit_flush_ranges(streamVar):
cgen.beginIf("!sResourceTracker->usingDirectMapping()")
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = pMemoryRanges[i].memory")
cgen.stmt("auto size = pMemoryRanges[i].size")
cgen.stmt("auto offset = pMemoryRanges[i].offset")
cgen.stmt("uint64_t streamSize = 0")
cgen.stmt("if (!memory) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
cgen.stmt("if (!hostPtr) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("streamSize = actualSize")
cgen.stmt("%s->write(&streamSize, sizeof(uint64_t))" % streamVar)
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("%s->write(targetRange, actualSize)" % streamVar)
cgen.endFor()
cgen.endIf()
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_flush_ranges(STREAM)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_pool_free(cgen)
emit_unlock(cgen)
emit_return(typeInfo, api, cgen)
def encode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
emit_lock(cgen)
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
def emit_invalidate_ranges(streamVar):
cgen.beginIf("!sResourceTracker->usingDirectMapping()")
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = pMemoryRanges[i].memory")
cgen.stmt("auto size = pMemoryRanges[i].size")
cgen.stmt("auto offset = pMemoryRanges[i].offset")
cgen.stmt("uint64_t streamSize = 0")
cgen.stmt("if (!memory) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
cgen.stmt("if (!hostPtr) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("streamSize = actualSize")
cgen.stmt("%s->read(&streamSize, sizeof(uint64_t))" % streamVar)
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("%s->read(targetRange, actualSize)" % streamVar)
cgen.endFor()
cgen.endIf()
emit_invalidate_ranges(STREAM)
emit_pool_free(cgen)
emit_unlock(cgen)
emit_return(typeInfo, api, cgen)
def emit_manual_inline(typeInfo, api, cgen):
cgen.line("#include \"%s_encode_impl.cpp.inl\"" % api.name)
def unwrap_vkCreateImage_pCreateInfo():
def mapOp(cgen, orig, local):
cgen.stmt("sResourceTracker->unwrap_vkCreateImage_pCreateInfo(%s, %s)" %
(orig.paramName, local.paramName))
return { "pCreateInfo" : { "mapOp" : mapOp } }
def unwrap_vkBindImageMemory2_pBindInfos():
def mapOp(cgen, orig, local):
cgen.stmt("sResourceTracker->unwrap_VkBindImageMemory2_pBindInfos(bindInfoCount, %s, %s)" %
(orig.paramName, local.paramName))
return { "pBindInfos" : { "mapOp" : mapOp } }
def unwrap_vkAcquireImageANDROID_nativeFenceFd():
def mapOp(cgen, orig, local):
cgen.stmt("sResourceTracker->unwrap_vkAcquireImageANDROID_nativeFenceFd(%s, &%s)" %
(orig.paramName, local.paramName))
return { "nativeFenceFd" : { "mapOp" : mapOp } }
custom_encodes = {
"vkMapMemory" : emit_only_resource_event,
"vkUnmapMemory" : emit_only_resource_event,
"vkFlushMappedMemoryRanges" : encode_vkFlushMappedMemoryRanges,
"vkInvalidateMappedMemoryRanges" : encode_vkInvalidateMappedMemoryRanges,
"vkCreateImage" : emit_with_custom_unwrap(unwrap_vkCreateImage_pCreateInfo()),
"vkCreateImageWithRequirementsGOOGLE" : emit_with_custom_unwrap(unwrap_vkCreateImage_pCreateInfo()),
"vkBindImageMemory2": emit_with_custom_unwrap(unwrap_vkBindImageMemory2_pBindInfos()),
"vkAcquireImageANDROID" : emit_with_custom_unwrap(unwrap_vkAcquireImageANDROID_nativeFenceFd()),
"vkQueueFlushCommandsGOOGLE" : emit_manual_inline,
}
class VulkanEncoder(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
self.cgenHeader = CodeGen()
self.cgenHeader.incrIndent()
self.cgenImpl = CodeGen()
def onBegin(self,):
self.module.appendHeader(encoder_decl_preamble)
self.module.appendImpl(encoder_impl_preamble)
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
api = copy.deepcopy(self.typeInfo.apis[name])
api.parameters.append(makeVulkanTypeSimple(False, "uint32_t", 0, "doLock"))
self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(api))
apiImpl = api.withModifiedName("VkEncoder::" + api.name)
self.module.appendHeader(self.cgenHeader.swapCode())
def emit_function_impl(cgen):
emit_health_watchdog(api, cgen)
if api.name in custom_encodes.keys():
custom_encodes[api.name](self.typeInfo, api, cgen)
else:
emit_default_encoding(self.typeInfo, api, cgen)
self.module.appendImpl(self.cgenImpl.makeFuncImpl(apiImpl, emit_function_impl))
def onEnd(self,):
self.module.appendHeader(encoder_decl_postamble)
self.cgenHeader.decrIndent()

View file

@ -0,0 +1,124 @@
# 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
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import STRUCT_EXTENSION_PARAM
from .wrapperdefs import STRUCT_EXTENSION_PARAM_FOR_WRITE
from .wrapperdefs import EXTENSION_SIZE_API_NAME
from .wrapperdefs import EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
from .wrapperdefs import STRUCT_TYPE_API_NAME
class VulkanExtensionStructs(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.structTypeRetType = \
makeVulkanTypeSimple(False, "uint32_t", 0)
self.rootTypeVarName = "rootType"
self.rootTypeParam = \
makeVulkanTypeSimple(False, "VkStructureType",
0, self.rootTypeVarName)
self.structTypePrototype = \
VulkanAPI(STRUCT_TYPE_API_NAME,
self.structTypeRetType,
[STRUCT_EXTENSION_PARAM])
self.extensionStructSizeRetType = \
makeVulkanTypeSimple(False, "size_t", 0)
self.extensionStructSizePrototype = \
VulkanAPI(EXTENSION_SIZE_API_NAME,
self.extensionStructSizeRetType,
[self.rootTypeParam, STRUCT_EXTENSION_PARAM])
self.streamFeaturesType = makeVulkanTypeSimple(False, "uint32_t", 0, "streamFeatures")
self.extensionStructSizeWithStreamFeaturesPrototype = \
VulkanAPI(EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME,
self.extensionStructSizeRetType,
[self.streamFeaturesType, self.rootTypeParam, STRUCT_EXTENSION_PARAM])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
self.module.appendHeader(self.codegen.makeFuncDecl(
self.structTypePrototype))
self.module.appendHeader(self.codegen.makeFuncDecl(
self.extensionStructSizePrototype))
self.module.appendHeader(self.codegen.makeFuncDecl(
self.extensionStructSizeWithStreamFeaturesPrototype))
def onGenType(self, typeXml, name, alias):
VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
def onEnd(self,):
VulkanWrapperGenerator.onEnd(self)
def castAsStruct(varName, typeName, const=True):
return "reinterpret_cast<%s%s*>(%s)" % \
("const " if const else "", typeName, varName)
def structTypeImpl(cgen):
cgen.stmt(
"const uint32_t asStructType = *(%s)" %
(castAsStruct(STRUCT_EXTENSION_PARAM.paramName, "uint32_t")))
cgen.stmt("return asStructType")
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.structTypePrototype, structTypeImpl))
def forEachExtensionReturnSize(ext, _, cgen):
cgen.stmt("return sizeof(%s)" % ext.name)
def forEachExtensionReturnSizeProtectedByFeature(ext, _, cgen):
streamFeature = ext.getProtectStreamFeature()
if streamFeature is None:
cgen.stmt("return sizeof(%s)" % ext.name)
return
cgen.beginIf("%s & %s" % ("streamFeatures", streamFeature))
cgen.stmt("return sizeof(%s)" % ext.name)
cgen.endIf()
cgen.beginElse()
cgen.stmt("return 0")
cgen.endIf()
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.extensionStructSizePrototype,
lambda cgen: self.emitForEachStructExtension(
cgen,
self.extensionStructSizeRetType,
STRUCT_EXTENSION_PARAM,
forEachExtensionReturnSize, autoBreak=False,
rootTypeVar=self.rootTypeParam)))
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.extensionStructSizeWithStreamFeaturesPrototype,
lambda cgen: self.emitForEachStructExtension(
cgen,
self.extensionStructSizeRetType,
STRUCT_EXTENSION_PARAM,
forEachExtensionReturnSizeProtectedByFeature, autoBreak=False,
rootTypeVar=self.rootTypeParam)))

View file

@ -0,0 +1,102 @@
# 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, VulkanAPIWrapper
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import API_PREFIX_VALIDATE
from .wrapperdefs import PARAMETERS_VALIDATE
from .wrapperdefs import VOID_TYPE
from .wrapperdefs import VALIDATE_RESULT_TYPE
from .wrapperdefs import VALIDATE_VAR_NAME
from .wrapperdefs import VALIDATE_GOOD_RESULT
from .wrapperdefs import VULKAN_STREAM_TYPE
from .wrapperdefs import VULKAN_STREAM_VAR_NAME
from .wrapperdefs import API_PREFIX_MARSHAL
from .wrapperdefs import API_PREFIX_FRONTEND
# Frontend
class VulkanFrontend(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
def validateDefFunc(_codegen, _api):
# TODO
pass
self.validateWrapper = \
VulkanAPIWrapper(
API_PREFIX_VALIDATE,
PARAMETERS_VALIDATE,
VOID_TYPE,
validateDefFunc)
def frontendDefFunc(codegen, api):
retTypeName = api.retType.typeName
codegen.stmt(
"%s %s = %s" % (VALIDATE_RESULT_TYPE, VALIDATE_VAR_NAME,
VALIDATE_GOOD_RESULT))
codegen.funcCall(None, API_PREFIX_VALIDATE + api.origName,
["&%s" % VALIDATE_VAR_NAME] + list(
map(lambda p: p.paramName, api.parameters)))
codegen.beginIf(
"%s != %s" % (VALIDATE_VAR_NAME, VALIDATE_GOOD_RESULT))
if retTypeName == VALIDATE_RESULT_TYPE:
codegen.stmt("return %s" % VALIDATE_VAR_NAME)
elif retTypeName != "void":
codegen.stmt("return (%s)0" % retTypeName)
else:
codegen.stmt("return")
codegen.endIf()
codegen.stmt("// VULKAN_STREAM_GET()")
codegen.stmt("%s* %s = nullptr" % (VULKAN_STREAM_TYPE,
VULKAN_STREAM_VAR_NAME))
retLhs = None
if retTypeName != "void":
retLhs = retTypeName + " res"
codegen.funcCall(retLhs, API_PREFIX_MARSHAL + api.origName,
[VULKAN_STREAM_VAR_NAME] + list(
map(lambda p: p.paramName, api.parameters)))
if retTypeName != "void":
codegen.stmt("return res")
self.frontendWrapper = \
VulkanAPIWrapper(
API_PREFIX_FRONTEND,
[],
None,
frontendDefFunc)
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
self.module.appendHeader(
self.frontendWrapper.makeDecl(self.typeInfo, name))
self.module.appendImpl(
self.validateWrapper.makeDefinition(
self.typeInfo, name, isStatic=True))
self.module.appendImpl(
self.frontendWrapper.makeDefinition(self.typeInfo, name))

View file

@ -0,0 +1,411 @@
from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
from .common.vulkantypes import EXCLUDED_APIS
RESOURCE_TRACKER_ENTRIES = [
"vkEnumerateInstanceExtensionProperties",
"vkEnumerateDeviceExtensionProperties",
"vkEnumeratePhysicalDevices",
"vkAllocateMemory",
"vkFreeMemory",
"vkCreateImage",
"vkDestroyImage",
"vkGetImageMemoryRequirements",
"vkGetImageMemoryRequirements2",
"vkGetImageMemoryRequirements2KHR",
"vkBindImageMemory",
"vkBindImageMemory2",
"vkBindImageMemory2KHR",
"vkCreateBuffer",
"vkDestroyBuffer",
"vkGetBufferMemoryRequirements",
"vkGetBufferMemoryRequirements2",
"vkGetBufferMemoryRequirements2KHR",
"vkBindBufferMemory",
"vkBindBufferMemory2",
"vkBindBufferMemory2KHR",
"vkCreateSemaphore",
"vkDestroySemaphore",
"vkQueueSubmit",
"vkQueueSubmit2",
"vkQueueWaitIdle",
"vkImportSemaphoreFdKHR",
"vkGetSemaphoreFdKHR",
# Warning: These need to be defined in vk.xml (currently no-op) {
"vkGetMemoryFuchsiaHandleKHR",
"vkGetMemoryFuchsiaHandlePropertiesKHR",
"vkGetSemaphoreFuchsiaHandleKHR",
"vkImportSemaphoreFuchsiaHandleKHR",
# } end Warning: These need to be defined in vk.xml (currently no-op)
"vkGetAndroidHardwareBufferPropertiesANDROID",
"vkGetMemoryAndroidHardwareBufferANDROID",
"vkCreateSamplerYcbcrConversion",
"vkDestroySamplerYcbcrConversion",
"vkCreateSamplerYcbcrConversionKHR",
"vkDestroySamplerYcbcrConversionKHR",
"vkUpdateDescriptorSetWithTemplate",
"vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkBeginCommandBuffer",
"vkEndCommandBuffer",
"vkResetCommandBuffer",
"vkCreateImageView",
"vkCreateSampler",
"vkGetPhysicalDeviceExternalFenceProperties",
"vkGetPhysicalDeviceExternalFencePropertiesKHR",
"vkGetPhysicalDeviceExternalBufferProperties",
"vkGetPhysicalDeviceExternalBufferPropertiesKHR",
"vkCreateFence",
"vkResetFences",
"vkImportFenceFdKHR",
"vkGetFenceFdKHR",
"vkWaitForFences",
"vkCreateDescriptorPool",
"vkDestroyDescriptorPool",
"vkResetDescriptorPool",
"vkAllocateDescriptorSets",
"vkFreeDescriptorSets",
"vkCreateDescriptorSetLayout",
"vkUpdateDescriptorSets",
"vkCmdExecuteCommands",
"vkCmdBindDescriptorSets",
"vkDestroyDescriptorSetLayout",
"vkAllocateCommandBuffers",
"vkQueueSignalReleaseImageANDROID",
"vkCmdPipelineBarrier",
"vkCreateGraphicsPipelines",
# Fuchsia
"vkGetMemoryZirconHandleFUCHSIA",
"vkGetMemoryZirconHandlePropertiesFUCHSIA",
"vkGetSemaphoreZirconHandleFUCHSIA",
"vkImportSemaphoreZirconHandleFUCHSIA",
"vkCreateBufferCollectionFUCHSIA",
"vkDestroyBufferCollectionFUCHSIA",
"vkSetBufferCollectionImageConstraintsFUCHSIA",
"vkSetBufferCollectionBufferConstraintsFUCHSIA",
"vkGetBufferCollectionPropertiesFUCHSIA",
]
SUCCESS_VAL = {
"VkResult" : ["VK_SUCCESS"],
}
POSTPROCESSES = {
"vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) {
ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool);
}""",
"vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) {
ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers);
}""",
}
def is_cmdbuf_dispatch(api):
return "VkCommandBuffer" == api.parameters[0].typeName
def is_queue_dispatch(api):
return "VkQueue" == api.parameters[0].typeName
class VulkanFuncTable(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
self.cgen = CodeGen()
self.entries = []
self.entryFeatures = []
self.cmdToFeatureType = {}
self.feature = None
self.featureType = None
def onBegin(self,):
cgen = self.cgen
cgen.line("static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)")
cgen.beginBlock()
cgen.stmt("ALOGE(\"invalid call to %s: %s not supported\", apiname, neededFeature)")
cgen.stmt("abort()")
cgen.endBlock()
self.module.appendImpl(cgen.swapCode())
pass
def onBeginFeature(self, featureName, featureType):
self.feature = featureName
self.featureType = featureType
def onEndFeature(self):
self.feature = None
self.featureType = None
def onFeatureNewCmd(self, name):
self.cmdToFeatureType[name] = self.featureType
def onGenCmd(self, cmdinfo, name, alias):
typeInfo = self.typeInfo
cgen = self.cgen
api = typeInfo.apis[name]
self.entries.append(api)
self.entryFeatures.append(self.feature)
def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True):
cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
if is_cmdbuf_dispatch(api):
cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)")
elif is_queue_dispatch(api):
cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)")
else:
cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()")
callLhs = None
retTypeName = api.getRetTypeExpr()
if retTypeName != "void":
retVar = api.getRetVarExpr()
cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
callLhs = retVar
if name in RESOURCE_TRACKER_ENTRIES:
if declareResources:
cgen.stmt("auto resources = ResourceTracker::get()")
cgen.funcCall(
callLhs, "resources->" + "on_" + api.name,
["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
[p.paramName for p in api.parameters])
else:
cgen.funcCall(
callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"])
if name in POSTPROCESSES:
cgen.line(POSTPROCESSES[name])
if retTypeName != "void":
cgen.stmt("return %s" % retVar)
api_entry = api.withModifiedName("entry_" + api.name)
cgen.line("static " + self.cgen.makeFuncProto(api_entry))
cgen.beginBlock()
genEncoderOrResourceTrackerCall(cgen, api)
cgen.endBlock()
if self.isDeviceDispatch(api) and self.feature != "VK_VERSION_1_0":
api_entry_dyn_check = api.withModifiedName("dynCheck_entry_" + api.name)
cgen.line("static " + self.cgen.makeFuncProto(api_entry_dyn_check))
cgen.beginBlock()
if self.feature == "VK_VERSION_1_3":
cgen.stmt("auto resources = ResourceTracker::get()")
if "VkCommandBuffer" == api.parameters[0].typeName:
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_3")
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
cgen.endIf()
elif self.feature == "VK_VERSION_1_2":
cgen.stmt("auto resources = ResourceTracker::get()")
if "VkCommandBuffer" == api.parameters[0].typeName:
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_2")
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
cgen.endIf()
elif self.feature == "VK_VERSION_1_1":
cgen.stmt("auto resources = ResourceTracker::get()")
if "VkCommandBuffer" == api.parameters[0].typeName:
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1")
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
cgen.endIf()
elif self.feature != "VK_VERSION_1_0":
cgen.stmt("auto resources = ResourceTracker::get()")
if "VkCommandBuffer" == api.parameters[0].typeName:
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer);")
cgen.beginIf("!resources->hasDeviceExtension(device, \"%s\")" % self.feature)
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
cgen.endIf()
else:
print("About to generate a frivolous api!: dynCheck entry: %s" % api.name)
raise
genEncoderOrResourceTrackerCall(cgen, api, declareResources = False)
cgen.endBlock()
self.module.appendImpl(cgen.swapCode())
def onEnd(self,):
getProcAddressDecl = "void* goldfish_vulkan_get_proc_address(const char* name)"
self.module.appendHeader(getProcAddressDecl + ";\n")
self.module.appendImpl(getProcAddressDecl)
self.cgen.beginBlock()
prevFeature = None
for e, f in zip(self.entries, self.entryFeatures):
featureEndif = prevFeature is not None and (f != prevFeature)
featureif = not featureEndif and (f != prevFeature)
if featureEndif:
self.cgen.leftline("#endif")
self.cgen.leftline("#ifdef %s" % f)
if featureif:
self.cgen.leftline("#ifdef %s" % f)
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
if e.name in EXCLUDED_APIS:
self.cgen.stmt("return nullptr")
elif f == "VK_VERSION_1_3":
self.cgen.stmt("return nullptr")
elif f == "VK_VERSION_1_2":
self.cgen.stmt("return nullptr")
elif f == "VK_VERSION_1_1":
self.cgen.stmt("return nullptr")
elif f != "VK_VERSION_1_0":
self.cgen.stmt("return nullptr")
else:
self.cgen.stmt("return (void*)%s" % ("entry_" + e.name))
self.cgen.endIf()
prevFeature = f
self.cgen.leftline("#endif")
self.cgen.stmt("return nullptr")
self.cgen.endBlock()
self.module.appendImpl(self.cgen.swapCode())
getInstanceProcAddressDecl = "void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name)"
self.module.appendHeader(getInstanceProcAddressDecl + ";\n")
self.module.appendImpl(getInstanceProcAddressDecl)
self.cgen.beginBlock()
self.cgen.stmt(
"auto resources = ResourceTracker::get()")
self.cgen.stmt(
"bool has1_1OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_1")
self.cgen.stmt(
"bool has1_2OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_2")
self.cgen.stmt(
"bool has1_3OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_3")
prevFeature = None
for e, f in zip(self.entries, self.entryFeatures):
featureEndif = prevFeature is not None and (f != prevFeature)
featureif = not featureEndif and (f != prevFeature)
if featureEndif:
self.cgen.leftline("#endif")
self.cgen.leftline("#ifdef %s" % f)
if featureif:
self.cgen.leftline("#ifdef %s" % f)
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
entryPointExpr = "(void*)%s" % ("entry_" + e.name)
if e.name in EXCLUDED_APIS:
self.cgen.stmt("return nullptr")
elif f == "VK_VERSION_1_3":
if self.isDeviceDispatch(e):
self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
else:
self.cgen.stmt( \
"return has1_3OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f == "VK_VERSION_1_2":
if self.isDeviceDispatch(e):
self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
else:
self.cgen.stmt( \
"return has1_2OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f == "VK_VERSION_1_1":
if self.isDeviceDispatch(e):
self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
else:
self.cgen.stmt( \
"return has1_1OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f != "VK_VERSION_1_0":
entryNeedsInstanceExtensionCheck = self.cmdToFeatureType[e.name] == "instance"
entryPrefix = "dynCheck_" if self.isDeviceDispatch(e) else ""
entryPointExpr = "(void*)%sentry_%s" % (entryPrefix, e.name)
if entryNeedsInstanceExtensionCheck:
self.cgen.stmt("bool hasExt = resources->hasInstanceExtension(instance, \"%s\")" % f)
self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
else:
# TODO(b/236246382): We need to check the device extension support here.
self.cgen.stmt("// TODO(b/236246382): Check support for device extension");
self.cgen.stmt("return %s" % entryPointExpr)
else:
self.cgen.stmt("return %s" % entryPointExpr)
self.cgen.endIf()
prevFeature = f
self.cgen.leftline("#endif")
self.cgen.stmt("return nullptr")
self.cgen.endBlock()
self.module.appendImpl(self.cgen.swapCode())
getDeviceProcAddressDecl = "void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)"
self.module.appendHeader(getDeviceProcAddressDecl + ";\n")
self.module.appendImpl(getDeviceProcAddressDecl)
self.cgen.beginBlock()
self.cgen.stmt(
"auto resources = ResourceTracker::get()")
self.cgen.stmt(
"bool has1_1OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_1")
self.cgen.stmt(
"bool has1_2OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_2")
self.cgen.stmt(
"bool has1_3OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_3")
prevFeature = None
for e, f in zip(self.entries, self.entryFeatures):
featureEndif = prevFeature is not None and (f != prevFeature)
featureif = not featureEndif and (f != prevFeature)
if featureEndif:
self.cgen.leftline("#endif")
self.cgen.leftline("#ifdef %s" % f)
if featureif:
self.cgen.leftline("#ifdef %s" % f)
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
entryPointExpr = "(void*)%s" % ("entry_" + e.name)
if e.name in EXCLUDED_APIS:
self.cgen.stmt("return nullptr")
elif f == "VK_VERSION_1_3":
self.cgen.stmt( \
"return has1_3OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f == "VK_VERSION_1_2":
self.cgen.stmt( \
"return has1_2OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f == "VK_VERSION_1_1":
self.cgen.stmt( \
"return has1_1OrHigher ? %s : nullptr" % \
entryPointExpr)
elif f != "VK_VERSION_1_0":
self.cgen.stmt( \
"bool hasExt = resources->hasDeviceExtension(device, \"%s\")" % f)
self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
else:
self.cgen.stmt("return %s" % entryPointExpr)
self.cgen.endIf()
prevFeature = f
self.cgen.leftline("#endif")
self.cgen.stmt("return nullptr")
self.cgen.endBlock()
self.module.appendImpl(self.cgen.swapCode())
def isDeviceDispatch(self, api):
# TODO(230793667): improve the heuristic and just use "cmdToFeatureType"
return (len(api.parameters) > 0 and
"VkDevice" == api.parameters[0].typeName) or (
"VkCommandBuffer" == api.parameters[0].typeName and
self.cmdToFeatureType.get(api.name, "") == "device")

View file

@ -0,0 +1,264 @@
# 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
class HandleMapCodegen(VulkanTypeIterator):
def __init__(self, cgen, inputVar, handlemapVarName, prefix, isHandleFunc):
self.cgen = cgen
self.inputVar = inputVar
self.prefix = prefix
self.handlemapVarName = handlemapVarName
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.isHandleFunc = isHandleFunc
def needSkip(self, vulkanType):
return False
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):
if self.needSkip(vulkanType):
self.cgen.line("// TODO: Unsupported : %s" %
self.cgen.makeCTypeDecl(vulkanType))
return
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)
self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
[self.handlemapVarName, 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):
if not self.isHandleFunc(vulkanType):
return
accessLhs = self.exprAccessor(vulkanType)
lenAccess = self.lenAccessor(vulkanType)
self.cgen.stmt("%s->mapHandles_%s(%s%s, %s)" % \
(self.handlemapVarName, vulkanType.typeName,
self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
accessLhs, lenAccess))
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.handlemapVarName, castedAccessExpr])
self.cgen.endIf()
def onPointer(self, vulkanType):
if self.needSkip(vulkanType):
return
if not self.isHandleFunc(vulkanType):
return
access = self.exprAccessor(vulkanType)
lenAccess = self.lenAccessor(vulkanType)
lenAccess = "1" if lenAccess is None else lenAccess
self.cgen.beginIf(access)
self.cgen.stmt( \
"%s->mapHandles_%s(%s%s, %s)" % \
(self.handlemapVarName,
vulkanType.typeName,
self.makeCastExpr(vulkanType.getForNonConstAccess()),
access,
lenAccess))
self.cgen.endIf()
def onValue(self, vulkanType):
if not self.isHandleFunc(vulkanType):
return
access = self.exprAccessor(vulkanType)
self.cgen.stmt(
"%s->mapHandles_%s(%s%s)" % \
(self.handlemapVarName, vulkanType.typeName,
self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
access))
class VulkanHandleMap(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.handlemapPrefix = "handlemap_"
self.toMapVar = "toMap"
self.handlemapVarName = "handlemap"
self.handlemapParam = \
makeVulkanTypeSimple(False, "VulkanHandleMapping", 1,
self.handlemapVarName)
self.voidType = makeVulkanTypeSimple(False, "void", 0)
self.handlemapCodegen = \
HandleMapCodegen(
None,
self.toMapVar,
self.handlemapVarName,
self.handlemapPrefix,
lambda vtype : typeInfo.isHandleType(vtype.typeName))
self.knownDefs = {}
self.extensionHandlemapPrototype = \
VulkanAPI(self.handlemapPrefix + "extension_struct",
self.voidType,
[self.handlemapParam, STRUCT_EXTENSION_PARAM_FOR_WRITE])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
self.module.appendImpl(self.codegen.makeFuncDecl(
self.extensionHandlemapPrototype))
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.handlemapPrefix + name,
self.handlemapPrefix + alias))
if category in ["struct", "union"] and not alias:
structInfo = self.typeInfo.structs[name]
typeFromName = \
lambda varname: \
makeVulkanTypeSimple(varname == "from", name, 1, varname)
handlemapParams = \
[self.handlemapParam] + \
list(map(typeFromName, [self.toMapVar]))
handlemapPrototype = \
VulkanAPI(self.handlemapPrefix + name,
self.voidType,
handlemapParams)
def funcDefGenerator(cgen):
self.handlemapCodegen.cgen = cgen
for p in handlemapParams:
cgen.stmt("(void)%s" % p.paramName)
for member in structInfo.members:
iterateVulkanType(self.typeInfo, member,
self.handlemapCodegen)
self.module.appendHeader(
self.codegen.makeFuncDecl(handlemapPrototype))
self.module.appendImpl(
self.codegen.makeFuncImpl(handlemapPrototype, funcDefGenerator))
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
def onEnd(self,):
VulkanWrapperGenerator.onEnd(self)
def forEachExtensionHandlemap(ext, castedAccess, cgen):
cgen.funcCall(None, self.handlemapPrefix + ext.name,
[self.handlemapVarName, castedAccess])
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.extensionHandlemapPrototype,
lambda cgen: self.emitForEachStructExtension(
cgen,
self.voidType,
STRUCT_EXTENSION_PARAM_FOR_WRITE,
forEachExtensionHandlemap)))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,528 @@
# Copyright (c) 2021 The Android Open Source Project
# Copyright (c) 2021 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.
KNOWN_FUNCTION_OPCODES = {
"vkCreateInstance": 20000,
"vkDestroyInstance": 20001,
"vkEnumeratePhysicalDevices": 20002,
"vkGetPhysicalDeviceFeatures": 20003,
"vkGetPhysicalDeviceFormatProperties": 20004,
"vkGetPhysicalDeviceImageFormatProperties": 20005,
"vkGetPhysicalDeviceProperties": 20006,
"vkGetPhysicalDeviceQueueFamilyProperties": 20007,
"vkGetPhysicalDeviceMemoryProperties": 20008,
"vkGetInstanceProcAddr": 20009,
"vkGetDeviceProcAddr": 20010,
"vkCreateDevice": 20011,
"vkDestroyDevice": 20012,
"vkEnumerateInstanceExtensionProperties": 20013,
"vkEnumerateDeviceExtensionProperties": 20014,
"vkEnumerateInstanceLayerProperties": 20015,
"vkEnumerateDeviceLayerProperties": 20016,
"vkGetDeviceQueue": 20017,
"vkQueueSubmit": 20018,
"vkQueueWaitIdle": 20019,
"vkDeviceWaitIdle": 20020,
"vkAllocateMemory": 20021,
"vkFreeMemory": 20022,
"vkMapMemory": 20023,
"vkUnmapMemory": 20024,
"vkFlushMappedMemoryRanges": 20025,
"vkInvalidateMappedMemoryRanges": 20026,
"vkGetDeviceMemoryCommitment": 20027,
"vkBindBufferMemory": 20028,
"vkBindImageMemory": 20029,
"vkGetBufferMemoryRequirements": 20030,
"vkGetImageMemoryRequirements": 20031,
"vkGetImageSparseMemoryRequirements": 20032,
"vkGetPhysicalDeviceSparseImageFormatProperties": 20033,
"vkQueueBindSparse": 20034,
"vkCreateFence": 20035,
"vkDestroyFence": 20036,
"vkResetFences": 20037,
"vkGetFenceStatus": 20038,
"vkWaitForFences": 20039,
"vkCreateSemaphore": 20040,
"vkDestroySemaphore": 20041,
"vkCreateEvent": 20042,
"vkDestroyEvent": 20043,
"vkGetEventStatus": 20044,
"vkSetEvent": 20045,
"vkResetEvent": 20046,
"vkCreateQueryPool": 20047,
"vkDestroyQueryPool": 20048,
"vkGetQueryPoolResults": 20049,
"vkCreateBuffer": 20050,
"vkDestroyBuffer": 20051,
"vkCreateBufferView": 20052,
"vkDestroyBufferView": 20053,
"vkCreateImage": 20054,
"vkDestroyImage": 20055,
"vkGetImageSubresourceLayout": 20056,
"vkCreateImageView": 20057,
"vkDestroyImageView": 20058,
"vkCreateShaderModule": 20059,
"vkDestroyShaderModule": 20060,
"vkCreatePipelineCache": 20061,
"vkDestroyPipelineCache": 20062,
"vkGetPipelineCacheData": 20063,
"vkMergePipelineCaches": 20064,
"vkCreateGraphicsPipelines": 20065,
"vkCreateComputePipelines": 20066,
"vkDestroyPipeline": 20067,
"vkCreatePipelineLayout": 20068,
"vkDestroyPipelineLayout": 20069,
"vkCreateSampler": 20070,
"vkDestroySampler": 20071,
"vkCreateDescriptorSetLayout": 20072,
"vkDestroyDescriptorSetLayout": 20073,
"vkCreateDescriptorPool": 20074,
"vkDestroyDescriptorPool": 20075,
"vkResetDescriptorPool": 20076,
"vkAllocateDescriptorSets": 20077,
"vkFreeDescriptorSets": 20078,
"vkUpdateDescriptorSets": 20079,
"vkCreateFramebuffer": 20080,
"vkDestroyFramebuffer": 20081,
"vkCreateRenderPass": 20082,
"vkDestroyRenderPass": 20083,
"vkGetRenderAreaGranularity": 20084,
"vkCreateCommandPool": 20085,
"vkDestroyCommandPool": 20086,
"vkResetCommandPool": 20087,
"vkAllocateCommandBuffers": 20088,
"vkFreeCommandBuffers": 20089,
"vkBeginCommandBuffer": 20090,
"vkEndCommandBuffer": 20091,
"vkResetCommandBuffer": 20092,
"vkCmdBindPipeline": 20093,
"vkCmdSetViewport": 20094,
"vkCmdSetScissor": 20095,
"vkCmdSetLineWidth": 20096,
"vkCmdSetDepthBias": 20097,
"vkCmdSetBlendConstants": 20098,
"vkCmdSetDepthBounds": 20099,
"vkCmdSetStencilCompareMask": 20100,
"vkCmdSetStencilWriteMask": 20101,
"vkCmdSetStencilReference": 20102,
"vkCmdBindDescriptorSets": 20103,
"vkCmdBindIndexBuffer": 20104,
"vkCmdBindVertexBuffers": 20105,
"vkCmdDraw": 20106,
"vkCmdDrawIndexed": 20107,
"vkCmdDrawIndirect": 20108,
"vkCmdDrawIndexedIndirect": 20109,
"vkCmdDispatch": 20110,
"vkCmdDispatchIndirect": 20111,
"vkCmdCopyBuffer": 20112,
"vkCmdCopyImage": 20113,
"vkCmdBlitImage": 20114,
"vkCmdCopyBufferToImage": 20115,
"vkCmdCopyImageToBuffer": 20116,
"vkCmdUpdateBuffer": 20117,
"vkCmdFillBuffer": 20118,
"vkCmdClearColorImage": 20119,
"vkCmdClearDepthStencilImage": 20120,
"vkCmdClearAttachments": 20121,
"vkCmdResolveImage": 20122,
"vkCmdSetEvent": 20123,
"vkCmdResetEvent": 20124,
"vkCmdWaitEvents": 20125,
"vkCmdPipelineBarrier": 20126,
"vkCmdBeginQuery": 20127,
"vkCmdEndQuery": 20128,
"vkCmdResetQueryPool": 20129,
"vkCmdWriteTimestamp": 20130,
"vkCmdCopyQueryPoolResults": 20131,
"vkCmdPushConstants": 20132,
"vkCmdBeginRenderPass": 20133,
"vkCmdNextSubpass": 20134,
"vkCmdEndRenderPass": 20135,
"vkCmdExecuteCommands": 20136,
"vkEnumerateInstanceVersion": 20137,
"vkBindBufferMemory2": 20138,
"vkBindImageMemory2": 20139,
"vkGetDeviceGroupPeerMemoryFeatures": 20140,
"vkCmdSetDeviceMask": 20141,
"vkCmdDispatchBase": 20142,
"vkEnumeratePhysicalDeviceGroups": 20143,
"vkGetImageMemoryRequirements2": 20144,
"vkGetBufferMemoryRequirements2": 20145,
"vkGetImageSparseMemoryRequirements2": 20146,
"vkGetPhysicalDeviceFeatures2": 20147,
"vkGetPhysicalDeviceProperties2": 20148,
"vkGetPhysicalDeviceFormatProperties2": 20149,
"vkGetPhysicalDeviceImageFormatProperties2": 20150,
"vkGetPhysicalDeviceQueueFamilyProperties2": 20151,
"vkGetPhysicalDeviceMemoryProperties2": 20152,
"vkGetPhysicalDeviceSparseImageFormatProperties2": 20153,
"vkTrimCommandPool": 20154,
"vkGetDeviceQueue2": 20155,
"vkCreateSamplerYcbcrConversion": 20156,
"vkDestroySamplerYcbcrConversion": 20157,
"vkCreateDescriptorUpdateTemplate": 20158,
"vkDestroyDescriptorUpdateTemplate": 20159,
"vkUpdateDescriptorSetWithTemplate": 20160,
"vkGetPhysicalDeviceExternalBufferProperties": 20161,
"vkGetPhysicalDeviceExternalFenceProperties": 20162,
"vkGetPhysicalDeviceExternalSemaphoreProperties": 20163,
"vkGetDescriptorSetLayoutSupport": 20164,
"vkDestroySurfaceKHR": 20165,
"vkGetPhysicalDeviceSurfaceSupportKHR": 20166,
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR": 20167,
"vkGetPhysicalDeviceSurfaceFormatsKHR": 20168,
"vkGetPhysicalDeviceSurfacePresentModesKHR": 20169,
"vkCreateSwapchainKHR": 20170,
"vkDestroySwapchainKHR": 20171,
"vkGetSwapchainImagesKHR": 20172,
"vkAcquireNextImageKHR": 20173,
"vkQueuePresentKHR": 20174,
"vkGetDeviceGroupPresentCapabilitiesKHR": 20175,
"vkGetDeviceGroupSurfacePresentModesKHR": 20176,
"vkGetPhysicalDevicePresentRectanglesKHR": 20177,
"vkAcquireNextImage2KHR": 20178,
"vkGetPhysicalDeviceDisplayPropertiesKHR": 20179,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR": 20180,
"vkGetDisplayPlaneSupportedDisplaysKHR": 20181,
"vkGetDisplayModePropertiesKHR": 20182,
"vkCreateDisplayModeKHR": 20183,
"vkGetDisplayPlaneCapabilitiesKHR": 20184,
"vkCreateDisplayPlaneSurfaceKHR": 20185,
"vkCreateSharedSwapchainsKHR": 20186,
"vkCreateXlibSurfaceKHR": 20187,
"vkGetPhysicalDeviceXlibPresentationSupportKHR": 20188,
"vkCreateXcbSurfaceKHR": 20189,
"vkGetPhysicalDeviceXcbPresentationSupportKHR": 20190,
"vkCreateWaylandSurfaceKHR": 20191,
"vkGetPhysicalDeviceWaylandPresentationSupportKHR": 20192,
"vkCreateMirSurfaceKHR": 20193,
"vkGetPhysicalDeviceMirPresentationSupportKHR": 20194,
"vkCreateAndroidSurfaceKHR": 20195,
"vkCreateWin32SurfaceKHR": 20196,
"vkGetPhysicalDeviceWin32PresentationSupportKHR": 20197,
"vkGetPhysicalDeviceFeatures2KHR": 20198,
"vkGetPhysicalDeviceProperties2KHR": 20199,
"vkGetPhysicalDeviceFormatProperties2KHR": 20200,
"vkGetPhysicalDeviceImageFormatProperties2KHR": 20201,
"vkGetPhysicalDeviceQueueFamilyProperties2KHR": 20202,
"vkGetPhysicalDeviceMemoryProperties2KHR": 20203,
"vkGetPhysicalDeviceSparseImageFormatProperties2KHR": 20204,
"vkGetDeviceGroupPeerMemoryFeaturesKHR": 20205,
"vkCmdSetDeviceMaskKHR": 20206,
"vkCmdDispatchBaseKHR": 20207,
"vkTrimCommandPoolKHR": 20208,
"vkEnumeratePhysicalDeviceGroupsKHR": 20209,
"vkGetPhysicalDeviceExternalBufferPropertiesKHR": 20210,
"vkGetMemoryWin32HandleKHR": 20211,
"vkGetMemoryWin32HandlePropertiesKHR": 20212,
"vkGetMemoryFdKHR": 20213,
"vkGetMemoryFdPropertiesKHR": 20214,
"vkGetPhysicalDeviceExternalSemaphorePropertiesKHR": 20215,
"vkImportSemaphoreWin32HandleKHR": 20216,
"vkGetSemaphoreWin32HandleKHR": 20217,
"vkImportSemaphoreFdKHR": 20218,
"vkGetSemaphoreFdKHR": 20219,
"vkCmdPushDescriptorSetKHR": 20220,
"vkCmdPushDescriptorSetWithTemplateKHR": 20221,
"vkCreateDescriptorUpdateTemplateKHR": 20222,
"vkDestroyDescriptorUpdateTemplateKHR": 20223,
"vkUpdateDescriptorSetWithTemplateKHR": 20224,
"vkCreateRenderPass2KHR": 20225,
"vkCmdBeginRenderPass2KHR": 20226,
"vkCmdNextSubpass2KHR": 20227,
"vkCmdEndRenderPass2KHR": 20228,
"vkGetSwapchainStatusKHR": 20229,
"vkGetPhysicalDeviceExternalFencePropertiesKHR": 20230,
"vkImportFenceWin32HandleKHR": 20231,
"vkGetFenceWin32HandleKHR": 20232,
"vkImportFenceFdKHR": 20233,
"vkGetFenceFdKHR": 20234,
"vkGetPhysicalDeviceSurfaceCapabilities2KHR": 20235,
"vkGetPhysicalDeviceSurfaceFormats2KHR": 20236,
"vkGetPhysicalDeviceDisplayProperties2KHR": 20237,
"vkGetPhysicalDeviceDisplayPlaneProperties2KHR": 20238,
"vkGetDisplayModeProperties2KHR": 20239,
"vkGetDisplayPlaneCapabilities2KHR": 20240,
"vkGetImageMemoryRequirements2KHR": 20241,
"vkGetBufferMemoryRequirements2KHR": 20242,
"vkGetImageSparseMemoryRequirements2KHR": 20243,
"vkCreateSamplerYcbcrConversionKHR": 20244,
"vkDestroySamplerYcbcrConversionKHR": 20245,
"vkBindBufferMemory2KHR": 20246,
"vkBindImageMemory2KHR": 20247,
"vkGetDescriptorSetLayoutSupportKHR": 20248,
"vkCmdDrawIndirectCountKHR": 20249,
"vkCmdDrawIndexedIndirectCountKHR": 20250,
"vkGetSwapchainGrallocUsageANDROID": 20251,
"vkAcquireImageANDROID": 20252,
"vkQueueSignalReleaseImageANDROID": 20253,
"vkCreateDebugReportCallbackEXT": 20254,
"vkDestroyDebugReportCallbackEXT": 20255,
"vkDebugReportMessageEXT": 20256,
"vkDebugMarkerSetObjectTagEXT": 20257,
"vkDebugMarkerSetObjectNameEXT": 20258,
"vkCmdDebugMarkerBeginEXT": 20259,
"vkCmdDebugMarkerEndEXT": 20260,
"vkCmdDebugMarkerInsertEXT": 20261,
"vkCmdDrawIndirectCountAMD": 20262,
"vkCmdDrawIndexedIndirectCountAMD": 20263,
"vkGetShaderInfoAMD": 20264,
"vkGetPhysicalDeviceExternalImageFormatPropertiesNV": 20265,
"vkGetMemoryWin32HandleNV": 20266,
"vkCreateViSurfaceNN": 20267,
"vkCmdBeginConditionalRenderingEXT": 20268,
"vkCmdEndConditionalRenderingEXT": 20269,
"vkCmdProcessCommandsNVX": 20270,
"vkCmdReserveSpaceForCommandsNVX": 20271,
"vkCreateIndirectCommandsLayoutNVX": 20272,
"vkDestroyIndirectCommandsLayoutNVX": 20273,
"vkCreateObjectTableNVX": 20274,
"vkDestroyObjectTableNVX": 20275,
"vkRegisterObjectsNVX": 20276,
"vkUnregisterObjectsNVX": 20277,
"vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX": 20278,
"vkCmdSetViewportWScalingNV": 20279,
"vkReleaseDisplayEXT": 20280,
"vkAcquireXlibDisplayEXT": 20281,
"vkGetRandROutputDisplayEXT": 20282,
"vkGetPhysicalDeviceSurfaceCapabilities2EXT": 20283,
"vkDisplayPowerControlEXT": 20284,
"vkRegisterDeviceEventEXT": 20285,
"vkRegisterDisplayEventEXT": 20286,
"vkGetSwapchainCounterEXT": 20287,
"vkGetRefreshCycleDurationGOOGLE": 20288,
"vkGetPastPresentationTimingGOOGLE": 20289,
"vkCmdSetDiscardRectangleEXT": 20290,
"vkSetHdrMetadataEXT": 20291,
"vkCreateIOSSurfaceMVK": 20292,
"vkCreateMacOSSurfaceMVK": 20293,
"vkSetDebugUtilsObjectNameEXT": 20294,
"vkSetDebugUtilsObjectTagEXT": 20295,
"vkQueueBeginDebugUtilsLabelEXT": 20296,
"vkQueueEndDebugUtilsLabelEXT": 20297,
"vkQueueInsertDebugUtilsLabelEXT": 20298,
"vkCmdBeginDebugUtilsLabelEXT": 20299,
"vkCmdEndDebugUtilsLabelEXT": 20300,
"vkCmdInsertDebugUtilsLabelEXT": 20301,
"vkCreateDebugUtilsMessengerEXT": 20302,
"vkDestroyDebugUtilsMessengerEXT": 20303,
"vkSubmitDebugUtilsMessageEXT": 20304,
"vkGetAndroidHardwareBufferPropertiesANDROID": 20305,
"vkGetMemoryAndroidHardwareBufferANDROID": 20306,
"vkCmdSetSampleLocationsEXT": 20307,
"vkGetPhysicalDeviceMultisamplePropertiesEXT": 20308,
"vkCreateValidationCacheEXT": 20309,
"vkDestroyValidationCacheEXT": 20310,
"vkMergeValidationCachesEXT": 20311,
"vkGetValidationCacheDataEXT": 20312,
"vkGetMemoryHostPointerPropertiesEXT": 20313,
"vkCmdWriteBufferMarkerAMD": 20314,
"vkCmdSetCheckpointNV": 20315,
"vkGetQueueCheckpointDataNV": 20316,
"vkMapMemoryIntoAddressSpaceGOOGLE": 20317,
"vkUpdateDescriptorSetWithTemplateSizedGOOGLE": 20320,
"vkBeginCommandBufferAsyncGOOGLE": 20321,
"vkEndCommandBufferAsyncGOOGLE": 20322,
"vkResetCommandBufferAsyncGOOGLE": 20323,
"vkCommandBufferHostSyncGOOGLE": 20324,
"vkCreateImageWithRequirementsGOOGLE": 20325,
"vkCreateBufferWithRequirementsGOOGLE": 20326,
"vkGetMemoryHostAddressInfoGOOGLE": 20327,
"vkFreeMemorySyncGOOGLE": 20328,
"vkQueueHostSyncGOOGLE": 20329,
"vkQueueSubmitAsyncGOOGLE": 20330,
"vkQueueWaitIdleAsyncGOOGLE": 20331,
"vkQueueBindSparseAsyncGOOGLE": 20332,
"vkGetLinearImageLayoutGOOGLE": 20333,
"vkGetMTLDeviceMVK": 20334,
"vkSetMTLTextureMVK": 20335,
"vkGetMTLTextureMVK": 20336,
"vkGetMTLBufferMVK": 20337,
"vkUseIOSurfaceMVK": 20338,
"vkGetIOSurfaceMVK": 20339,
"vkQueueFlushCommandsGOOGLE": 20340,
"vkGetBlobGOOGLE": 20341,
}
CUSTOM_MARSHAL_TYPES = {
"VkAccelerationStructureInstanceKHR": {
"common": """
typedef struct VkAccelerationStructureInstanceKHRWithoutBitFields {
VkTransformMatrixKHR transform;
uint32_t dwords[2];
uint64_t accelerationStructureReference;
} VkAccelerationStructureInstanceKHRWithoutBitFields;
""",
"marshaling": """
const VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"unmarshaling": """
VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"reservedmarshaling": """
(void)vkStream;
const VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
"reservedunmarshaling": """
VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
},
"VkAccelerationStructureMatrixMotionInstanceNV": {
"common": """
typedef struct VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields {
VkTransformMatrixKHR transformT0;
VkTransformMatrixKHR transformT1;
uint32_t dwords[2];
uint64_t accelerationStructureReference;
} VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields;
""",
"marshaling": """
const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0));
marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"unmarshaling": """
VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0));
unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"reservedmarshaling": """
(void)vkStream;
const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0), ptr);
reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
"reservedunmarshaling": """
VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0), ptr);
reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
},
"VkAccelerationStructureSRTMotionInstanceNV": {
"common": """
typedef struct VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields {
VkSRTDataNV transformT0;
VkSRTDataNV transformT1;
uint32_t dwords[2];
uint64_t accelerationStructureReference;
} VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields;
""",
"marshaling": """
const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
marshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0));
marshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"unmarshaling": """
VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
unmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0));
unmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1));
for (uint32_t i = 0; i < 2; i++) {{
{streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
}}
{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
""",
"reservedmarshaling": """
(void)vkStream;
const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
reservedmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0), ptr);
reservedmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
"reservedunmarshaling": """
VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
reservedunmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0), ptr);
reservedunmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1), ptr);
for (uint32_t i = 0; i < 2; i++) {{
memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
*ptr += sizeof(uint32_t);
}}
memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
*ptr += sizeof(uint64_t);
""",
},
"VkXcbSurfaceCreateInfoKHR": {
"common": """
// This struct should never be marshaled / unmarshaled.
__builtin_trap();
""",
"marshaling": "",
"unmarshaling": "",
"reservedmarshaling": "",
"reservedunmarshaling": "",
},
"VkMetalSurfaceCreateInfoEXT": {
"common": """
// This struct should never be marshaled / unmarshaled.
__builtin_trap();
""",
"marshaling": "",
"unmarshaling": "",
"reservedmarshaling": "",
"reservedunmarshaling": "",
},
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,405 @@
from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import VulkanAPI, iterateVulkanType, VulkanType
from .reservedmarshaling import VulkanReservedMarshalingCodegen
from .transform import TransformCodegen
from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
from .wrapperdefs import MAX_PACKET_LENGTH
from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
decoder_decl_preamble = """
"""
decoder_impl_preamble = """
"""
global_state_prefix = "this->on_"
READ_STREAM = "readStream"
WRITE_STREAM = "vkStream"
# Driver workarounds for APIs that don't work well multithreaded
driver_workarounds_global_lock_apis = [
"vkCreatePipelineLayout",
"vkDestroyPipelineLayout",
]
MAX_STACK_ITEMS = "16"
def emit_param_decl_for_reading(param, cgen):
if param.staticArrExpr:
cgen.stmt(
cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
else:
cgen.stmt(
cgen.makeRichCTypeDecl(param))
if param.pointerIndirectionLevels > 0:
lenAccess = cgen.generalLengthAccess(param)
if not lenAccess:
lenAccess = "1"
arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
typeHere = "uint8_t*" if "void" == param.typeName else param.typeName
cgen.stmt("%s%s stack_%s[%s]" % (
typeHere, "*" * (param.pointerIndirectionLevels - 1), param.paramName, arrSize))
def emit_unmarshal(typeInfo, param, cgen, output=False, destroy=False, noUnbox=False):
if destroy:
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"",
direction="read",
dynAlloc=True))
lenAccess = cgen.generalLengthAccess(param)
lenAccessGuard = cgen.generalLengthAccessGuard(param)
if None == lenAccess or "1" == lenAccess:
cgen.stmt("boxed_%s_preserve = %s" %
(param.paramName, param.paramName))
cgen.stmt("%s = unbox_%s(%s)" %
(param.paramName, param.typeName, param.paramName))
else:
if lenAccessGuard is not None:
self.cgen.beginIf(lenAccessGuard)
cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
cgen.stmt("boxed_%s_preserve[i] = %s[i]" %
(param.paramName, param.paramName))
cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName,
param.paramName, param.typeName, param.paramName))
cgen.endFor()
if lenAccessGuard is not None:
self.cgen.endIf()
else:
if noUnbox:
cgen.line("// No unbox for %s" % (param.paramName))
lenAccess = cgen.generalLengthAccess(param)
if not lenAccess:
lenAccess = "1"
arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"" if (output or noUnbox) else "unbox_",
direction="read",
dynAlloc=True,
stackVar="stack_%s" % param.paramName,
stackArrSize=arrSize))
def emit_dispatch_unmarshal(typeInfo, param, cgen, globalWrapped):
if globalWrapped:
cgen.stmt(
"// Begin global wrapped dispatchable handle unboxing for %s" % param.paramName)
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"",
direction="read",
dynAlloc=True))
else:
cgen.stmt(
"// Begin non wrapped dispatchable handle unboxing for %s" % param.paramName)
# cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
cgen,
"host",
READ_STREAM,
ROOT_TYPE_DEFAULT_VALUE,
param.paramName,
"readStreamPtrPtr",
API_PREFIX_RESERVEDUNMARSHAL,
"",
direction="read",
dynAlloc=True))
cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
(param.paramName, param.typeName, param.paramName))
cgen.stmt("auto vk = dispatch_%s(%s)" %
(param.typeName, param.paramName))
cgen.stmt("// End manual dispatchable handle unboxing for %s" %
param.paramName)
def emit_transform(typeInfo, param, cgen, variant="tohost"):
res = \
iterateVulkanType(typeInfo, param, TransformCodegen(
cgen, param.paramName, "globalstate", "transform_%s_" % variant, variant))
if not res:
cgen.stmt("(void)%s" % param.paramName)
# Everything here elides the initial arg
class DecodingParameters(object):
def __init__(self, api: VulkanAPI):
self.params: list[VulkanType] = []
self.toRead: list[VulkanType] = []
self.toWrite: list[VulkanType] = []
for i, param in enumerate(api.parameters[1:]):
if i == 0 and param.isDispatchableHandleType():
param.dispatchHandle = True
if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
param.nonDispatchableHandleCreate = True
if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
param.nonDispatchableHandleDestroy = True
if param.isDispatchableHandleType() and param.isCreatedBy(api):
param.dispatchableHandleCreate = True
if param.isDispatchableHandleType() and param.isDestroyedBy(api):
param.dispatchableHandleDestroy = True
self.toRead.append(param)
if param.possiblyOutput():
self.toWrite.append(param)
self.params.append(param)
def emit_call_log(api, cgen):
decodingParams = DecodingParameters(api)
paramsToRead = decodingParams.toRead
# cgen.beginIf("m_logCalls")
paramLogFormat = "%p"
paramLogArgs = ["(void*)boxed_dispatchHandle"]
for p in paramsToRead:
paramLogFormat += "0x%llx "
for p in paramsToRead:
paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
# cgen.stmt("fprintf(stderr, \"substream %%p: call %s %s\\n\", readStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
# cgen.endIf()
def emit_decode_parameters(typeInfo, api, cgen, globalWrapped=False):
decodingParams = DecodingParameters(api)
paramsToRead = decodingParams.toRead
for p in paramsToRead:
emit_param_decl_for_reading(p, cgen)
i = 0
for p in paramsToRead:
lenAccess = cgen.generalLengthAccess(p)
if p.dispatchHandle:
emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
else:
destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
noUnbox = False
if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
destroy = True
cgen.stmt(
"// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
if None == lenAccess or "1" == lenAccess:
cgen.stmt("%s boxed_%s_preserve" %
(p.typeName, p.paramName))
else:
cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" %
(p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
if p.possiblyOutput():
cgen.stmt(
"// Begin manual dispatchable handle unboxing for %s" % p.paramName)
cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
emit_unmarshal(typeInfo, p, cgen, output=p.possiblyOutput(
), destroy=destroy, noUnbox=noUnbox)
i += 1
for p in paramsToRead:
emit_transform(typeInfo, p, cgen, variant="tohost")
emit_call_log(api, cgen)
def emit_dispatch_call(api, cgen):
decodingParams = DecodingParameters(api)
customParams = ["(VkCommandBuffer)dispatchHandle"]
for (i, p) in enumerate(api.parameters[1:]):
customParam = p.paramName
if decodingParams.params[i].dispatchHandle:
customParam = "unboxed_%s" % p.paramName
customParams.append(customParam)
if api.name in driver_workarounds_global_lock_apis:
cgen.stmt("lock()")
cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams,
checkForDeviceLost=True, globalStatePrefix=global_state_prefix,
checkForOutOfMemory=True)
if api.name in driver_workarounds_global_lock_apis:
cgen.stmt("unlock()")
def emit_global_state_wrapped_call(api, cgen, context=False):
customParams = ["pool", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \
list(map(lambda p: p.paramName, api.parameters[1:]))
if context:
customParams += ["context"];
cgen.vkApiCall(api, customPrefix=global_state_prefix,
customParameters=customParams, checkForDeviceLost=True,
checkForOutOfMemory=True, globalStatePrefix=global_state_prefix)
def emit_default_decoding(typeInfo, api, cgen):
emit_decode_parameters(typeInfo, api, cgen)
emit_dispatch_call(api, cgen)
def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True)
emit_global_state_wrapped_call(api, cgen)
def emit_global_state_wrapped_decoding_with_context(typeInfo, api, cgen):
emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True)
emit_global_state_wrapped_call(api, cgen, context=True)
custom_decodes = {
"vkCmdCopyBufferToImage": emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage": emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer": emit_global_state_wrapped_decoding,
"vkCmdCopyBufferToImage2": emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage2": emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer2": emit_global_state_wrapped_decoding,
"vkCmdCopyBufferToImage2KHR": emit_global_state_wrapped_decoding_with_context,
"vkCmdCopyImage2KHR": emit_global_state_wrapped_decoding,
"vkCmdCopyImageToBuffer2KHR": emit_global_state_wrapped_decoding,
"vkCmdExecuteCommands": emit_global_state_wrapped_decoding,
"vkBeginCommandBuffer": emit_global_state_wrapped_decoding_with_context,
"vkEndCommandBuffer": emit_global_state_wrapped_decoding_with_context,
"vkResetCommandBuffer": emit_global_state_wrapped_decoding,
"vkCmdPipelineBarrier": emit_global_state_wrapped_decoding,
"vkCmdBindPipeline": emit_global_state_wrapped_decoding,
"vkCmdBindDescriptorSets": emit_global_state_wrapped_decoding,
"vkCmdCopyQueryPoolResults": emit_global_state_wrapped_decoding,
"vkBeginCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding_with_context,
"vkEndCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding_with_context,
"vkResetCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding,
"vkCommandBufferHostSyncGOOGLE": emit_global_state_wrapped_decoding,
}
class VulkanSubDecoder(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
self.cgen = CodeGen()
def onBegin(self,):
self.module.appendImpl(
"#define MAX_STACK_ITEMS %s\n" % MAX_STACK_ITEMS)
self.module.appendImpl(
"#define MAX_PACKET_LENGTH %s\n" % MAX_PACKET_LENGTH)
self.module.appendImpl(
"size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle, void* dispatchHandle, VkDeviceSize dataSize, const void* pData, const VkDecoderContext& context)\n")
self.cgen.beginBlock() # function body
self.cgen.stmt("auto& metricsLogger = *context.metricsLogger")
self.cgen.stmt("uint32_t count = 0")
self.cgen.stmt("unsigned char *buf = (unsigned char *)pData")
self.cgen.stmt("android::base::BumpPool* pool = readStream->pool()")
self.cgen.stmt("unsigned char *ptr = (unsigned char *)pData")
self.cgen.stmt(
"const unsigned char* const end = (const unsigned char*)buf + dataSize")
self.cgen.stmt(
"VkDecoderGlobalState* globalstate = VkDecoderGlobalState::get()")
self.cgen.line("while (end - ptr >= 8)")
self.cgen.beginBlock() # while loop
self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
self.cgen.stmt("uint32_t packetLen = *(uint32_t *)(ptr + 4)")
self.cgen.line("""
// packetLen should be at least 8 (op code and packet length) and should not be excessively large
if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
WARN("Bad packet length %d detected, subdecode may fail", packetLen);
metricsLogger.logMetricEvent(MetricEventBadPacketLength{ .len = packetLen });
}
""")
self.cgen.stmt("if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
self.cgen.stmt(
"uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
self.cgen.line("switch (opcode)")
self.cgen.beginBlock() # switch stmt
self.module.appendImpl(self.cgen.swapCode())
def onGenCmd(self, cmdinfo, name, alias):
typeInfo = self.typeInfo
cgen = self.cgen
api = typeInfo.apis[name]
if "commandBuffer" != api.parameters[0].paramName:
return
cgen.line("case OP_%s:" % name)
cgen.beginBlock()
cgen.stmt("android::base::beginTrace(\"%s subdecode\")" % name)
if api.name in custom_decodes.keys():
custom_decodes[api.name](typeInfo, api, cgen)
else:
emit_default_decoding(typeInfo, api, cgen)
cgen.stmt("android::base::endTrace()")
cgen.stmt("break")
cgen.endBlock()
self.module.appendImpl(self.cgen.swapCode())
def onEnd(self,):
self.cgen.line("default:")
self.cgen.beginBlock()
self.cgen.stmt(
"GFXSTREAM_ABORT(::emugl::FatalError(::emugl::ABORT_REASON_OTHER)) << \"Unrecognized opcode \" << opcode")
self.cgen.endBlock()
self.cgen.endBlock() # switch stmt
self.cgen.stmt("++count; if (count % 1000 == 0) { pool->freeAll(); }")
self.cgen.stmt("ptr += packetLen")
self.cgen.endBlock() # while loop
self.cgen.stmt("pool->freeAll()")
self.cgen.stmt("return ptr - (unsigned char*)buf;")
self.cgen.endBlock() # function body
self.module.appendImpl(self.cgen.swapCode())

View file

@ -0,0 +1,399 @@
# 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
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import EQUALITY_VAR_NAMES
from .wrapperdefs import EQUALITY_ON_FAIL_VAR
from .wrapperdefs import EQUALITY_ON_FAIL_VAR_TYPE
from .wrapperdefs import EQUALITY_RET_TYPE
from .wrapperdefs import API_PREFIX_EQUALITY
from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM2
class VulkanEqualityCodegen(VulkanTypeIterator):
def __init__(self, cgen, inputVars, onFailCompareVar, prefix):
self.cgen = cgen
self.inputVars = inputVars
self.onFailCompareVar = onFailCompareVar
self.prefix = prefix
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.lenAccessGuardLhs = makeLengthAccessGuard(self.inputVars[0])
self.lenAccessGuardRhs = makeLengthAccessGuard(self.inputVars[1])
self.checked = False
def getTypeForCompare(self, vulkanType):
res = copy(vulkanType)
if not vulkanType.accessibleAsPointer():
res = res.getForAddressAccess()
if vulkanType.staticArrExpr:
res = res.getForAddressAccess()
return res
def makeCastExpr(self, vulkanType):
return "(%s)" % (
self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
def makeEqualExpr(self, lhs, rhs):
return "(%s) == (%s)" % (lhs, rhs)
def makeEqualBufExpr(self, lhs, rhs, size):
return "(memcmp(%s, %s, %s) == 0)" % (lhs, rhs, size)
def makeEqualStringExpr(self, lhs, rhs):
return "(strcmp(%s, %s) == 0)" % (lhs, rhs)
def makeBothNotNullExpr(self, lhs, rhs):
return "(%s) && (%s)" % (lhs, rhs)
def makeBothNullExpr(self, lhs, rhs):
return "!(%s) && !(%s)" % (lhs, rhs)
def compareWithConsequence(self, compareExpr, vulkanType, errMsg=""):
self.cgen.stmt("if (!(%s)) { %s(\"%s (Error: %s)\"); }" %
(compareExpr, self.onFailCompareVar,
self.exprAccessorValueLhs(vulkanType), errMsg))
def onCheck(self, vulkanType):
self.checked = True
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
bothNull = self.makeBothNullExpr(accessLhs, accessRhs)
bothNotNull = self.makeBothNotNullExpr(accessLhs, accessRhs)
nullMatchExpr = "(%s) || (%s)" % (bothNull, bothNotNull)
self.compareWithConsequence( \
nullMatchExpr,
vulkanType,
"Mismatch in optional field")
skipStreamInternal = vulkanType.typeName == "void"
if skipStreamInternal:
return
self.cgen.beginIf("%s && %s" % (accessLhs, accessRhs))
def endCheck(self, vulkanType):
skipStreamInternal = vulkanType.typeName == "void"
if skipStreamInternal:
return
if self.checked:
self.cgen.endIf()
self.checked = False
def onCompoundType(self, vulkanType):
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
lenAccessLhs = self.lenAccessorLhs(vulkanType)
lenAccessRhs = self.lenAccessorRhs(vulkanType)
lenAccessGuardLhs = self.lenAccessGuardLhs(vulkanType)
lenAccessGuardRhs = self.lenAccessGuardRhs(vulkanType)
needNullCheck = vulkanType.pointerIndirectionLevels > 0
if needNullCheck:
bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
self.cgen.beginIf(bothNotNullExpr)
if lenAccessLhs is not None:
equalLenExpr = self.makeEqualExpr(lenAccessLhs, lenAccessRhs)
self.compareWithConsequence( \
equalLenExpr,
vulkanType, "Lengths not equal")
loopVar = "i"
accessLhs = "%s + %s" % (accessLhs, loopVar)
accessRhs = "%s + %s" % (accessRhs, loopVar)
forInit = "uint32_t %s = 0" % loopVar
forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs)
forIncr = "++%s" % loopVar
if needNullCheck:
self.cgen.beginIf(equalLenExpr)
if lenAccessGuardLhs is not None:
self.cgen.beginIf(lenAccessGuardLhs)
self.cgen.beginFor(forInit, forCond, forIncr)
self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
[accessLhs, accessRhs, self.onFailCompareVar])
if lenAccessLhs is not None:
self.cgen.endFor()
if lenAccessGuardLhs is not None:
self.cgen.endIf()
if needNullCheck:
self.cgen.endIf()
if needNullCheck:
self.cgen.endIf()
def onString(self, vulkanType):
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
bothNullExpr = self.makeBothNullExpr(accessLhs, accessRhs)
bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
nullMatchExpr = "(%s) || (%s)" % (bothNullExpr, bothNotNullExpr)
self.compareWithConsequence( \
nullMatchExpr,
vulkanType,
"Mismatch in string pointer nullness")
self.cgen.beginIf(bothNotNullExpr)
self.compareWithConsequence(
self.makeEqualStringExpr(accessLhs, accessRhs),
vulkanType, "Unequal strings")
self.cgen.endIf()
def onStringArray(self, vulkanType):
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
lenAccessLhs = self.lenAccessorLhs(vulkanType)
lenAccessRhs = self.lenAccessorRhs(vulkanType)
lenAccessGuardLhs = self.lenAccessGuardLhs(vulkanType)
lenAccessGuardRhs = self.lenAccessGuardRhs(vulkanType)
bothNullExpr = self.makeBothNullExpr(accessLhs, accessRhs)
bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
nullMatchExpr = "(%s) || (%s)" % (bothNullExpr, bothNotNullExpr)
self.compareWithConsequence( \
nullMatchExpr,
vulkanType,
"Mismatch in string array pointer nullness")
equalLenExpr = self.makeEqualExpr(lenAccessLhs, lenAccessRhs)
self.compareWithConsequence( \
equalLenExpr,
vulkanType, "Lengths not equal in string array")
self.compareWithConsequence( \
equalLenExpr,
vulkanType, "Lengths not equal in string array")
self.cgen.beginIf("%s && %s" % (equalLenExpr, bothNotNullExpr))
loopVar = "i"
accessLhs = "*(%s + %s)" % (accessLhs, loopVar)
accessRhs = "*(%s + %s)" % (accessRhs, loopVar)
forInit = "uint32_t %s = 0" % loopVar
forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs)
forIncr = "++%s" % loopVar
if lenAccessGuardLhs is not None:
self.cgen.beginIf(lenAccessGuardLhs)
self.cgen.beginFor(forInit, forCond, forIncr)
self.compareWithConsequence(
self.makeEqualStringExpr(accessLhs, accessRhs),
vulkanType, "Unequal string in string array")
self.cgen.endFor()
if lenAccessGuardLhs is not None:
self.cgen.endIf()
self.cgen.endIf()
def onStaticArr(self, vulkanType):
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
lenAccessLhs = self.lenAccessorLhs(vulkanType)
finalLenExpr = "%s * %s" % (lenAccessLhs,
self.cgen.sizeofExpr(vulkanType))
self.compareWithConsequence(
self.makeEqualBufExpr(accessLhs, accessRhs, finalLenExpr),
vulkanType, "Unequal static array")
def onStructExtension(self, vulkanType):
lhs = self.exprAccessorLhs(vulkanType)
rhs = self.exprAccessorRhs(vulkanType)
self.cgen.beginIf(lhs)
self.cgen.funcCall(None, self.prefix + "extension_struct",
[lhs, rhs, self.onFailCompareVar])
self.cgen.endIf()
def onPointer(self, vulkanType):
accessLhs = self.exprAccessorLhs(vulkanType)
accessRhs = self.exprAccessorRhs(vulkanType)
skipStreamInternal = vulkanType.typeName == "void"
if skipStreamInternal:
return
lenAccessLhs = self.lenAccessorLhs(vulkanType)
lenAccessRhs = self.lenAccessorRhs(vulkanType)
if lenAccessLhs is not None:
self.compareWithConsequence( \
self.makeEqualExpr(lenAccessLhs, lenAccessRhs),
vulkanType, "Lengths not equal")
finalLenExpr = "%s * %s" % (lenAccessLhs,
self.cgen.sizeofExpr(
vulkanType.getForValueAccess()))
else:
finalLenExpr = self.cgen.sizeofExpr(vulkanType.getForValueAccess())
self.compareWithConsequence(
self.makeEqualBufExpr(accessLhs, accessRhs, finalLenExpr),
vulkanType, "Unequal dyn array")
def onValue(self, vulkanType):
accessLhs = self.exprAccessorValueLhs(vulkanType)
accessRhs = self.exprAccessorValueRhs(vulkanType)
self.compareWithConsequence(
self.makeEqualExpr(accessLhs, accessRhs), vulkanType,
"Value not equal")
class VulkanTesting(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.equalityCodegen = \
VulkanEqualityCodegen(
None,
EQUALITY_VAR_NAMES,
EQUALITY_ON_FAIL_VAR,
API_PREFIX_EQUALITY)
self.knownDefs = {}
self.extensionTestingPrototype = \
VulkanAPI(API_PREFIX_EQUALITY + "extension_struct",
EQUALITY_RET_TYPE,
[STRUCT_EXTENSION_PARAM,
STRUCT_EXTENSION_PARAM2,
EQUALITY_ON_FAIL_VAR_TYPE])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
self.module.appendImpl(self.codegen.makeFuncDecl(
self.extensionTestingPrototype))
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(API_PREFIX_EQUALITY + name,
API_PREFIX_EQUALITY + alias))
if category in ["struct", "union"] and not alias:
structInfo = self.typeInfo.structs[name]
typeFromName = \
lambda varname: makeVulkanTypeSimple(True, name, 1, varname)
compareParams = \
list(map(typeFromName, EQUALITY_VAR_NAMES)) + \
[EQUALITY_ON_FAIL_VAR_TYPE]
comparePrototype = \
VulkanAPI(API_PREFIX_EQUALITY + name,
EQUALITY_RET_TYPE,
compareParams)
def structCompareDef(cgen):
self.equalityCodegen.cgen = cgen
for member in structInfo.members:
iterateVulkanType(self.typeInfo, member,
self.equalityCodegen)
self.module.appendHeader(
self.codegen.makeFuncDecl(comparePrototype))
self.module.appendImpl(
self.codegen.makeFuncImpl(comparePrototype, structCompareDef))
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
def onEnd(self,):
VulkanWrapperGenerator.onEnd(self)
def forEachExtensionCompare(ext, castedAccess, cgen):
cgen.funcCall(None, API_PREFIX_EQUALITY + ext.name,
[castedAccess,
cgen.makeReinterpretCast(
STRUCT_EXTENSION_PARAM2.paramName, ext.name),
EQUALITY_ON_FAIL_VAR])
self.module.appendImpl(
self.codegen.makeFuncImpl(
self.extensionTestingPrototype,
lambda cgen: self.emitForEachStructExtension(
cgen,
EQUALITY_RET_TYPE,
STRUCT_EXTENSION_PARAM,
forEachExtensionCompare)))

View file

@ -0,0 +1,348 @@
# 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)))

View file

@ -0,0 +1,81 @@
# 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, TRANSFORMED_TYPES
from .wrapperdefs import VulkanWrapperGenerator
from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
# This is different from others; it operations solely in terms of deepcopy and handlemap
class VulkanUnbox(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.codegen = CodeGen()
self.unboxPrefix = "unbox"
self.toUnboxVar = "toUnbox"
self.poolParam = \
makeVulkanTypeSimple(False, "BumpPool", 1, "pool")
self.knownStructs = {}
self.needsTransform = set([])
def onBegin(self,):
VulkanWrapperGenerator.onBegin(self)
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:
self.module.appendHeader(
self.codegen.makeFuncAlias(self.unboxPrefix + "_" + name,
self.unboxPrefix + "_" + alias))
if category in ["struct", "union"] and not alias:
structInfo = self.typeInfo.structs[name]
self.knownStructs[name] = structInfo
api = VulkanAPI( \
self.unboxPrefix + "_" + name,
makeVulkanTypeSimple(False, name, 1),
[self.poolParam] + \
[makeVulkanTypeSimple( \
True, name, 1, self.toUnboxVar)])
def funcDefGenerator(cgen):
cgen.stmt("BoxedHandleUnwrapMapping unboxMapping")
cgen.stmt("%s* res = (%s*)pool->alloc(sizeof(const %s))" % (name, name, name))
cgen.stmt("deepcopy_%s(pool, %s, %s)" % (name, self.toUnboxVar, "res"))
cgen.stmt("handlemap_%s(%s, %s)" % (name, "&unboxMapping", "res"))
cgen.stmt("return res")
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)

View file

@ -0,0 +1,46 @@
# Copyright (c) 2022 The Android Open Source Project
# Copyright (c) 2022 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 .wrapperdefs import VulkanWrapperGenerator
class VulkanExtensionStructureType(VulkanWrapperGenerator):
def __init__(self, extensionName: str, module, typeInfo):
super().__init__(module, typeInfo)
self._extensionName = extensionName
def onGenGroup(self, groupinfo, groupName, alias=None):
super().onGenGroup(groupinfo, groupName, alias)
elem = groupinfo.elem
if (not elem.get('type') == 'enum'):
return
if (not elem.get('name') == 'VkStructureType'):
return
extensionEnumFactoryMacro = f'{self._extensionName.upper()}_ENUM'
for enum in elem.findall(f"enum[@extname='{self._extensionName}']"):
name = enum.get('name')
offset = enum.get('offset')
self.module.appendHeader(
f"#define {name} {extensionEnumFactoryMacro}(VkStructureType, {offset})\n")
class VulkanGfxstreamStructureType(VulkanExtensionStructureType):
def __init__(self, module, typeInfo):
super().__init__('VK_GOOGLE_gfxstream', module, typeInfo)
class VulkanAndroidNativeBufferStructureType(VulkanExtensionStructureType):
def __init__(self, module, typeInfo):
super().__init__('VK_ANDROID_native_buffer', module, typeInfo)

View file

@ -0,0 +1,108 @@
# 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 VulkanWrapperGenerator
from .common.vulkantypes import makeVulkanTypeSimple
# Contains definitions for various Vulkan API wrappers. This information is
# shared to make it easier for one kind of wrapper to know how to call
# another one.
API_PREFIX_MARSHAL = "marshal_"
API_PREFIX_UNMARSHAL = "unmarshal_"
API_PREFIX_RESERVEDMARSHAL = "reservedmarshal_"
API_PREFIX_RESERVEDUNMARSHAL = "reservedunmarshal_"
MARSHAL_INPUT_VAR_NAME = "forMarshaling"
UNMARSHAL_INPUT_VAR_NAME = "forUnmarshaling"
API_PREFIX_VALIDATE = "validate_"
API_PREFIX_FRONTEND = "goldfish_frontend_"
VULKAN_STREAM_TYPE = "VulkanStream"
VULKAN_STREAM_TYPE_GUEST = "VulkanStreamGuest"
VULKAN_STREAM_VAR_NAME = "vkStream"
VALIDATE_RESULT_TYPE = "VkResult"
VALIDATE_VAR_NAME = "validateResult"
VALIDATE_GOOD_RESULT = "VK_SUCCESS"
ROOT_TYPE_VAR_NAME = "rootType"
ROOT_TYPE_DEFAULT_VALUE = "VK_STRUCTURE_TYPE_MAX_ENUM"
ROOT_TYPE_TYPE = "VkStructureType"
ROOT_TYPE_PARAM = makeVulkanTypeSimple(
False, ROOT_TYPE_TYPE, 0, ROOT_TYPE_VAR_NAME)
PARAMETERS_MARSHALING = [
makeVulkanTypeSimple(False, VULKAN_STREAM_TYPE, 1, VULKAN_STREAM_VAR_NAME),
ROOT_TYPE_PARAM,
]
PARAMETERS_MARSHALING_GUEST = [
makeVulkanTypeSimple(False, VULKAN_STREAM_TYPE_GUEST,
1, VULKAN_STREAM_VAR_NAME),
ROOT_TYPE_PARAM,
]
PARAMETERS_VALIDATE = [
makeVulkanTypeSimple(False, VALIDATE_RESULT_TYPE, 1, VALIDATE_VAR_NAME)
]
PARAMETERS_COUNTING = [
makeVulkanTypeSimple(False, "size_t", 1, VULKAN_STREAM_VAR_NAME)
]
STRUCT_EXTENSION_PARAM = \
makeVulkanTypeSimple(True, "void", 1, "structExtension")
STRUCT_EXTENSION_PARAM2 = \
makeVulkanTypeSimple(True, "void", 1, "structExtension2")
STRUCT_EXTENSION_PARAM_FOR_WRITE = \
makeVulkanTypeSimple(False, "void", 1, "structExtension_out")
STRUCT_TYPE_API_NAME = "goldfish_vk_struct_type"
EXTENSION_SIZE_API_NAME = "goldfish_vk_extension_struct_size"
EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME = "goldfish_vk_extension_struct_size_with_stream_features"
VOID_TYPE = makeVulkanTypeSimple(False, "void", 0)
STREAM_RET_TYPE = makeVulkanTypeSimple(False, "void", 0)
API_PREFIX_EQUALITY = "checkEqual_"
EQUALITY_VAR_NAMES = ["a", "b"]
EQUALITY_ON_FAIL_VAR = "onFail"
EQUALITY_ON_FAIL_VAR_TYPE = makeVulkanTypeSimple(False, "OnFailCompareFunc", 0,
EQUALITY_ON_FAIL_VAR)
EQUALITY_RET_TYPE = makeVulkanTypeSimple(False, "void", 0)
RELAXED_APIS = [
"vkWaitForFences",
"vkWaitSemaphores",
"vkWaitSemaphoresKHR",
"vkQueueWaitIdle",
"vkDeviceWaitIdle",
"vkQueueFlushCommandsGOOGLE",
]
STYPE_OVERRIDE = {
"VkPhysicalDeviceFragmentDensityMapFeaturesEXT": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT",
"VkPhysicalDeviceFragmentDensityMapPropertiesEXT": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT",
"VkRenderPassFragmentDensityMapCreateInfoEXT": "VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT",
"VkImportColorBufferGOOGLE": "VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE",
"VkImportBufferGOOGLE": "VK_STRUCTURE_TYPE_IMPORT_BUFFER_GOOGLE",
"VkCreateBlobGOOGLE": "VK_STRUCTURE_TYPE_CREATE_BLOB_GOOGLE",
}
MAX_PACKET_LENGTH = "(400 * 1024 * 1024) // 400MB"

View file

@ -0,0 +1,892 @@
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2018 The Khronos Group Inc.
# Copyright (c) 2013-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.
import os, re, sys
from generator import *
from pathlib import Path, PurePosixPath
import cereal
from cereal.wrapperdefs import VULKAN_STREAM_TYPE
from cereal.wrapperdefs import VULKAN_STREAM_TYPE_GUEST
# CerealGenerator - generates set of driver sources
# while being agnostic to the stream implementation
from reg import GroupInfo, TypeInfo, EnumInfo
SUPPORTED_FEATURES = [
"VK_VERSION_1_0",
"VK_VERSION_1_1",
"VK_VERSION_1_2",
"VK_VERSION_1_3",
# Instance extensions
"VK_KHR_get_physical_device_properties2",
"VK_KHR_sampler_ycbcr_conversion",
"VK_KHR_external_semaphore_capabilities",
"VK_KHR_external_memory_capabilities",
"VK_KHR_external_fence_capabilities",
# Device extensions
"VK_KHR_storage_buffer_storage_class",
"VK_KHR_vulkan_memory_model",
"VK_KHR_buffer_device_address",
"VK_KHR_maintenance1",
"VK_KHR_maintenance2",
"VK_KHR_maintenance3",
"VK_KHR_bind_memory2",
"VK_KHR_dedicated_allocation",
"VK_KHR_get_memory_requirements2",
"VK_KHR_sampler_ycbcr_conversion",
"VK_KHR_shader_float16_int8",
"VK_AMD_gpu_shader_half_float",
"VK_NV_shader_subgroup_partitioned",
"VK_KHR_shader_subgroup_extended_types",
"VK_EXT_provoking_vertex",
"VK_EXT_line_rasterization",
"VK_EXT_transform_feedback",
"VK_EXT_primitive_topology_list_restart",
"VK_EXT_index_type_uint8",
"VK_EXT_load_store_op_none",
"VK_EXT_swapchain_colorspace",
"VK_EXT_custom_border_color",
"VK_EXT_shader_stencil_export",
"VK_KHR_image_format_list",
"VK_KHR_incremental_present",
"VK_KHR_pipeline_executable_properties",
"VK_EXT_queue_family_foreign",
"VK_KHR_external_semaphore",
"VK_KHR_external_semaphore_fd",
"VK_KHR_external_memory",
"VK_KHR_external_fence",
"VK_KHR_external_fence_fd",
"VK_EXT_device_memory_report",
"VK_KHR_create_renderpass2",
"VK_KHR_imageless_framebuffer",
"VK_KHR_descriptor_update_template",
# see aosp/2736079 + b/268351352
"VK_EXT_swapchain_maintenance1",
"VK_EXT_image_compression_control",
"VK_EXT_image_compression_control_swapchain",
# VK1.3 extensions: see b/298704840
"VK_KHR_copy_commands2",
"VK_KHR_dynamic_rendering",
"VK_KHR_format_feature_flags2",
"VK_KHR_maintenance4",
"VK_KHR_shader_integer_dot_product",
"VK_KHR_shader_non_semantic_info",
"VK_KHR_shader_terminate_invocation",
"VK_KHR_synchronization2",
"VK_KHR_zero_initialize_workgroup_memory",
"VK_EXT_4444_formats",
"VK_EXT_extended_dynamic_state",
"VK_EXT_extended_dynamic_state2",
"VK_EXT_image_robustness",
"VK_EXT_inline_uniform_block",
"VK_EXT_pipeline_creation_cache_control",
"VK_EXT_pipeline_creation_feedback",
"VK_EXT_private_data",
"VK_EXT_shader_demote_to_helper_invocation",
"VK_EXT_subgroup_size_control",
"VK_EXT_texel_buffer_alignment",
"VK_EXT_texture_compression_astc_hdr",
"VK_EXT_tooling_info",
"VK_EXT_ycbcr_2plane_444_formats",
# Host dispatch
"VK_EXT_debug_utils",
"VK_KHR_surface",
"VK_KHR_swapchain",
"VK_KHR_xcb_surface",
"VK_KHR_win32_surface",
"VK_EXT_metal_surface",
"VK_MVK_moltenvk",
"VK_KHR_external_semaphore_win32",
"VK_KHR_external_memory_win32",
"VK_KHR_external_memory_fd",
# Android
"VK_ANDROID_native_buffer",
"VK_ANDROID_external_memory_android_hardware_buffer",
"VK_KHR_android_surface",
# Custom
"VK_GOOGLE_gfxstream",
# Used in tests without proper support checks
"VK_EXT_graphics_pipeline_library",
]
# By default, the all wrappers are run all on all features. In certain cases,
# we wish run only a subset of wrappers. For example, `VK_GOOGLE_gfxstream`
# shouldn't generate a function table entry since it's an internal interface.
SUPPORTED_WRAPPERS = {
"VK_EXT_debug_utils": [cereal.VulkanDispatch],
"VK_KHR_surface": [cereal.VulkanDispatch],
"VK_KHR_xcb_surface": [cereal.VulkanDispatch],
"VK_KHR_win32_surface": [cereal.VulkanDispatch],
"VK_EXT_metal_surface": [cereal.VulkanDispatch],
# VK_MVK_moltenvk doesn't generate a generate dispatch entry for some reason, but should. The
# lack of this extension doesn't cause any build failtures though.
"VK_MVK_moltenvk": [cereal.VulkanDispatch],
"VK_KHR_external_semaphore_win32" : [cereal.VulkanDispatch],
"VK_KHR_external_memory_win32" : [cereal.VulkanDispatch],
"VK_KHR_external_memory_fd": [cereal.VulkanDispatch],
"VK_ANDROID_external_memory_android_hardware_buffer": [cereal.VulkanFuncTable],
"VK_KHR_android_surface": [cereal.VulkanFuncTable],
}
copyrightHeader = """// 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.
"""
# We put the long generated commands in a separate paragraph, so that the formatter won't mess up
# with other texts.
autogeneratedHeaderTemplate = """
// Autogenerated module %s
//
// %s
//
// Please do not modify directly;
// re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,
// or directly from Python by defining:
// VULKAN_REGISTRY_XML_DIR : Directory containing vk.xml
// VULKAN_REGISTRY_SCRIPTS_DIR : Directory containing genvk.py
// CEREAL_OUTPUT_DIR: Where to put the generated sources.
//
// python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
//
"""
autogeneratedMkTemplate = """
# Autogenerated makefile
# %s
# Please do not modify directly;
# re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,
# or directly from Python by defining:
# VULKAN_REGISTRY_XML_DIR : Directory containing vk.xml
# VULKAN_REGISTRY_SCRIPTS_DIR : Directory containing genvk.py
# CEREAL_OUTPUT_DIR: Where to put the generated sources.
# python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
"""
namespaceBegin ="""
namespace gfxstream {
namespace vk {\n
"""
namespaceEnd = """
} // namespace vk
} // namespace gfxstream
"""
def banner_command(argv):
"""Return sanitized command-line description.
|argv| must be a list of command-line parameters, e.g. sys.argv.
Return a string corresponding to the command, with platform-specific
paths removed."""
def makePosixRelative(someArg):
if os.path.exists(someArg):
return str(PurePosixPath(Path(os.path.relpath(someArg))))
return someArg
return ' '.join(map(makePosixRelative, argv))
def envGetOrDefault(key, default=None):
if key in os.environ:
return os.environ[key]
print("envGetOrDefault: notfound: %s" % key)
return default
# ---- methods overriding base class ----
# beginFile(genOpts)
# endFile()
# beginFeature(interface, emit)
# endFeature()
# genType(typeinfo,name)
# genStruct(typeinfo,name)
# genGroup(groupinfo,name)
# genEnum(enuminfo, name)
# genCmd(cmdinfo)
class CerealGenerator(OutputGenerator):
"""Generate serialization code"""
def __init__(self, errFile = sys.stderr,
warnFile = sys.stderr,
diagFile = sys.stdout):
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
self.typeInfo = cereal.VulkanTypeInfo(self)
self.modules = {}
self.protos = {}
self.moduleList = []
self.protoList = []
self.wrappers = []
self.codegen = cereal.CodeGen()
self.featureSupported = False
self.supportedWrappers = None
self.guestBaseLibDirPrefix = \
envGetOrDefault("VK_CEREAL_GUEST_BASELIB_PREFIX", "aemu/base")
self.baseLibDirPrefix = \
envGetOrDefault("VK_CEREAL_BASELIB_PREFIX", "aemu/base")
self.baseLibLinkName = \
envGetOrDefault("VK_CEREAL_BASELIB_LINKNAME", "android-emu-base")
self.vulkanHeaderTargetName = envGetOrDefault("VK_CEREAL_VK_HEADER_TARGET", "")
self.utilsHeader = envGetOrDefault("VK_CEREAL_UTILS_LINKNAME", "")
self.utilsHeaderDirPrefix = envGetOrDefault("VK_CEREAL_UTILS_PREFIX", "utils")
# THe host always needs all possible guest struct definitions, while the guest only needs
# platform sepcific headers.
self.hostCommonExtraVulkanHeaders = '#include "vk_android_native_buffer.h"'
self.host_cmake_generator = lambda cppFiles: f"""{autogeneratedMkTemplate % banner_command(sys.argv)}
add_library(OpenglRender_vulkan_cereal {cppFiles})
target_compile_definitions(OpenglRender_vulkan_cereal PRIVATE -DVK_GOOGLE_gfxstream)
if (WIN32)
target_compile_definitions(OpenglRender_vulkan_cereal PRIVATE -DVK_USE_PLATFORM_WIN32_KHR)
endif()
target_link_libraries(
OpenglRender_vulkan_cereal
PUBLIC
{self.baseLibLinkName}
{self.vulkanHeaderTargetName}
PRIVATE
{self.utilsHeader})
target_include_directories(OpenglRender_vulkan_cereal
PUBLIC
.
PRIVATE
..
../..
../../../include)
"""
encoderInclude = f"""
#include "{self.guestBaseLibDirPrefix}/AndroidHealthMonitor.h"
#include "goldfish_vk_private_defs.h"
#include <memory>
namespace gfxstream {{
namespace guest {{
class IOStream;
}} // namespace guest
}} // namespace gfxstream
"""
encoderImplInclude = f"""
#include "EncoderDebug.h"
#include "IOStream.h"
#include "Resources.h"
#include "ResourceTracker.h"
#include "Validation.h"
#include "%s.h"
#include "{self.guestBaseLibDirPrefix}/AlignedBuf.h"
#include "{self.guestBaseLibDirPrefix}/BumpPool.h"
#include "{self.guestBaseLibDirPrefix}/synchronization/AndroidLock.h"
#include <cutils/properties.h>
#include "goldfish_vk_marshaling_guest.h"
#include "goldfish_vk_reserved_marshaling_guest.h"
#include "goldfish_vk_deepcopy_guest.h"
#include "goldfish_vk_counting_guest.h"
#include "goldfish_vk_private_defs.h"
#include "goldfish_vk_transform_guest.h"
#include <memory>
#include <optional>
#include <unordered_map>
#include <string>
#include <vector>
""" % VULKAN_STREAM_TYPE_GUEST
functableImplInclude = """
#include "VkEncoder.h"
#include "../OpenglSystemCommon/HostConnection.h"
#include "ResourceTracker.h"
#include "goldfish_vk_private_defs.h"
#include <log/log.h>
#include <cstring>
// Stuff we are not going to use but if included,
// will cause compile errors. These are Android Vulkan
// required extensions, but the approach will be to
// implement them completely on the guest side.
#undef VK_KHR_android_surface
#if defined(LINUX_GUEST_BUILD)
#undef VK_ANDROID_native_buffer
#endif
"""
marshalIncludeGuest = """
#include "goldfish_vk_marshaling_guest.h"
#include "goldfish_vk_private_defs.h"
#include "%s.h"
// Stuff we are not going to use but if included,
// will cause compile errors. These are Android Vulkan
// required extensions, but the approach will be to
// implement them completely on the guest side.
#undef VK_KHR_android_surface
#undef VK_ANDROID_external_memory_android_hardware_buffer
""" % VULKAN_STREAM_TYPE_GUEST
reservedmarshalIncludeGuest = """
#include "goldfish_vk_marshaling_guest.h"
#include "goldfish_vk_private_defs.h"
#include "%s.h"
// Stuff we are not going to use but if included,
// will cause compile errors. These are Android Vulkan
// required extensions, but the approach will be to
// implement them completely on the guest side.
#undef VK_KHR_android_surface
#undef VK_ANDROID_external_memory_android_hardware_buffer
""" % VULKAN_STREAM_TYPE_GUEST
reservedmarshalImplIncludeGuest = """
#include "Resources.h"
"""
vulkanStreamIncludeHost = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
#include "%s.h"
#include "{self.baseLibDirPrefix}/files/StreamSerializing.h"
""" % VULKAN_STREAM_TYPE
poolInclude = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
#include "{self.baseLibDirPrefix}/BumpPool.h"
using android::base::Allocator;
using android::base::BumpPool;
"""
handleMapInclude = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
#include "VulkanHandleMapping.h"
"""
transformIncludeGuest = """
#include "goldfish_vk_private_defs.h"
"""
transformInclude = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
#include "goldfish_vk_extension_structs.h"
"""
transformImplIncludeGuest = """
#include "ResourceTracker.h"
"""
transformImplInclude = """
#include "VkDecoderGlobalState.h"
"""
deepcopyInclude = """
#include "vk_util.h"
"""
poolIncludeGuest = f"""
#include "goldfish_vk_private_defs.h"
#include "{self.guestBaseLibDirPrefix}/BumpPool.h"
using gfxstream::guest::Allocator;
using gfxstream::guest::BumpPool;
// Stuff we are not going to use but if included,
// will cause compile errors. These are Android Vulkan
// required extensions, but the approach will be to
// implement them completely on the guest side.
#undef VK_KHR_android_surface
#undef VK_ANDROID_external_memory_android_hardware_buffer
"""
dispatchHeaderDefs = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
namespace gfxstream {{
namespace vk {{
struct VulkanDispatch;
}} // namespace vk
}} // namespace gfxstream
using DlOpenFunc = void* (void);
using DlSymFunc = void* (void*, const char*);
"""
extensionStructsInclude = f"""
{self.hostCommonExtraVulkanHeaders}
#include "goldfish_vk_private_defs.h"
"""
extensionStructsIncludeGuest = """
#include "vk_platform_compat.h"
#include "goldfish_vk_private_defs.h"
// Stuff we are not going to use but if included,
// will cause compile errors. These are Android Vulkan
// required extensions, but the approach will be to
// implement them completely on the guest side.
#undef VK_KHR_android_surface
#undef VK_ANDROID_external_memory_android_hardware_buffer
"""
commonCerealImplIncludes = """
#include "goldfish_vk_extension_structs.h"
#include "goldfish_vk_private_defs.h"
#include <string.h>
"""
commonCerealIncludesGuest = """
#include "vk_platform_compat.h"
"""
commonCerealImplIncludesGuest = """
#include "goldfish_vk_extension_structs_guest.h"
#include "goldfish_vk_private_defs.h"
#include <cstring>
"""
countingIncludes = """
#include "vk_platform_compat.h"
#include "goldfish_vk_private_defs.h"
"""
dispatchImplIncludes = """
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
"""
decoderSnapshotHeaderIncludes = f"""
#include <memory>
#include "{self.utilsHeaderDirPrefix}/GfxApiLogger.h"
#include "{self.baseLibDirPrefix}/HealthMonitor.h"
#include "common/goldfish_vk_private_defs.h"
"""
decoderSnapshotImplIncludes = f"""
#include "VulkanHandleMapping.h"
#include "VkDecoderGlobalState.h"
#include "VkReconstruction.h"
#include "{self.baseLibDirPrefix}/synchronization/Lock.h"
"""
decoderHeaderIncludes = f"""
#include "VkDecoderContext.h"
#include <memory>
namespace android {{
namespace base {{
class BumpPool;
}} // namespace android
}} // namespace base
"""
decoderImplIncludes = f"""
#include "common/goldfish_vk_marshaling.h"
#include "common/goldfish_vk_reserved_marshaling.h"
#include "common/goldfish_vk_private_defs.h"
#include "common/goldfish_vk_transform.h"
#include "{self.baseLibDirPrefix}/BumpPool.h"
#include "{self.baseLibDirPrefix}/system/System.h"
#include "{self.baseLibDirPrefix}/Tracing.h"
#include "{self.baseLibDirPrefix}/Metrics.h"
#include "render-utils/IOStream.h"
#include "host/FrameBuffer.h"
#include "host-common/feature_control.h"
#include "host-common/GfxstreamFatalError.h"
#include "host-common/logging.h"
#include "VkDecoderGlobalState.h"
#include "VkDecoderSnapshot.h"
#include "VulkanDispatch.h"
#include "%s.h"
#include <functional>
#include <optional>
#include <unordered_map>
""" % VULKAN_STREAM_TYPE
def createVkExtensionStructureTypePreamble(extensionName: str) -> str:
return f"""
#define {extensionName}_ENUM(type,id) \
((type)(1000000000 + (1000 * ({extensionName}_NUMBER - 1)) + (id)))
"""
self.guest_encoder_tag = "guest_encoder"
self.host_tag = "host"
default_guest_abs_encoder_destination = \
os.path.join(
os.getcwd(),
"..", "..",
"device", "generic", "goldfish-opengl",
"system", "vulkan_enc")
self.guest_abs_encoder_destination = \
envGetOrDefault("VK_CEREAL_GUEST_ENCODER_DIR",
default_guest_abs_encoder_destination)
default_host_abs_decoder_destination = \
os.path.join(
os.getcwd(),
"android", "android-emugl", "host",
"libs", "libOpenglRender", "vulkan")
self.host_abs_decoder_destination = \
envGetOrDefault("VK_CEREAL_HOST_DECODER_DIR",
default_host_abs_decoder_destination)
self.host_script_destination = envGetOrDefault("VK_CEREAL_HOST_SCRIPTS_DIR")
assert(self.host_script_destination is not None)
self.addGuestEncoderModule(
"VkEncoder",
extraHeader = encoderInclude,
extraImpl = encoderImplInclude)
self.addGuestEncoderModule("goldfish_vk_extension_structs_guest",
extraHeader=extensionStructsIncludeGuest)
self.addGuestEncoderModule("goldfish_vk_marshaling_guest",
extraHeader=commonCerealIncludesGuest + marshalIncludeGuest,
extraImpl=commonCerealImplIncludesGuest)
self.addGuestEncoderModule("goldfish_vk_reserved_marshaling_guest",
extraHeader=commonCerealIncludesGuest + reservedmarshalIncludeGuest,
extraImpl=commonCerealImplIncludesGuest + reservedmarshalImplIncludeGuest)
self.addGuestEncoderModule("goldfish_vk_deepcopy_guest",
extraHeader=commonCerealIncludesGuest + poolIncludeGuest,
extraImpl=commonCerealImplIncludesGuest + deepcopyInclude)
self.addGuestEncoderModule("goldfish_vk_counting_guest",
extraHeader=countingIncludes,
extraImpl=commonCerealImplIncludesGuest)
self.addGuestEncoderModule("goldfish_vk_transform_guest",
extraHeader=commonCerealIncludesGuest + transformIncludeGuest,
extraImpl=commonCerealImplIncludesGuest + transformImplIncludeGuest)
self.addGuestEncoderModule(
"vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
moduleName="vulkan_gfxstream_structure_type_guest", useNamespace=False,
suppressVulkanHeaders=True,
extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude)
self.addCppModule("common", "goldfish_vk_extension_structs",
extraHeader=extensionStructsInclude)
self.addCppModule("common", "goldfish_vk_marshaling",
extraHeader=vulkanStreamIncludeHost,
extraImpl=commonCerealImplIncludes)
self.addCppModule("common", "goldfish_vk_reserved_marshaling",
extraHeader=vulkanStreamIncludeHost,
extraImpl=commonCerealImplIncludes)
self.addCppModule("common", "goldfish_vk_deepcopy",
extraHeader=poolInclude,
extraImpl=commonCerealImplIncludes + deepcopyInclude)
self.addCppModule("common", "goldfish_vk_handlemap",
extraHeader=handleMapInclude,
extraImpl=commonCerealImplIncludes)
self.addCppModule("common", "goldfish_vk_dispatch",
extraHeader=dispatchHeaderDefs,
extraImpl=dispatchImplIncludes)
self.addCppModule("common", "goldfish_vk_transform",
extraHeader=transformInclude,
extraImpl=transformImplInclude)
self.addHostModule("VkDecoder",
extraHeader=decoderHeaderIncludes,
extraImpl=decoderImplIncludes,
useNamespace=False)
self.addHostModule("VkDecoderSnapshot",
extraHeader=decoderSnapshotHeaderIncludes,
extraImpl=decoderSnapshotImplIncludes,
useNamespace=False)
self.addHostModule("VkSubDecoder",
extraHeader="",
extraImpl="",
useNamespace=False,
implOnly=True)
self.addModule(cereal.PyScript(self.host_tag, "vulkan_printer", customAbsDir=Path(
self.host_script_destination) / "print_gfx_logs"), moduleName="ApiLogDecoder")
self.addHostModule(
"vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
moduleName="vulkan_gfxstream_structure_type_host", useNamespace=False,
suppressVulkanHeaders=True,
extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
self.addHostModule(
"vk_android_native_buffer_structure_type", headerOnly=True, suppressFeatureGuards=True,
useNamespace=False, suppressVulkanHeaders=True,
extraHeader=createVkExtensionStructureTypePreamble('VK_ANDROID_NATIVE_BUFFER'))
self.addWrapper(cereal.VulkanEncoder, "VkEncoder")
self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest")
self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling_guest", variant = "guest")
self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling_guest", variant = "guest")
self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy_guest")
self.addWrapper(cereal.VulkanCounting, "goldfish_vk_counting_guest")
self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest")
self.addWrapper(cereal.VulkanFuncTable, "func_table")
self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs")
self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling")
self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling", variant = "host")
self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy")
self.addWrapper(cereal.VulkanHandleMap, "goldfish_vk_handlemap")
self.addWrapper(cereal.VulkanDispatch, "goldfish_vk_dispatch")
self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform", resourceTrackerTypeName="VkDecoderGlobalState")
self.addWrapper(cereal.VulkanDecoder, "VkDecoder")
self.addWrapper(cereal.VulkanDecoderSnapshot, "VkDecoderSnapshot")
self.addWrapper(cereal.VulkanSubDecoder, "VkSubDecoder")
self.addWrapper(cereal.ApiLogDecoder, "ApiLogDecoder")
self.addWrapper(cereal.VulkanGfxstreamStructureType,
"vulkan_gfxstream_structure_type_guest")
self.addWrapper(cereal.VulkanGfxstreamStructureType, "vulkan_gfxstream_structure_type_host")
self.addWrapper(cereal.VulkanAndroidNativeBufferStructureType,
"vk_android_native_buffer_structure_type")
self.guestAndroidMkCppFiles = ""
self.hostCMakeCppFiles = ""
self.hostDecoderCMakeCppFiles = ""
def addSrcEntry(m):
mkSrcEntry = m.getMakefileSrcEntry()
cmakeSrcEntry = m.getCMakeSrcEntry()
if m.directory == self.guest_encoder_tag:
self.guestAndroidMkCppFiles += mkSrcEntry
elif m.directory == self.host_tag:
self.hostDecoderCMakeCppFiles += cmakeSrcEntry
else:
self.hostCMakeCppFiles += cmakeSrcEntry
self.forEachModule(addSrcEntry)
def addGuestEncoderModule(
self, basename, extraHeader="", extraImpl="", useNamespace=True, headerOnly=False,
suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False):
if not os.path.exists(self.guest_abs_encoder_destination):
print("Path [%s] not found (guest encoder path), skipping" % self.guest_abs_encoder_destination)
return
self.addCppModule(self.guest_encoder_tag, basename, extraHeader=extraHeader,
extraImpl=extraImpl, customAbsDir=self.guest_abs_encoder_destination,
useNamespace=useNamespace, headerOnly=headerOnly,
suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
suppressVulkanHeaders=suppressVulkanHeaders)
def addHostModule(
self, basename, extraHeader="", extraImpl="", useNamespace=True, implOnly=False,
suppress=False, headerOnly=False, suppressFeatureGuards=False, moduleName=None,
suppressVulkanHeaders=False):
if not os.path.exists(self.host_abs_decoder_destination):
print("Path [%s] not found (host encoder path), skipping" %
self.host_abs_decoder_destination)
return
if not suppressVulkanHeaders:
extraHeader = self.hostCommonExtraVulkanHeaders + '\n' + extraHeader
self.addCppModule(
self.host_tag, basename, extraHeader=extraHeader, extraImpl=extraImpl,
customAbsDir=self.host_abs_decoder_destination, useNamespace=useNamespace,
implOnly=implOnly, suppress=suppress, headerOnly=headerOnly,
suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
suppressVulkanHeaders=suppressVulkanHeaders)
def addModule(self, module, moduleName=None):
if moduleName is None:
moduleName = module.basename
self.moduleList.append(moduleName)
self.modules[moduleName] = module
def addCppModule(
self, directory, basename, extraHeader="", extraImpl="", customAbsDir=None,
useNamespace=True, implOnly=False, suppress=False, headerOnly=False,
suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False):
module = cereal.Module(
directory, basename, customAbsDir=customAbsDir, suppress=suppress, implOnly=implOnly,
headerOnly=headerOnly, suppressFeatureGuards=suppressFeatureGuards)
self.addModule(module, moduleName=moduleName)
module.headerPreamble = copyrightHeader
module.headerPreamble += \
autogeneratedHeaderTemplate % \
(basename, "(header) generated by %s" % banner_command(sys.argv))
module.headerPreamble += "#pragma once\n"
if (not suppressVulkanHeaders):
module.headerPreamble += "#include <vulkan/vulkan.h>\n"
module.headerPreamble += '#include "vulkan_gfxstream.h"\n'
module.headerPreamble += extraHeader + '\n'
if useNamespace:
module.headerPreamble += namespaceBegin
module.implPreamble = copyrightHeader
module.implPreamble += \
autogeneratedHeaderTemplate % \
(basename, "(impl) generated by %s" % \
banner_command(sys.argv))
if not implOnly:
module.implPreamble += '\n#include "%s.h"' % \
(basename)
module.implPreamble += extraImpl
if useNamespace:
module.implPreamble += namespaceBegin
module.implPostamble += namespaceEnd
module.headerPostamble += namespaceEnd
def addWrapper(self, moduleType, moduleName, **kwargs):
if moduleName not in self.modules:
print(f'Unknown module: {moduleName}. All known modules are: {", ".join(self.modules)}.')
return
self.wrappers.append(
moduleType(
self.modules[moduleName],
self.typeInfo, **kwargs))
def forEachModule(self, func):
for moduleName in self.moduleList:
func(self.modules[moduleName])
def forEachWrapper(self, func, supportedWrappers):
for wrapper in self.wrappers:
if supportedWrappers is None:
func(wrapper)
elif type(wrapper) in supportedWrappers:
func(wrapper)
## Overrides####################################################################
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
write(self.host_cmake_generator(self.hostCMakeCppFiles),
file = self.outFile)
self.forEachModule(lambda m: m.begin(self.genOpts.directory))
self.forEachWrapper(lambda w: w.onBegin(), None)
def endFile(self):
OutputGenerator.endFile(self)
self.typeInfo.onEnd()
self.forEachWrapper(lambda w: w.onEnd(), None)
self.forEachModule(lambda m: m.end())
def beginFeature(self, interface, emit):
# Start processing in superclass
OutputGenerator.beginFeature(self, interface, emit)
for supportedFeature in SUPPORTED_FEATURES:
if self.featureName == supportedFeature:
self.featureSupported = True
if self.featureSupported == False:
return
self.supportedWrappers = SUPPORTED_WRAPPERS.get(self.featureName)
self.typeInfo.onBeginFeature(self.featureName, self.featureType)
self.forEachModule(
lambda m: m.appendHeader("#ifdef %s\n" % self.featureName)
if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
self.forEachModule(
lambda m: m.appendImpl("#ifdef %s\n" % self.featureName)
if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
self.forEachWrapper(lambda w: w.onBeginFeature(self.featureName, self.featureType), self.supportedWrappers)
# functable needs to understand the feature type (device vs instance) of each cmd
for features in interface.findall('require'):
for c in features.findall('command'):
self.forEachWrapper(lambda w: w.onFeatureNewCmd(c.get('name')), self.supportedWrappers)
def endFeature(self):
# Finish processing in superclass
OutputGenerator.endFeature(self)
if self.featureSupported == False:
return
self.featureSupported = False
self.typeInfo.onEndFeature()
self.forEachModule(lambda m: m.appendHeader("#endif\n") if isinstance(
m, cereal.Module) and not m.suppressFeatureGuards else None)
self.forEachModule(lambda m: m.appendImpl("#endif\n") if isinstance(
m, cereal.Module) and not m.suppressFeatureGuards else None)
self.forEachWrapper(lambda w: w.onEndFeature(), self.supportedWrappers)
def genType(self, typeinfo: TypeInfo, name, alias):
OutputGenerator.genType(self, typeinfo, name, alias)
if self.featureSupported == False and name == "int":
self.typeInfo.onGenType(typeinfo, name, alias)
return
if self.featureSupported == False and name == "int64_t":
self.typeInfo.onGenType(typeinfo, name, alias)
return
if self.featureSupported == False and name == "double":
self.typeInfo.onGenType(typeinfo, name, alias)
return
if self.featureSupported == False and name == "VkPresentScalingFlagsEXT":
self.typeInfo.onGenType(typeinfo, name, alias)
return
if self.featureSupported == False and name == "VkPresentGravityFlagsEXT":
self.typeInfo.onGenType(typeinfo, name, alias)
return
if self.featureSupported == False:
return
self.typeInfo.onGenType(typeinfo, name, alias)
self.forEachWrapper(lambda w: w.onGenType(typeinfo, name, alias), self.supportedWrappers)
def genStruct(self, typeinfo, typeName, alias):
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
if self.featureSupported == False:
return
self.typeInfo.onGenStruct(typeinfo, typeName, alias)
self.forEachWrapper(lambda w: w.onGenStruct(typeinfo, typeName, alias), self.supportedWrappers)
def genGroup(self, groupinfo: GroupInfo, groupName, alias = None):
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
if self.featureSupported == False:
return
self.typeInfo.onGenGroup(groupinfo, groupName, alias)
self.forEachWrapper(lambda w: w.onGenGroup(groupinfo, groupName, alias), self.supportedWrappers)
def genEnum(self, enuminfo: EnumInfo, name, alias):
OutputGenerator.genEnum(self, enuminfo, name, alias)
if self.featureSupported == False:
return
self.typeInfo.onGenEnum(enuminfo, name, alias)
self.forEachWrapper(lambda w: w.onGenEnum(enuminfo, name, alias), self.supportedWrappers)
def genCmd(self, cmdinfo, name, alias):
OutputGenerator.genCmd(self, cmdinfo, name, alias)
if self.featureSupported == False:
return
self.typeInfo.onGenCmd(cmdinfo, name, alias)
self.forEachWrapper(lambda w: w.onGenCmd(cmdinfo, name, alias), self.supportedWrappers)