mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-13 05:20:45 +00:00
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:
committed by
Baldur Karlsson
parent
e169df5d88
commit
14d74e4dd3
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user