mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-25 03:58:19 +02:00
Sometimes guest renders to an AHB without calling vkQueueSignalReleaseImageANDROIDAsyncGOOGLE. This would result in the color buffer not being updated from Vulkan. This commit tracks the situation that AHB is rendered to, and copies its content to color buffer. Note that it adds extra wait, which could hurt performance. 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>
408 lines
15 KiB
Python
408 lines
15 KiB
Python
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,
|
|
"vkCmdBeginRenderPass" : emit_global_state_wrapped_decoding,
|
|
"vkCmdBeginRenderPass2" : emit_global_state_wrapped_decoding,
|
|
"vkCmdBeginRenderPass2KHR" : 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())
|