diff --git a/renderdoc/driver/metal/CMakeLists.txt b/renderdoc/driver/metal/CMakeLists.txt index 2a9b78d62..cd96aca3c 100644 --- a/renderdoc/driver/metal/CMakeLists.txt +++ b/renderdoc/driver/metal/CMakeLists.txt @@ -20,6 +20,11 @@ set(sources metal_function.h metal_function_bridge.mm metal_common.h + metal_core.cpp + metal_core.h + metal_manager.cpp + metal_manager.h + metal_init_state.cpp metal_helpers_bridge.h metal_helpers_bridge.mm official/metal-cpp.h diff --git a/renderdoc/driver/metal/metal_common.h b/renderdoc/driver/metal/metal_common.h index 57525c9c7..2cc1c81e0 100644 --- a/renderdoc/driver/metal/metal_common.h +++ b/renderdoc/driver/metal/metal_common.h @@ -26,10 +26,24 @@ #include "api/replay/rdcstr.h" #include "common/common.h" +#include "common/timing.h" #include "official/metal-cpp.h" +#include "serialise/serialiser.h" #include "metal_resources.h" #include "metal_types.h" +enum class MetalChunk : uint32_t +{ + MTLCreateSystemDefaultDevice = (uint32_t)SystemChunk::FirstDriverChunk, + 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__); + #ifdef __OBJC__ #define METAL_NOT_HOOKED() \ do \ @@ -37,3 +51,21 @@ RDCWARN("Metal %s %s not hooked", class_getName([self class]), sel_getName(_cmd)); \ } while((void)0, 0) #endif + +// similar to RDCUNIMPLEMENTED but without the debugbreak +#define METAL_NOT_IMPLEMENTED(...) \ + do \ + { \ + RDCWARN("Metal '%s' not implemented -" __VA_ARGS__, __PRETTY_FUNCTION__); \ + } while((void)0, 0) + +// similar to RDCUNIMPLEMENTED but for things that are hit often so we don't want to fire the +// debugbreak. +#define METAL_NOT_IMPLEMENTED_ONCE(...) \ + do \ + { \ + static bool msgprinted = false; \ + if(!msgprinted) \ + RDCDEBUG("Metal '%s' not implemented - " __VA_ARGS__, __PRETTY_FUNCTION__); \ + msgprinted = true; \ + } while((void)0, 0) diff --git a/renderdoc/driver/metal/metal_core.cpp b/renderdoc/driver/metal/metal_core.cpp new file mode 100644 index 000000000..b49fcaa00 --- /dev/null +++ b/renderdoc/driver/metal/metal_core.cpp @@ -0,0 +1,55 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "metal_core.h" +#include "metal_device.h" + +WriteSerialiser &WrappedMTLDevice::GetThreadSerialiser() +{ + WriteSerialiser *ser = (WriteSerialiser *)Threading::GetTLSValue(threadSerialiserTLSSlot); + if(ser) + return *ser; + + // slow path, but rare + ser = new WriteSerialiser(new StreamWriter(1024), Ownership::Stream); + + uint32_t flags = WriteSerialiser::ChunkDuration | WriteSerialiser::ChunkTimestamp | + WriteSerialiser::ChunkThreadID; + + if(RenderDoc::Inst().GetCaptureOptions().captureCallstacks) + flags |= WriteSerialiser::ChunkCallstack; + + ser->SetChunkMetadataRecording(flags); + ser->SetUserData(GetResourceManager()); + ser->SetVersion(MetalInitParams::CurrentVersion); + + Threading::SetTLSValue(threadSerialiserTLSSlot, (void *)ser); + + { + SCOPED_LOCK(m_ThreadSerialisersLock); + m_ThreadSerialisers.push_back(ser); + } + + return *ser; +} diff --git a/renderdoc/driver/metal/metal_core.h b/renderdoc/driver/metal/metal_core.h new file mode 100644 index 000000000..53dc3a68d --- /dev/null +++ b/renderdoc/driver/metal/metal_core.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "metal_common.h" + +struct MetalInitParams +{ + // check if a frame capture section version is supported + static const uint64_t CurrentVersion = 0x1; +}; + +DECLARE_REFLECTION_STRUCT(MetalInitParams); diff --git a/renderdoc/driver/metal/metal_device.cpp b/renderdoc/driver/metal/metal_device.cpp index 633232dad..47b1f6cf5 100644 --- a/renderdoc/driver/metal/metal_device.cpp +++ b/renderdoc/driver/metal/metal_device.cpp @@ -23,12 +23,24 @@ ******************************************************************************/ #include "metal_device.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; + threadSerialiserTLSSlot = Threading::AllocateTLSSlot(); + + m_ResourceManager = new MetalResourceManager(m_State, this); + RDCASSERT(m_WrappedMTLDevice == this); } MTL::Device *WrappedMTLDevice::MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice) diff --git a/renderdoc/driver/metal/metal_device.h b/renderdoc/driver/metal/metal_device.h index d14d30105..2aad33c52 100644 --- a/renderdoc/driver/metal/metal_device.h +++ b/renderdoc/driver/metal/metal_device.h @@ -25,20 +25,43 @@ #pragma once #include "metal_common.h" +#include "metal_manager.h" class WrappedMTLDevice : public WrappedMTLObject { + friend class MetalResourceManager; + public: WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId); ~WrappedMTLDevice() {} static MTL::Device *MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice); CaptureState &GetStateRef() { return m_State; } + CaptureState GetState() { return m_State; } + MetalResourceManager *GetResourceManager() { return m_ResourceManager; }; + WriteSerialiser &GetThreadSerialiser(); + enum { TypeEnum = eResDevice }; private: + void Construct(); + + bool Prepare_InitialState(WrappedMTLObject *res); + uint64_t GetSize_InitialState(ResourceId id, const MetalInitialContents &initial); + template + bool Serialise_InitialState(SerialiserType &ser, ResourceId id, MetalResourceRecord *record, + const MetalInitialContents *initial); + void Create_InitialState(ResourceId id, WrappedMTLObject *live, bool hasData); + void Apply_InitialState(WrappedMTLObject *live, const MetalInitialContents &initial); + + MetalResourceManager *m_ResourceManager; + CaptureState m_State; + + uint64_t threadSerialiserTLSSlot; + Threading::CriticalSection m_ThreadSerialisersLock; + rdcarray m_ThreadSerialisers; }; diff --git a/renderdoc/driver/metal/metal_device_bridge.mm b/renderdoc/driver/metal/metal_device_bridge.mm index 2a1a4d20d..11aac492b 100644 --- a/renderdoc/driver/metal/metal_device_bridge.mm +++ b/renderdoc/driver/metal/metal_device_bridge.mm @@ -37,7 +37,7 @@ // ObjCWrappedMTLDevice specific - (id)real { - MTL::Device *real = Unwrap(self.wrappedCPP); + MTL::Device *real = Unwrap(self.wrappedCPP); return id(real); } diff --git a/renderdoc/driver/metal/metal_function.cpp b/renderdoc/driver/metal/metal_function.cpp index b08bc1a92..aa99ac59f 100644 --- a/renderdoc/driver/metal/metal_function.cpp +++ b/renderdoc/driver/metal/metal_function.cpp @@ -29,5 +29,5 @@ WrappedMTLFunction::WrappedMTLFunction(MTL::Function *realMTLFunction, ResourceI WrappedMTLDevice *wrappedMTLDevice) : WrappedMTLObject(realMTLFunction, objId, wrappedMTLDevice, wrappedMTLDevice->GetStateRef()) { - wrappedObjC = AllocateObjCWrapper(this); + objc = AllocateObjCWrapper(this); } diff --git a/renderdoc/driver/metal/metal_function_bridge.mm b/renderdoc/driver/metal/metal_function_bridge.mm index 49b71c772..6e788c64f 100644 --- a/renderdoc/driver/metal/metal_function_bridge.mm +++ b/renderdoc/driver/metal/metal_function_bridge.mm @@ -31,7 +31,7 @@ // ObjCWrappedMTLFunction specific - (id)real { - MTL::Function *real = Unwrap(self.wrappedCPP); + MTL::Function *real = Unwrap(self.wrappedCPP); return id(real); } diff --git a/renderdoc/driver/metal/metal_init_state.cpp b/renderdoc/driver/metal/metal_init_state.cpp new file mode 100644 index 000000000..80754b92b --- /dev/null +++ b/renderdoc/driver/metal/metal_init_state.cpp @@ -0,0 +1,70 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "metal_common.h" +#include "metal_device.h" + +bool WrappedMTLDevice::Prepare_InitialState(WrappedMTLObject *res) +{ + ResourceId id = GetResourceManager()->GetID(res); + + MetalResourceType type = res->record->resType; + { + RDCERR("Unhandled resource type %d", type); + } + + return false; +} + +uint64_t WrappedMTLDevice::GetSize_InitialState(ResourceId id, const MetalInitialContents &initial) +{ + METAL_NOT_IMPLEMENTED(); + return 128; +} + +template +bool WrappedMTLDevice::Serialise_InitialState(SerialiserType &ser, ResourceId id, + MetalResourceRecord *record, + const MetalInitialContents *initial) +{ + METAL_NOT_IMPLEMENTED(); + return false; +} + +void WrappedMTLDevice::Create_InitialState(ResourceId id, WrappedMTLObject *live, bool hasData) +{ + METAL_NOT_IMPLEMENTED(); +} + +void WrappedMTLDevice::Apply_InitialState(WrappedMTLObject *live, const MetalInitialContents &initial) +{ + METAL_NOT_IMPLEMENTED(); +} + +template bool WrappedMTLDevice::Serialise_InitialState(ReadSerialiser &ser, ResourceId id, + MetalResourceRecord *record, + const MetalInitialContents *initial); +template bool WrappedMTLDevice::Serialise_InitialState(WriteSerialiser &ser, ResourceId id, + MetalResourceRecord *record, + const MetalInitialContents *initial); diff --git a/renderdoc/driver/metal/metal_library.cpp b/renderdoc/driver/metal/metal_library.cpp index 5fde072d0..ffc7726fe 100644 --- a/renderdoc/driver/metal/metal_library.cpp +++ b/renderdoc/driver/metal/metal_library.cpp @@ -30,5 +30,5 @@ WrappedMTLLibrary::WrappedMTLLibrary(MTL::Library *realMTLLibrary, ResourceId ob WrappedMTLDevice *wrappedMTLDevice) : WrappedMTLObject(realMTLLibrary, objId, wrappedMTLDevice, wrappedMTLDevice->GetStateRef()) { - wrappedObjC = AllocateObjCWrapper(this); + objc = AllocateObjCWrapper(this); } diff --git a/renderdoc/driver/metal/metal_library_bridge.mm b/renderdoc/driver/metal/metal_library_bridge.mm index af8fb2ae1..51c6fef84 100644 --- a/renderdoc/driver/metal/metal_library_bridge.mm +++ b/renderdoc/driver/metal/metal_library_bridge.mm @@ -31,7 +31,7 @@ // ObjCWrappedMTLLibrary specific - (id)real { - MTL::Library *real = Unwrap(self.wrappedCPP); + MTL::Library *real = Unwrap(self.wrappedCPP); return id(real); } diff --git a/renderdoc/driver/metal/metal_manager.cpp b/renderdoc/driver/metal/metal_manager.cpp new file mode 100644 index 000000000..a5094ae3d --- /dev/null +++ b/renderdoc/driver/metal/metal_manager.cpp @@ -0,0 +1,60 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2021 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "metal_manager.h" +#include "metal_device.h" + +bool MetalResourceManager::ResourceTypeRelease(WrappedResourceType res) +{ + METAL_NOT_IMPLEMENTED(); + return false; +} + +bool MetalResourceManager::Prepare_InitialState(WrappedMTLObject *res) +{ + return m_WrappedMTLDevice->Prepare_InitialState(res); +} + +uint64_t MetalResourceManager::GetSize_InitialState(ResourceId id, const MetalInitialContents &initial) +{ + return m_WrappedMTLDevice->GetSize_InitialState(id, initial); +} + +bool MetalResourceManager::Serialise_InitialState(WriteSerialiser &ser, ResourceId id, + MetalResourceRecord *record, + const MetalInitialContents *initial) +{ + return m_WrappedMTLDevice->Serialise_InitialState(ser, id, record, initial); +} + +void MetalResourceManager::Create_InitialState(ResourceId id, WrappedMTLObject *live, bool hasData) +{ + return m_WrappedMTLDevice->Create_InitialState(id, live, hasData); +} + +void MetalResourceManager::Apply_InitialState(WrappedMTLObject *live, + const MetalInitialContents &initial) +{ + return m_WrappedMTLDevice->Apply_InitialState(live, initial); +} diff --git a/renderdoc/driver/metal/metal_manager.h b/renderdoc/driver/metal/metal_manager.h new file mode 100644 index 000000000..b8d88d9cd --- /dev/null +++ b/renderdoc/driver/metal/metal_manager.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2021 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "core/resource_manager.h" +#include "metal_resources.h" + +struct MetalInitialContents +{ + MetalInitialContents() + { + RDCCOMPILE_ASSERT(std::is_standard_layout::value, + "MetalInitialContents must be POD"); + memset(this, 0, sizeof(*this)); + } + + MetalInitialContents(MetalResourceType t) + { + memset(this, 0, sizeof(*this)); + type = t; + } + + template + void Free(ResourceManager *rm) + { + RDCASSERT(false); + } + bytebuf resourceContents; + + // for plain resources, we store the resource type + MetalResourceType type; +}; + +struct MetalResourceManagerConfiguration +{ + typedef WrappedMTLObject *WrappedResourceType; + typedef void *RealResourceType; + typedef MetalResourceRecord RecordType; + typedef MetalInitialContents InitialContentData; +}; + +class MetalResourceManager : public ResourceManager +{ +public: + MetalResourceManager(CaptureState &state, WrappedMTLDevice *device) + : ResourceManager(state), m_WrappedMTLDevice(device) + { + } + void SetState(CaptureState state) { m_State = state; } + CaptureState GetState() { return m_State; } + ~MetalResourceManager() {} + void ClearWithoutReleasing() + { + // if any objects leaked past, it's no longer safe to delete them as we would + // be calling Shutdown() after the device that owns them is destroyed. Instead + // we just have to leak ourselves. + RDCASSERT(m_LiveResourceMap.empty()); + RDCASSERT(m_InitialContents.empty()); + RDCASSERT(m_ResourceRecords.empty()); + RDCASSERT(m_CurrentResourceMap.empty()); + RDCASSERT(m_WrapperMap.empty()); + + m_LiveResourceMap.clear(); + m_InitialContents.clear(); + m_ResourceRecords.clear(); + m_CurrentResourceMap.clear(); + m_WrapperMap.clear(); + } + + // ResourceManager interface + ResourceId GetID(WrappedMTLObject *res) + { + if(res == NULL) + return ResourceId(); + + return res->id; + } + // ResourceManager interface + + template + ResourceId WrapResource(realtype obj, typename UnwrapHelper::Outer *&wrapped) + { + RDCASSERT(obj != NULL); + RDCASSERT(m_WrappedMTLDevice != NULL); + + ResourceId id = ResourceIDGen::GetNewUniqueID(); + using WrappedType = typename UnwrapHelper::Outer; + wrapped = new WrappedType(obj, id, m_WrappedMTLDevice); + wrapped->real = obj; + AddCurrentResource(id, wrapped); + + // TODO: implement RD MTL replay + // if(IsReplayMode(m_State)) + // AddWrapper(wrapMetalResourceManager(obj)); + return id; + } + + using ResourceManager::AddResourceRecord; + + template + MetalResourceRecord *AddResourceRecord(wrappedtype *wrapped) + { + MetalResourceRecord *ret = wrapped->record = ResourceManager::AddResourceRecord(wrapped->id); + + ret->Resource = (WrappedMTLObject *)wrapped; + ret->resType = (MetalResourceType)wrappedtype::TypeEnum; + return ret; + } + + // ResourceRecordHandler interface implemented in ResourceManager + // void MarkDirtyResource(ResourceId id); + // void RemoveResourceRecord(ResourceId id); + // void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType); + // void DestroyResourceRecord(ResourceRecord *record); + // ResourceRecordHandler interface + +private: + // ResourceManager interface + bool ResourceTypeRelease(WrappedMTLObject *res); + bool Prepare_InitialState(WrappedMTLObject *res); + uint64_t GetSize_InitialState(ResourceId id, const MetalInitialContents &initial); + bool Serialise_InitialState(WriteSerialiser &ser, ResourceId id, MetalResourceRecord *record, + const MetalInitialContents *initial); + void Create_InitialState(ResourceId id, WrappedMTLObject *live, bool hasData); + void Apply_InitialState(WrappedMTLObject *live, const MetalInitialContents &initial); + // ResourceManager interface + + WrappedMTLDevice *m_WrappedMTLDevice; +}; diff --git a/renderdoc/driver/metal/metal_resources.cpp b/renderdoc/driver/metal/metal_resources.cpp index a4d65fb93..0df85916e 100644 --- a/renderdoc/driver/metal/metal_resources.cpp +++ b/renderdoc/driver/metal/metal_resources.cpp @@ -38,9 +38,14 @@ void WrappedMTLObject::Dealloc() // TODO: call the wrapped object destructor } +MetalResourceManager *WrappedMTLObject::GetResourceManager() +{ + return m_WrappedMTLDevice->GetResourceManager(); +} + MTL::Device *WrappedMTLObject::GetObjCWrappedMTLDevice() { - return UnwrapObjC(m_WrappedMTLDevice); + return GetObjC(m_WrappedMTLDevice); } MetalResourceRecord::~MetalResourceRecord() diff --git a/renderdoc/driver/metal/metal_resources.h b/renderdoc/driver/metal/metal_resources.h index 4f3cbfd29..68462e892 100644 --- a/renderdoc/driver/metal/metal_resources.h +++ b/renderdoc/driver/metal/metal_resources.h @@ -26,9 +26,11 @@ #include "core/resource_manager.h" #include "metal_common.h" +#include "metal_types.h" struct MetalResourceRecord; class WrappedMTLDevice; +class MetalResourceManager; enum MetalResourceType { @@ -44,7 +46,7 @@ struct WrappedMTLObject { WrappedMTLObject() = delete; WrappedMTLObject(WrappedMTLDevice *wrappedMTLDevice, CaptureState &captureState) - : wrappedObjC(NULL), + : objc(NULL), real(NULL), record(NULL), m_WrappedMTLDevice(wrappedMTLDevice), @@ -53,7 +55,7 @@ struct WrappedMTLObject } WrappedMTLObject(void *mtlObject, ResourceId objId, WrappedMTLDevice *wrappedMTLDevice, CaptureState &captureState) - : wrappedObjC(NULL), + : objc(NULL), real(mtlObject), id(objId), record(NULL), @@ -67,7 +69,9 @@ struct WrappedMTLObject MTL::Device *GetObjCWrappedMTLDevice(); - void *wrappedObjC; + MetalResourceManager *GetResourceManager(); + + void *objc; void *real; ResourceId id; MetalResourceRecord *record; @@ -77,6 +81,15 @@ struct WrappedMTLObject ResourceId GetResID(WrappedMTLObject *obj); +template +MetalResourceRecord *GetRecord(WrappedType *obj) +{ + if(obj == NULL) + return NULL; + + return obj->record; +} + template RealType Unwrap(WrappedMTLObject *obj) { @@ -87,14 +100,39 @@ RealType Unwrap(WrappedMTLObject *obj) } template -RealType UnwrapObjC(WrappedMTLObject *obj) +RealType GetObjC(WrappedMTLObject *obj) { if(obj == NULL) return RealType(); - return (RealType)obj->wrappedObjC; + return (RealType)obj->objc; } +// template magic voodoo to unwrap types +template +struct UnwrapHelper +{ +}; + +#define UNWRAP_HELPER(CPPTYPE) \ + template <> \ + struct UnwrapHelper \ + { \ + typedef CONCAT(WrappedMTL, CPPTYPE) Outer; \ + }; + +METALCPP_WRAPPED_PROTOCOLS(UNWRAP_HELPER) +#undef UNWRAP_HELPER + +#define IMPLEMENT_WRAPPED_TYPE_UNWRAP(CPPTYPE) \ + inline MTL::CPPTYPE *Unwrap(WrappedMTL##CPPTYPE *obj) \ + { \ + return Unwrap((WrappedMTLObject *)obj); \ + } + +METALCPP_WRAPPED_PROTOCOLS(IMPLEMENT_WRAPPED_TYPE_UNWRAP) +#undef IMPLEMENT_WRAPPED_TYPE_UNWRAP + struct MetalResourceRecord : public ResourceRecord { public: diff --git a/renderdoc/driver/metal/metal_types.h b/renderdoc/driver/metal/metal_types.h index 8af84d7ac..3a8907816 100644 --- a/renderdoc/driver/metal/metal_types.h +++ b/renderdoc/driver/metal/metal_types.h @@ -24,7 +24,9 @@ #pragma once -#include "metal_common.h" +#include "api/replay/rdcstr.h" +#include "official/metal-cpp.h" +#include "serialise/serialiser.h" #define METALCPP_WRAPPED_PROTOCOLS(FUNC) \ FUNC(Device); \ diff --git a/renderdoc/driver/metal/metal_types_bridge.mm b/renderdoc/driver/metal/metal_types_bridge.mm index bd072b80b..8cfca1688 100644 --- a/renderdoc/driver/metal/metal_types_bridge.mm +++ b/renderdoc/driver/metal/metal_types_bridge.mm @@ -24,9 +24,50 @@ #include "metal_types_bridge.h" #include "metal_device.h" +#include "metal_function.h" #include "metal_library.h" #define DEFINE_OBJC_HELPERS(CPPTYPE) \ + static ObjCWrappedMTL##CPPTYPE *GetObjC(MTL::CPPTYPE *cppType) \ + { \ + if(cppType == NULL) \ + { \ + return NULL; \ + } \ + ObjCWrappedMTL##CPPTYPE *objC = (ObjCWrappedMTL##CPPTYPE *)cppType; \ + RDCASSERT([objC isKindOfClass:[ObjCWrappedMTL##CPPTYPE class]]); \ + return objC; \ + } \ + \ + WrappedMTL##CPPTYPE *GetWrapped(MTL::CPPTYPE *cppType) \ + { \ + ObjCWrappedMTL##CPPTYPE *objC = GetObjC(cppType); \ + return objC.wrappedCPP; \ + } \ + \ + MTL::CPPTYPE *GetReal(MTL::CPPTYPE *cppType) \ + { \ + ObjCWrappedMTL##CPPTYPE *objC = GetObjC(cppType); \ + MTL::CPPTYPE *real = (MTL::CPPTYPE *)objC.real; \ + return real; \ + } \ + \ + bool IsObjCWrapped(MTL::CPPTYPE *cppType) \ + { \ + ObjCWrappedMTL##CPPTYPE *objC = (ObjCWrappedMTL##CPPTYPE *)cppType; \ + return [objC isKindOfClass:[ObjCWrappedMTL##CPPTYPE class]]; \ + } \ + \ + ResourceId GetId(MTL::CPPTYPE *cppType) \ + { \ + WrappedMTL##CPPTYPE *wrappedCPP = GetWrapped(cppType); \ + if(wrappedCPP == NULL) \ + { \ + return ResourceId(); \ + } \ + return wrappedCPP->id; \ + } \ + \ MTL::CPPTYPE *AllocateObjCWrapper(WrappedMTL##CPPTYPE *wrappedCPP) \ { \ ObjCWrappedMTL##CPPTYPE *objC = [ObjCWrappedMTL##CPPTYPE alloc]; \