diff --git a/renderdoc/driver/metal/metal_command_buffer.cpp b/renderdoc/driver/metal/metal_command_buffer.cpp index f3b7e22cb..5ade3091e 100644 --- a/renderdoc/driver/metal/metal_command_buffer.cpp +++ b/renderdoc/driver/metal/metal_command_buffer.cpp @@ -149,42 +149,59 @@ WrappedMTLRenderCommandEncoder *WrappedMTLCommandBuffer::renderCommandEncoderWit } template -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); diff --git a/renderdoc/driver/metal/metal_command_buffer.h b/renderdoc/driver/metal/metal_command_buffer.h index 6ad1b121e..a757113ed 100644 --- a/renderdoc/driver/metal/metal_command_buffer.h +++ b/renderdoc/driver/metal/metal_command_buffer.h @@ -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 + bool Serialise_presentDrawable(SerialiserType &ser, WrappedMTLTexture *presentedImage); DECLARE_FUNCTION_SERIALISED(void, commit); DECLARE_FUNCTION_SERIALISED(void, enqueue); DECLARE_FUNCTION_SERIALISED(void, waitUntilCompleted); diff --git a/renderdoc/driver/metal/metal_core.cpp b/renderdoc/driver/metal/metal_core.cpp index 31126f263..3ad78646c 100644 --- a/renderdoc/driver/metal/metal_core.cpp +++ b/renderdoc/driver/metal/metal_core.cpp @@ -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)); diff --git a/renderdoc/driver/metal/metal_device.cpp b/renderdoc/driver/metal/metal_device.cpp index d0230a643..30119d66b 100644 --- a/renderdoc/driver/metal/metal_device.cpp +++ b/renderdoc/driver/metal/metal_device.cpp @@ -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() diff --git a/renderdoc/driver/metal/metal_device.h b/renderdoc/driver/metal/metal_device.h index f71a821df..c38480018 100644 --- a/renderdoc/driver/metal/metal_device.h +++ b/renderdoc/driver/metal/metal_device.h @@ -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 m_CaptureOutputLayers; WrappedMTLTexture *m_CapturedBackbuffer = NULL; + Threading::CriticalSection m_CaptureDrawablesLock; + rdcflatmap m_CaptureDrawableInfos; CaptureState m_State; bool m_AppControlledCapture = false;