From 5f3203c69858de1368bdde785f31366051ed93d7 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Sat, 12 Mar 2022 20:02:43 +0000 Subject: [PATCH] Hooking for MTLDevice basic new Library APIs --- renderdoc/driver/metal/metal_common.h | 33 ++++- renderdoc/driver/metal/metal_device.cpp | 132 ++++++++++++++++-- renderdoc/driver/metal/metal_device.h | 14 +- renderdoc/driver/metal/metal_device_bridge.mm | 12 +- renderdoc/driver/metal/metal_hook_bridge.mm | 3 +- 5 files changed, 174 insertions(+), 20 deletions(-) diff --git a/renderdoc/driver/metal/metal_common.h b/renderdoc/driver/metal/metal_common.h index 2cc1c81e0..f3c5cd659 100644 --- a/renderdoc/driver/metal/metal_common.h +++ b/renderdoc/driver/metal/metal_common.h @@ -29,20 +29,47 @@ #include "common/timing.h" #include "official/metal-cpp.h" #include "serialise/serialiser.h" +#include "serialise/serialiser.h" #include "metal_resources.h" #include "metal_types.h" enum class MetalChunk : uint32_t { MTLCreateSystemDefaultDevice = (uint32_t)SystemChunk::FirstDriverChunk, + MTLDevice_newDefaultLibrary, + MTLDevice_newLibraryWithSource, + MTLLibrary_newFunctionWithName, Max }; DECLARE_REFLECTION_ENUM(MetalChunk); -#define INSTANTIATE_FUNCTION_SERIALISED(CLASS, func, ...) \ - template bool CLASS::func(ReadSerialiser &ser, __VA_ARGS__); \ - template bool CLASS::func(WriteSerialiser &ser, __VA_ARGS__); +// must be at the start of any function that serialises +#define CACHE_THREAD_SERIALISER() WriteSerialiser &ser = m_WrappedMTLDevice->GetThreadSerialiser(); + +#define SERIALISE_TIME_CALL(...) \ + { \ + WriteSerialiser &ser = m_WrappedMTLDevice->GetThreadSerialiser(); \ + ser.ChunkMetadata().timestampMicro = Timing::GetTick(); \ + __VA_ARGS__; \ + ser.ChunkMetadata().durationMicro = Timing::GetTick() - ser.ChunkMetadata().timestampMicro; \ + } + +#define DECLARE_FUNCTION_SERIALISED(ret, func, ...) \ + ret func(__VA_ARGS__); \ + template \ + bool CONCAT(Serialise_, func(SerialiserType &ser, ##__VA_ARGS__)); + +#define INSTANTIATE_FUNCTION_SERIALISED(CLASS, ret, func, ...) \ + template bool CLASS::CONCAT(Serialise_, func(ReadSerialiser &ser, __VA_ARGS__)); \ + template bool CLASS::CONCAT(Serialise_, func(WriteSerialiser &ser, __VA_ARGS__)); + +// A handy macro to say "is the serialiser reading and we're doing replay-mode stuff?" +// The reason we check both is that checking the first allows the compiler to eliminate the other +// path at compile-time, and the second because we might be just struct-serialising in which case we +// should be doing no work to restore states. +// Writing is unambiguously during capture mode, so we don't have to check both in that case. +#define IsReplayingAndReading() (ser.IsReading() && IsReplayMode(m_WrappedMTLDevice->GetState())) #ifdef __OBJC__ #define METAL_NOT_HOOKED() \ diff --git a/renderdoc/driver/metal/metal_device.cpp b/renderdoc/driver/metal/metal_device.cpp index 47b1f6cf5..e40e951ab 100644 --- a/renderdoc/driver/metal/metal_device.cpp +++ b/renderdoc/driver/metal/metal_device.cpp @@ -23,17 +23,12 @@ ******************************************************************************/ #include "metal_device.h" +#include "metal_helpers_bridge.h" +#include "metal_library.h" #include "metal_manager.h" WrappedMTLDevice::WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId) : WrappedMTLObject(realMTLDevice, objId, this, GetStateRef()) -{ - wrappedObjC = AllocateObjCWrapper(this); - Construct(); - GetResourceManager()->AddCurrentResource(objId, this); -} - -void WrappedMTLDevice::Construct() { objc = AllocateObjCWrapper(this); m_WrappedMTLDevice = this; @@ -41,12 +36,131 @@ void WrappedMTLDevice::Construct() m_ResourceManager = new MetalResourceManager(m_State, this); RDCASSERT(m_WrappedMTLDevice == this); + GetResourceManager()->AddCurrentResource(objId, this); } -MTL::Device *WrappedMTLDevice::MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice) +WrappedMTLDevice *WrappedMTLDevice::MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice) { ResourceId objId = ResourceIDGen::GetNewUniqueID(); WrappedMTLDevice *wrappedMTLDevice = new WrappedMTLDevice(realMTLDevice, objId); - return UnwrapObjC(wrappedMTLDevice); + // return GetObjC(wrappedMTLDevice); + return wrappedMTLDevice; } + +template +bool WrappedMTLDevice::Serialise_newDefaultLibrary(SerialiserType &ser, WrappedMTLLibrary *library) +{ + void *pData; + uint32_t bytesCount; + if(ser.IsWriting()) + { + ObjC::Get_defaultLibraryData(pData, bytesCount); + } + + SERIALISE_ELEMENT_LOCAL(Library, GetResID(library)).TypedAs("MTLLibrary"_lit); + SERIALISE_ELEMENT(bytesCount); + SERIALISE_ELEMENT_ARRAY(pData, bytesCount); + + if(ser.IsWriting()) + { + free(pData); + } + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + // TODO: implement RD MTL replay + } + return true; +} + +WrappedMTLLibrary *WrappedMTLDevice::newDefaultLibrary() +{ + MTL::Library *realMTLLibrary; + + SERIALISE_TIME_CALL(realMTLLibrary = Unwrap(this)->newDefaultLibrary()); + WrappedMTLLibrary *wrappedMTLLibrary; + ResourceId id = GetResourceManager()->WrapResource(realMTLLibrary, wrappedMTLLibrary); + if(IsCaptureMode(m_State)) + { + Chunk *chunk = NULL; + { + CACHE_THREAD_SERIALISER(); + SCOPED_SERIALISE_CHUNK(MetalChunk::MTLDevice_newDefaultLibrary); + Serialise_newDefaultLibrary(ser, wrappedMTLLibrary); + chunk = scope.Get(); + } + MetalResourceRecord *record = GetResourceManager()->AddResourceRecord(wrappedMTLLibrary); + record->AddChunk(chunk); + GetResourceManager()->MarkResourceFrameReferenced(id, eFrameRef_Read); + } + else + { + // TODO: implement RD MTL replay + // GetResourceManager()->AddLiveResource(id, wrappedMTLLibrary); + } + return wrappedMTLLibrary; +} + +template +bool WrappedMTLDevice::Serialise_newLibraryWithSource(SerialiserType &ser, + WrappedMTLLibrary *library, NS::String *source, + MTL::CompileOptions *options) +{ + SERIALISE_ELEMENT_LOCAL(Library, GetResID(library)).TypedAs("MTLLibrary"_lit); + SERIALISE_ELEMENT(source); + // TODO:SERIALISE_ELEMENT(options); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + // TODO: implement RD MTL replay + } + return true; +} + +WrappedMTLLibrary *WrappedMTLDevice::newLibraryWithSource(NS::String *source, + MTL::CompileOptions *options, + NS::Error **error) +{ + MTL::Library *realMTLLibrary; + SERIALISE_TIME_CALL(realMTLLibrary = Unwrap(this)->newLibrary(source, options, error)); + WrappedMTLLibrary *wrappedMTLLibrary; + ResourceId id = GetResourceManager()->WrapResource(realMTLLibrary, wrappedMTLLibrary); + if(IsCaptureMode(m_State)) + { + Chunk *chunk = NULL; + { + CACHE_THREAD_SERIALISER(); + SCOPED_SERIALISE_CHUNK(MetalChunk::MTLDevice_newLibraryWithSource); + Serialise_newLibraryWithSource(ser, wrappedMTLLibrary, source, options); + chunk = scope.Get(); + } + MetalResourceRecord *record = GetResourceManager()->AddResourceRecord(wrappedMTLLibrary); + record->AddChunk(chunk); + GetResourceManager()->MarkResourceFrameReferenced(id, eFrameRef_Read); + } + else + { + // TODO: implement RD MTL replay + // GetResourceManager()->AddLiveResource(id, wrappedMTLLibrary); + } + return wrappedMTLLibrary; +} + +template bool WrappedMTLDevice::Serialise_newDefaultLibrary(ReadSerialiser &ser, + WrappedMTLLibrary *library); +template bool WrappedMTLDevice::Serialise_newDefaultLibrary(WriteSerialiser &ser, + WrappedMTLLibrary *library); + +template bool WrappedMTLDevice::Serialise_newLibraryWithSource(ReadSerialiser &ser, + WrappedMTLLibrary *library, + NS::String *source, + MTL::CompileOptions *options); +template bool WrappedMTLDevice::Serialise_newLibraryWithSource(WriteSerialiser &ser, + WrappedMTLLibrary *library, + NS::String *source, + MTL::CompileOptions *options); diff --git a/renderdoc/driver/metal/metal_device.h b/renderdoc/driver/metal/metal_device.h index 2aad33c52..13e651502 100644 --- a/renderdoc/driver/metal/metal_device.h +++ b/renderdoc/driver/metal/metal_device.h @@ -34,7 +34,17 @@ class WrappedMTLDevice : public WrappedMTLObject public: WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId); ~WrappedMTLDevice() {} - static MTL::Device *MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice); + static WrappedMTLDevice *MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice); + + WrappedMTLLibrary *newDefaultLibrary(); + template + bool Serialise_newDefaultLibrary(SerialiserType &ser, WrappedMTLLibrary *library); + + WrappedMTLLibrary *newLibraryWithSource(NS::String *source, MTL::CompileOptions *options, + NS::Error **error); + template + bool Serialise_newLibraryWithSource(SerialiserType &ser, WrappedMTLLibrary *library, + NS::String *source, MTL::CompileOptions *options); CaptureState &GetStateRef() { return m_State; } CaptureState GetState() { return m_State; } @@ -47,8 +57,6 @@ public: }; private: - void Construct(); - 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 11aac492b..9983dc601 100644 --- a/renderdoc/driver/metal/metal_device_bridge.mm +++ b/renderdoc/driver/metal/metal_device_bridge.mm @@ -24,6 +24,7 @@ #include "metal_device.h" #include +#include "metal_library.h" #include "metal_types_bridge.h" // Define Mac SDK versions when compiling with earlier SDKs @@ -284,8 +285,9 @@ - (nullable id)newDefaultLibrary { - METAL_NOT_HOOKED(); - return [self.real newDefaultLibrary]; + WrappedMTLLibrary *wrapped = self.wrappedCPP->newDefaultLibrary(); + MTL::Library *objc = GetObjC(wrapped); + return id(objc); } - (nullable id)newDefaultLibraryWithBundle:(NSBundle *)bundle @@ -322,8 +324,10 @@ options:(nullable MTLCompileOptions *)options error:(__autoreleasing NSError **)error { - METAL_NOT_HOOKED(); - return [self.real newLibraryWithSource:source options:options error:error]; + WrappedMTLLibrary *wrapped = self.wrappedCPP->newLibraryWithSource( + (NS::String *)source, (MTL::CompileOptions *)options, (NS::Error **)error); + MTL::Library *objc = GetObjC(wrapped); + return (id)(objc); } - (void)newLibraryWithSource:(NSString *)source diff --git a/renderdoc/driver/metal/metal_hook_bridge.mm b/renderdoc/driver/metal/metal_hook_bridge.mm index dc133cd92..ba98e3bf2 100644 --- a/renderdoc/driver/metal/metal_hook_bridge.mm +++ b/renderdoc/driver/metal/metal_hook_bridge.mm @@ -54,7 +54,8 @@ id METAL_EXPORT_NAME(MTLCreateSystemDefaultDevice)(void) } id device = METAL.MTLCreateSystemDefaultDevice(); - return id(WrappedMTLDevice::MTLCreateSystemDefaultDevice((MTL::Device *)device)); + WrappedMTLDevice *wrapped = WrappedMTLDevice::MTLCreateSystemDefaultDevice((MTL::Device *)device); + return id(GetObjC(wrapped)); } /*