Pass VkSnapshotApiCallInfo-s through VkDecoderGlobalState

... so that `VkDecoderGlobalState` can append additional information
needed for snapshotting. Specifically, `VkDecoderGlobalState` may create
additional boxed handles that are not visible directly in the API surface.
For example, `vkCreateDevice()` creates boxed handles for the `VkQueue`-s
and `vkCreateDescriptorPool()` creates boxed handles for pre-allocated
`VkDescriptorSets`. These boxed handles are not recoverable from the API
for `vkCreateDevice()` nor `vkCreateDescriptorPool()` directly. This was
previously worked around by just sticking the extra boxed handles in
`VkReconstruction::mExtraHandlesForNextApi` but this is not thread safe.
Instead, let's give `VkDecoderGlobalState` and `VkDecoderSnapshot` exclusive
access to individual `VkSnapshotApiCallInfo` objects.

Reviewed-by: Marcin Radomski <dextero@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33018>
This commit is contained in:
Jason Macnak
2024-12-10 16:22:22 -08:00
committed by Marge Bot
parent 3c03bae20c
commit a07eb2cef0
4 changed files with 78 additions and 34 deletions

View File

@@ -29,6 +29,8 @@ DELAYED_DECODER_DELETE_DICT_ENTRIES = [
"vkDestroyShaderModule",
]
SNAPSHOT_API_CALL_INFO_VARNAME = "snapshotApiCallInfo"
global_state_prefix = "m_state->on_"
decoder_decl_preamble = """
@@ -77,7 +79,8 @@ public:
m_boxedHandleUnwrapAndDeleteMapping(m_state),
m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state),
m_prevSeqno(std::nullopt),
m_queueSubmitWithCommandsEnabled(m_state->getFeatures().VulkanQueueSubmitWithCommands.enabled) {}
m_queueSubmitWithCommandsEnabled(m_state->getFeatures().VulkanQueueSubmitWithCommands.enabled),
m_snapshotsEnabled(m_state->snapshotsEnabled()) {}
%s* stream() { return &m_vkStream; }
VulkanMemReadingStream* readStream() { return &m_vkMemReadingStream; }
@@ -103,6 +106,7 @@ private:
BoxedHandleUnwrapAndDeletePreserveBoxedMapping m_boxedHandleUnwrapAndDeletePreserveBoxedMapping;
std::optional<uint32_t> m_prevSeqno;
bool m_queueSubmitWithCommandsEnabled = false;
const bool m_snapshotsEnabled = false;
};
VkDecoder::VkDecoder() :
@@ -358,7 +362,7 @@ def emit_global_state_wrapped_call(api, cgen, context):
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))
customParams = ["&m_pool", SNAPSHOT_API_CALL_INFO_VARNAME] + list(map(lambda p: p.paramName, api.parameters))
if context:
customParams += ["context"]
cgen.vkApiCall(api, customPrefix=global_state_prefix, \
@@ -461,9 +465,10 @@ def emit_seqno_incr(api, cgen):
def emit_snapshot(typeInfo, api, cgen):
additionalParams = [ \
makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "&m_pool"),
makeVulkanTypeSimple(True, "VkSnapshotApiCallInfo", 1, SNAPSHOT_API_CALL_INFO_VARNAME),
makeVulkanTypeSimple(True, "uint8_t", 1, "packet"),
makeVulkanTypeSimple(False, "size_t", 0, "packetLen"),
makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "&m_pool"),
]
retTypeName = api.getRetTypeExpr()
@@ -487,7 +492,7 @@ def emit_snapshot(typeInfo, api, cgen):
api.withCustomReturnType(makeVulkanTypeSimple(False, "void", 0, "void")). \
withCustomParameters(customParams)
cgen.beginIf("m_state->snapshotsEnabled()")
cgen.beginIf("m_snapshotsEnabled")
cgen.vkApiCall(apiForSnapshot, customPrefix="m_state->snapshot()->")
cgen.endIf()
@@ -912,6 +917,13 @@ size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream,
}
""")
self.cgen.line("""
VkSnapshotApiCallInfo* %s = nullptr;
if (m_snapshotsEnabled) {
%s = m_state->snapshot()->createApiCallInfo();
}
""" % (SNAPSHOT_API_CALL_INFO_VARNAME, SNAPSHOT_API_CALL_INFO_VARNAME))
self.cgen.line("""
gfx_logger.recordCommandExecution();
""")
@@ -958,6 +970,12 @@ size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream,
self.cgen.endBlock() # switch stmt
self.cgen.line("""
if (m_snapshotsEnabled) {
m_state->snapshot()->destroyApiCallInfoIfUnused(%s);
}
""" % (SNAPSHOT_API_CALL_INFO_VARNAME))
self.cgen.stmt("ptr += packetLen")
self.cgen.stmt("vkStream->clearPool()")
self.cgen.endBlock() # while loop

