Improve tracking of MTLDrawables (swapchains)

Serialize the presented texture (presentedImage) as part of "presentDrawable" serialization.
Use the present texture resource ID in the action name ie. "presentDrawable(Texture 23219)"
Track the most recently presented image and use that in SystemChunk::CaptureEnd if the PresentedImage serialized data is empty resource.
Track the CAMetalDrawable's created via the hooked CAMetalLayer::nextDrawable() method.

Implements TODO in WrappedMTLCommandBuffer::presentDrawable
"remove the (CA::MetalDrawable*) cast. Associate created texture and layer in hooked nextDrawable with MTL::Drawable*"
This commit is contained in:
Jake Turner
2022-09-04 06:49:42 +01:00
committed by Baldur Karlsson
parent e169df5d88
commit 14d74e4dd3
5 changed files with 94 additions and 27 deletions
+35 -18
View File
@@ -149,42 +149,59 @@ WrappedMTLRenderCommandEncoder *WrappedMTLCommandBuffer::renderCommandEncoderWit
}
template <typename SerialiserType>
bool WrappedMTLCommandBuffer::Serialise_presentDrawable(SerialiserType &ser, MTL::Drawable *drawable)
bool WrappedMTLCommandBuffer::Serialise_presentDrawable(SerialiserType &ser,
WrappedMTLTexture *presentedImage)
{
SERIALISE_ELEMENT_LOCAL(CommandBuffer, this);
SERIALISE_ELEMENT(presentedImage).Important();
SERIALISE_CHECK_READ_ERRORS();
// TODO: implement RD MTL replay
if(IsReplayingAndReading())
{
if(IsLoading(m_State))
{
AddEvent();
ActionDescription action;
ResourceId presentedImageId = GetResourceManager()->GetOriginalID(GetResID(presentedImage));
action.customName = StringFormat::Fmt("presentDrawable(%s)", ToStr(presentedImageId).c_str());
action.flags |= ActionFlags::Present;
action.copyDestination = presentedImageId;
m_Device->SetLastPresentedIamge(presentedImageId);
AddAction(action);
}
}
return true;
}
void WrappedMTLCommandBuffer::presentDrawable(MTL::Drawable *drawable)
{
// TODO: remove the (CA::MetalDrawable*) cast. Associate created texture
// in hooked nextDrawable with MTL::Drawable* and CA::MetalLayer*
CA::MetalDrawable *mtlDrawable = (CA::MetalDrawable *)(drawable);
// To avoid metal assert about accessing drawable texture after calling present
MTL::Texture *mtlBackBuffer = mtlDrawable->texture();
SERIALISE_TIME_CALL(Unwrap(this)->presentDrawable(drawable));
if(IsCaptureMode(m_State))
{
Chunk *chunk = NULL;
MetalDrawableInfo info = m_Device->UnregisterDrawableInfo(drawable);
WrappedMTLTexture *presentedImage = info.texture;
if(presentedImage)
{
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CHUNK(MetalChunk::MTLCommandBuffer_presentDrawable);
Serialise_presentDrawable(ser, drawable);
chunk = scope.Get();
Chunk *chunk = NULL;
{
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CHUNK(MetalChunk::MTLCommandBuffer_presentDrawable);
Serialise_presentDrawable(ser, presentedImage);
chunk = scope.Get();
}
MetalResourceRecord *bufferRecord = GetRecord(this);
bufferRecord->AddChunk(chunk);
bufferRecord->cmdInfo->presented = true;
bufferRecord->cmdInfo->outputLayer = info.mtlLayer;
bufferRecord->cmdInfo->backBuffer = presentedImage;
}
else
{
RDCERR("Ignoring presentDrawable on untracked MTLDrawable");
}
MetalResourceRecord *bufferRecord = GetRecord(this);
bufferRecord->AddChunk(chunk);
bufferRecord->cmdInfo->presented = true;
bufferRecord->cmdInfo->outputLayer = mtlDrawable->layer();
bufferRecord->cmdInfo->backBuffer = GetWrapped(mtlBackBuffer);
}
else
{
@@ -309,7 +326,7 @@ INSTANTIATE_FUNCTION_WITH_RETURN_SERIALISED(WrappedMTLCommandBuffer,
renderCommandEncoderWithDescriptor,
RDMTL::RenderPassDescriptor &descriptor);
INSTANTIATE_FUNCTION_SERIALISED(WrappedMTLCommandBuffer, void, presentDrawable,
MTL::Drawable *drawable);
WrappedMTLTexture *presentedImage);
INSTANTIATE_FUNCTION_SERIALISED(WrappedMTLCommandBuffer, void, commit);
INSTANTIATE_FUNCTION_SERIALISED(WrappedMTLCommandBuffer, void, enqueue);
INSTANTIATE_FUNCTION_SERIALISED(WrappedMTLCommandBuffer, void, waitUntilCompleted);
@@ -41,7 +41,9 @@ public:
DECLARE_FUNCTION_WITH_RETURN_SERIALISED(WrappedMTLRenderCommandEncoder *,
renderCommandEncoderWithDescriptor,
RDMTL::RenderPassDescriptor &descriptor);
DECLARE_FUNCTION_SERIALISED(void, presentDrawable, MTL::Drawable *drawable);
void presentDrawable(MTL::Drawable *drawable);
template <typename SerialiserType>
bool Serialise_presentDrawable(SerialiserType &ser, WrappedMTLTexture *presentedImage);
DECLARE_FUNCTION_SERIALISED(void, commit);
DECLARE_FUNCTION_SERIALISED(void, enqueue);
DECLARE_FUNCTION_SERIALISED(void, waitUntilCompleted);
+31 -3
View File
@@ -442,8 +442,8 @@ bool WrappedMTLDevice::ProcessChunk(ReadSerialiser &ser, MetalChunk chunk)
SERIALISE_CHECK_READ_ERRORS();
// TODO: handle null PresentedImage
// TODO: Track most recently presented texture in Serialise_presentDrawable
if(PresentedImage != ResourceId())
m_LastPresentedImage = PresentedImage;
if(IsLoading(m_State))
{
@@ -452,7 +452,7 @@ bool WrappedMTLDevice::ProcessChunk(ReadSerialiser &ser, MetalChunk chunk)
ActionDescription action;
action.customName = "End of Capture";
action.flags |= ActionFlags::Present;
action.copyDestination = PresentedImage;
action.copyDestination = m_LastPresentedImage;
AddAction(action);
}
return true;
@@ -1029,6 +1029,34 @@ void WrappedMTLDevice::UnregisterMetalLayer(CA::MetalLayer *mtlLayer)
RenderDoc::Inst().RemoveFrameCapturer(devWnd);
}
void WrappedMTLDevice::RegisterDrawableInfo(CA::MetalDrawable *caMtlDrawable)
{
MetalDrawableInfo drawableInfo;
drawableInfo.mtlLayer = caMtlDrawable->layer();
drawableInfo.texture = GetWrapped(caMtlDrawable->texture());
SCOPED_LOCK(m_CaptureDrawablesLock);
RDCASSERTEQUAL(m_CaptureDrawableInfos.find(caMtlDrawable), m_CaptureDrawableInfos.end());
m_CaptureDrawableInfos[caMtlDrawable] = drawableInfo;
}
MetalDrawableInfo WrappedMTLDevice::UnregisterDrawableInfo(MTL::Drawable *mtlDrawable)
{
MetalDrawableInfo drawableInfo;
{
SCOPED_LOCK(m_CaptureDrawablesLock);
auto it = m_CaptureDrawableInfos.find(mtlDrawable);
if(it != m_CaptureDrawableInfos.end())
{
drawableInfo = it->second;
m_CaptureDrawableInfos.erase(it);
return drawableInfo;
}
}
drawableInfo.mtlLayer = NULL;
drawableInfo.texture = NULL;
return drawableInfo;
}
MetalInitParams::MetalInitParams()
{
memset(this, 0, sizeof(MetalInitParams));
+8 -5
View File
@@ -97,20 +97,23 @@ WrappedMTLDevice::WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId)
IMP WrappedMTLDevice::g_real_CAMetalLayer_nextDrawable;
uint64_t WrappedMTLDevice::g_nextDrawableTLSSlot;
MTL::Drawable *hooked_CAMetalLayer_nextDrawable(id self, SEL _cmd)
CA::MetalDrawable *hooked_CAMetalLayer_nextDrawable(id self, SEL _cmd)
{
CA::MetalLayer *mtlLayer = (CA::MetalLayer *)self;
MTL::Device *mtlDevice = mtlLayer->device();
WrappedMTLDevice *device = GetWrapped(mtlDevice);
RDCASSERT(object_getClass(mtlDevice) == objc_getClass("ObjCBridgeMTLDevice"));
GetWrapped(mtlDevice)->RegisterMetalLayer(mtlLayer);
device->RegisterMetalLayer(mtlLayer);
mtlLayer->setFramebufferOnly(false);
RDCASSERTEQUAL(Threading::GetTLSValue(WrappedMTLDevice::g_nextDrawableTLSSlot), 0);
Threading::SetTLSValue(WrappedMTLDevice::g_nextDrawableTLSSlot, (void *)(uintptr_t) true);
MTL::Drawable *drawable =
((MTL::Drawable * (*)(id, SEL))WrappedMTLDevice::g_real_CAMetalLayer_nextDrawable)(self, _cmd);
CA::MetalDrawable *caMtlDrawable =
((CA::MetalDrawable * (*)(id, SEL))WrappedMTLDevice::g_real_CAMetalLayer_nextDrawable)(self,
_cmd);
device->RegisterDrawableInfo(caMtlDrawable);
Threading::SetTLSValue(WrappedMTLDevice::g_nextDrawableTLSSlot, (void *)(uintptr_t) false);
return drawable;
return caMtlDrawable;
}
void WrappedMTLDevice::MTLHookObjcMethods()
+17
View File
@@ -31,6 +31,12 @@
class WrappedMTLDevice;
class MetalReplay;
struct MetalDrawableInfo
{
CA::MetalLayer *mtlLayer;
WrappedMTLTexture *texture;
};
class MetalCapturer : public IFrameCapturer
{
public:
@@ -131,6 +137,9 @@ public:
void RegisterMetalLayer(CA::MetalLayer *mtlLayer);
void UnregisterMetalLayer(CA::MetalLayer *mtlLayer);
void RegisterDrawableInfo(CA::MetalDrawable *caMtlDrawable);
MetalDrawableInfo UnregisterDrawableInfo(MTL::Drawable *mtlDrawable);
void AddEvent();
void AddAction(const ActionDescription &a);
@@ -143,6 +152,11 @@ public:
DerivedResource(GetResID(parent), child);
}
void SetLastPresentedIamge(ResourceId lastPresentedImage)
{
m_LastPresentedImage = lastPresentedImage;
}
enum
{
TypeEnum = eResDevice
@@ -177,6 +191,7 @@ private:
MTL::ResourceOptions options);
MetalResourceManager *m_ResourceManager = NULL;
ResourceId m_LastPresentedImage;
// Dummy objects used for serialisation replay
WrappedMTLBuffer *m_DummyBuffer = NULL;
@@ -194,6 +209,8 @@ private:
Threading::CriticalSection m_CaptureOutputLayersLock;
std::unordered_set<CA::MetalLayer *> m_CaptureOutputLayers;
WrappedMTLTexture *m_CapturedBackbuffer = NULL;
Threading::CriticalSection m_CaptureDrawablesLock;
rdcflatmap<MTL::Drawable *, MetalDrawableInfo> m_CaptureDrawableInfos;
CaptureState m_State;
bool m_AppControlledCapture = false;