unplugged-system/external/gfxstream-protocols/registry/vulkan/scripts/cereal/subdecode.py

396 lines
15 KiB
Python
Raw Normal View History

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,
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,
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,
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,
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,
"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())