View File

@@ -23,6 +23,9 @@ class Stream;
} // namespace base {
} // namespace android {
namespace gfxstream {
namespace vk {
class VkDecoderSnapshot {
public:
VkDecoderSnapshot();
@@ -31,7 +34,9 @@ public:
void save(android::base::Stream* stream);
void load(android::base::Stream* stream, emugl::GfxApiLogger& gfx_logger,
emugl::HealthMonitor<>* healthMonitor);
void createExtraHandlesForNextApi(const uint64_t* created, uint32_t count);
VkSnapshotApiCallInfo* createApiCallInfo();
void destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info);
"""
decoder_snapshot_decl_postamble = """
@@ -40,14 +45,19 @@ private:
std::unique_ptr<Impl> mImpl;
};
} // namespace vk
} // namespace gfxstream
"""
decoder_snapshot_impl_preamble ="""
using namespace gfxstream::vk;
using emugl::GfxApiLogger;
using emugl::HealthMonitor;
namespace gfxstream {
namespace vk {
class VkDecoderSnapshot::Impl {
public:
Impl() { }
@@ -61,9 +71,14 @@ public:
mReconstruction.load(stream, gfx_logger, healthMonitor);
}
void createExtraHandlesForNextApi(const uint64_t* created, uint32_t count) {
mLock.lock();
mReconstruction.createExtraHandlesForNextApi(created, count);
VkSnapshotApiCallInfo* createApiCallInfo() {
android::base::AutoLock lock(mLock);
return mReconstruction.createApiCallInfo();
}
void destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info) {
android::base::AutoLock lock(mLock);
return mReconstruction.destroyApiCallInfoIfUnused(info);
}
"""
@@ -85,13 +100,25 @@ void VkDecoderSnapshot::load(android::base::Stream* stream, GfxApiLogger& gfx_lo
mImpl->load(stream, gfx_logger, healthMonitor);
}
void VkDecoderSnapshot::createExtraHandlesForNextApi(const uint64_t* created, uint32_t count) {
mImpl->createExtraHandlesForNextApi(created, count);
VkSnapshotApiCallInfo* VkDecoderSnapshot::createApiCallInfo() {
return mImpl->createApiCallInfo();
}
void VkDecoderSnapshot::destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info) {
mImpl->destroyApiCallInfoIfUnused(info);
}
VkDecoderSnapshot::~VkDecoderSnapshot() = default;
"""
decoder_snapshot_namespace_postamble = """
} // namespace vk
} // namespace gfxstream
"""
AUXILIARY_SNAPSHOT_API_BASE_PARAM_COUNT = 3
AUXILIARY_SNAPSHOT_API_PARAM_NAMES = [
@@ -236,14 +263,13 @@ def api_special_implementation_vkBindImageMemory2(api, cgen):
(childObj, "1", childObj))
cgen.endFor()
cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
cgen.stmt("mReconstruction.setApiTrace(apiInfo, snapshotTraceBegin, snapshotTraceBytes)")
cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
cgen.line("// Note: the implementation does not work with bindInfoCount > 1");
cgen.beginFor("uint32_t i = 0", "i < bindInfoCount", "++i")
cgen.stmt("%s boxed_%s = unboxed_to_boxed_non_dispatchable_%s(pBindInfos[i].image)"
% (childType, childType, childType))
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)&{childObj}, {1}, apiHandle, VkReconstruction::BOUND_MEMORY)")
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)&{childObj}, {1}, apiCallHandle, VkReconstruction::BOUND_MEMORY)")
cgen.endFor()
apiSpecialImplementation = {
@@ -359,14 +385,13 @@ def emit_impl(typeInfo, api, cgen):
if api.name in specialCaseDependencyExtractors:
specialCaseDependencyExtractors[api.name](p, boxed_access, lenExpr, api, cgen)
cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
cgen.stmt("mReconstruction.setApiTrace(apiInfo, snapshotTraceBegin, snapshotTraceBytes)")
cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*){boxed_access}, {lenExpr}, apiHandle, {get_target_state(api, p)})")
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*){boxed_access}, {lenExpr}, apiCallHandle, {get_target_state(api, p)})")
if p.isCreatedBy(api):
cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiHandle, (const uint64_t*)%s, %s)" % (boxed_access, lenExpr))
cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiCallHandle, (const uint64_t*)%s, %s)" % (boxed_access, lenExpr))
if lenAccessGuard is not None:
cgen.endIf()
if isCreateExtraHandleApi:
@@ -391,20 +416,18 @@ def emit_impl(typeInfo, api, cgen):
cgen.endIf();
cgen.stmt("uint64_t handle = m_state->newGlobalVkGenericHandle()")
cgen.stmt("mReconstruction.addHandles((const uint64_t*)(&handle), 1)");
cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
cgen.stmt("mReconstruction.setApiTrace(apiInfo, snapshotTraceBegin, snapshotTraceBytes)")
cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
if api.name in specialCaseDependencyExtractors:
specialCaseDependencyExtractors[api.name](p, None, None, api, cgen)
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)(&handle), 1, apiHandle, {get_target_state(api, p)})")
cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiHandle, (const uint64_t*)(&handle), 1)")
cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)(&handle), 1, apiCallHandle, {get_target_state(api, p)})")
cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiCallHandle, (const uint64_t*)(&handle), 1)")
elif is_modify_operation(api, p) or is_clear_modifier_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, snapshotTraceBegin, snapshotTraceBytes)")
cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
if lenAccessGuard is not None:
cgen.beginIf(lenAccessGuard)
cgen.beginFor("uint32_t i = 0", "i < %s" % lenExpr, "++i")
@@ -414,7 +437,7 @@ def emit_impl(typeInfo, api, cgen):
cgen.line("// %s is already boxed, no need to box again" % p.paramName)
cgen.stmt("%s boxed = %s(%s[i])" % (p.typeName, p.typeName, access))
if is_modify_operation(api, p):
cgen.stmt("mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiHandle)")
cgen.stmt("mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiCallHandle)")
else: # is clear modifier operation
cgen.stmt("mReconstruction.forEachHandleClearModifyApi((const uint64_t*)(&boxed), 1)")
cgen.endFor()
@@ -453,9 +476,11 @@ class VulkanDecoderSnapshot(VulkanWrapperGenerator):
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"),]
makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "pool"),
makeVulkanTypeSimple(False, "VkSnapshotApiCallInfo", 1, "apiCallInfo"),
makeVulkanTypeSimple(True, "uint8_t", 1, "apiCallPacket"),
makeVulkanTypeSimple(False, "size_t", 0, "apiCallPacketSize"),
]
if api.retType.typeName != "void":
additionalParams.append( \
@@ -495,4 +520,4 @@ class VulkanDecoderSnapshot(VulkanWrapperGenerator):
self.cgenImpl.line("#endif")
self.module.appendImpl(self.cgenImpl.swapCode())
self.module.appendImpl(decoder_snapshot_namespace_postamble)

View File

@@ -268,7 +268,7 @@ def emit_dispatch_call(api, cgen):
def emit_global_state_wrapped_call(api, cgen, context=False):
customParams = ["pool", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \
customParams = ["pool", "nullptr", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \
list(map(lambda p: p.paramName, api.parameters[1:]))
if context:
customParams += ["context"];

View File

@@ -485,6 +485,7 @@ using DlSymFunc = void* (void*, const char*);
decoderSnapshotHeaderIncludes = f"""
#include <memory>
#include "VkSnapshotApiCall.h"
#include "{self.utilsHeaderDirPrefix}/GfxApiLogger.h"
#include "{self.baseLibDirPrefix}/HealthMonitor.h"
#include "goldfish_vk_private_defs.h"