diff --git a/renderdoc/driver/metal/metal_device.cpp b/renderdoc/driver/metal/metal_device.cpp index 1fa4088ff..74b821ac0 100644 --- a/renderdoc/driver/metal/metal_device.cpp +++ b/renderdoc/driver/metal/metal_device.cpp @@ -46,12 +46,38 @@ WrappedMTLDevice::WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId) WrappedMTLDevice *WrappedMTLDevice::MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice) { MTLFixupForMetalDriverAssert(); + MTLHookObjcMethods(); ResourceId objId = ResourceIDGen::GetNewUniqueID(); WrappedMTLDevice *wrappedMTLDevice = new WrappedMTLDevice(realMTLDevice, objId); return wrappedMTLDevice; } +IMP WrappedMTLDevice::real_CAMetalLayer_nextDrawable; +uint64_t WrappedMTLDevice::nextDrawableTLSSlot; + +MTL::Drawable *hooked_CAMetalLayer_nextDrawable(id self, SEL _cmd) +{ + RDCASSERTEQUAL(Threading::GetTLSValue(WrappedMTLDevice::nextDrawableTLSSlot), 0); + Threading::SetTLSValue(WrappedMTLDevice::nextDrawableTLSSlot, (void *)(uintptr_t) true); + MTL::Drawable *drawable = + ((MTL::Drawable * (*)(id, SEL))WrappedMTLDevice::real_CAMetalLayer_nextDrawable)(self, _cmd); + Threading::SetTLSValue(WrappedMTLDevice::nextDrawableTLSSlot, (void *)(uintptr_t) false); + return drawable; +} + +void WrappedMTLDevice::MTLHookObjcMethods() +{ + static bool s_hookObjcMethods = false; + if(s_hookObjcMethods) + return; + + Method m = + class_getInstanceMethod(objc_lookUpClass("CAMetalLayer"), sel_registerName("nextDrawable")); + real_CAMetalLayer_nextDrawable = method_setImplementation(m, (IMP)hooked_CAMetalLayer_nextDrawable); + nextDrawableTLSSlot = Threading::AllocateTLSSlot(); +} + void WrappedMTLDevice::MTLFixupForMetalDriverAssert() { static bool s_fixupMetalDriverAssert = false; @@ -311,14 +337,10 @@ WrappedMTLTexture *WrappedMTLDevice::newTextureWithDescriptor(MTL::TextureDescri IOSurfaceRef iosurface, NS::UInteger plane) { - return Common_NewTexture(descriptor, MetalChunk::MTLDevice_newTextureWithDescriptor_iosurface, - true, iosurface, plane); -} - -WrappedMTLTexture *WrappedMTLDevice::nextDrawableTexture(MTL::TextureDescriptor *descriptor, - IOSurfaceRef iosurface, NS::UInteger plane) -{ - return Common_NewTexture(descriptor, MetalChunk::MTLDevice_newTextureWithDescriptor_nextDrawable, + bool nextDrawable = (bool)(uintptr_t)Threading::GetTLSValue(nextDrawableTLSSlot); + return Common_NewTexture(descriptor, + nextDrawable ? MetalChunk::MTLDevice_newTextureWithDescriptor_nextDrawable + : MetalChunk::MTLDevice_newTextureWithDescriptor_iosurface, true, iosurface, plane); } diff --git a/renderdoc/driver/metal/metal_device.h b/renderdoc/driver/metal/metal_device.h index 0cd091756..dfb451ddd 100644 --- a/renderdoc/driver/metal/metal_device.h +++ b/renderdoc/driver/metal/metal_device.h @@ -51,8 +51,6 @@ public: NS::Error **error); WrappedMTLTexture *newTextureWithDescriptor(MTL::TextureDescriptor *descriptor, IOSurfaceRef iosurface, NS::UInteger plane); - WrappedMTLTexture *nextDrawableTexture(MTL::TextureDescriptor *descriptor, IOSurfaceRef iosurface, - NS::UInteger plane); WrappedMTLTexture *newTextureWithDescriptor(MTL::TextureDescriptor *descriptor); template bool Serialise_newTextureWithDescriptor(SerialiserType &ser, WrappedMTLTexture *, @@ -96,8 +94,12 @@ public: TypeEnum = eResDevice }; + static uint64_t nextDrawableTLSSlot; + static IMP real_CAMetalLayer_nextDrawable; + private: static void MTLFixupForMetalDriverAssert(); + static void MTLHookObjcMethods(); bool Prepare_InitialState(WrappedMTLObject *res); uint64_t GetSize_InitialState(ResourceId id, const MetalInitialContents &initial); template diff --git a/renderdoc/driver/metal/metal_device_bridge.mm b/renderdoc/driver/metal/metal_device_bridge.mm index d691128d5..af4686b79 100644 --- a/renderdoc/driver/metal/metal_device_bridge.mm +++ b/renderdoc/driver/metal/metal_device_bridge.mm @@ -266,21 +266,6 @@ plane:(NSUInteger)plane API_AVAILABLE(macos(10.11), ios(11.0)) { - NS::String *nsString = (NS::String *)[[NSThread callStackSymbols] objectAtIndex:1]; - // Example parentCallsite string - //"1 QuartzCore 0x00000001b956ece8 _ZL19get_unused_drawableP20_CAMetalLayerPrivatebb + 676" - bool nextDrawable = false; - if(nsString) - { - rdcstr parentCallsite(nsString->utf8String()); - nextDrawable = (parentCallsite.contains("CAMetalLayer") && parentCallsite.contains("drawable")); - } - - if(nextDrawable) - { - return id(GetWrapped(self)->nextDrawableTexture( - (MTL::TextureDescriptor *)descriptor, iosurface, plane)); - } return id(GetWrapped(self)->newTextureWithDescriptor( (MTL::TextureDescriptor *)descriptor, iosurface, plane)); }