diff --git a/renderdoc/driver/metal/CMakeLists.txt b/renderdoc/driver/metal/CMakeLists.txt index 6f516f815..928c1e94f 100644 --- a/renderdoc/driver/metal/CMakeLists.txt +++ b/renderdoc/driver/metal/CMakeLists.txt @@ -1,4 +1,16 @@ set(sources + metal_dispatch_table_bridge.mm + metal_dispatch_table_bridge.h + metal_hook_bridge.mm + metal_hook.cpp + metal_hook.h + metal_device.cpp + metal_device.h + metal_device_bridge.mm + metal_resources.h + metal_types_bridge.mm + metal_types_bridge.h + metal_types.h official/metal-cpp.h official/metal-cpp.cpp) diff --git a/renderdoc/driver/metal/metal_device.cpp b/renderdoc/driver/metal/metal_device.cpp new file mode 100644 index 000000000..cc02871bd --- /dev/null +++ b/renderdoc/driver/metal/metal_device.cpp @@ -0,0 +1,40 @@ +/****************************************************************************** + * 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_device.h" + +WrappedMTLDevice::WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId) + : WrappedMTLObject(realMTLDevice, objId, this) +{ + wrappedObjC = AllocateObjCWrapper(this); + m_WrappedMTLDevice = this; +} + +MTL::Device *WrappedMTLDevice::MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice) +{ + ResourceId objId = ResourceIDGen::GetNewUniqueID(); + WrappedMTLDevice *wrappedMTLDevice = new WrappedMTLDevice(realMTLDevice, objId); + + return UnwrapObjC(wrappedMTLDevice); +} diff --git a/renderdoc/driver/metal/metal_device.h b/renderdoc/driver/metal/metal_device.h new file mode 100644 index 000000000..956a01345 --- /dev/null +++ b/renderdoc/driver/metal/metal_device.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * 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_resources.h" + +class WrappedMTLDevice : public WrappedMTLObject +{ +public: + WrappedMTLDevice(MTL::Device *realMTLDevice, ResourceId objId); + ~WrappedMTLDevice() {} + static MTL::Device *MTLCreateSystemDefaultDevice(MTL::Device *realMTLDevice); + +private: +}; diff --git a/renderdoc/driver/metal/metal_device_bridge.mm b/renderdoc/driver/metal/metal_device_bridge.mm new file mode 100644 index 000000000..37c53adde --- /dev/null +++ b/renderdoc/driver/metal/metal_device_bridge.mm @@ -0,0 +1,790 @@ +/****************************************************************************** + * 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_device.h" +#include +#include "metal_types_bridge.h" + +// Define Mac SDK versions when compiling with earlier SDKs +#ifndef __MAC_12_0 +#define __MAC_12_0 120000 +#endif + +// Wrapper for MTLDevice +@implementation ObjCWrappedMTLDevice + +// ObjCWrappedMTLDevice specific +- (id)real +{ + MTL::Device *real = Unwrap(self.wrappedCPP); + return id(real); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector +{ + id fwd = self.real; + return [fwd methodSignatureForSelector:aSelector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + SEL aSelector = [invocation selector]; + + if([self.real respondsToSelector:aSelector]) + [invocation invokeWithTarget:self.real]; + else + [super forwardInvocation:invocation]; +} + +// MTLDevice : based on the protocol defined in +// Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/System/Library/Frameworks/Metal.framework/Headers/MTLDevice.h + +- (NSString *)name +{ + return self.real.name; +} + +- (uint64_t)registryID API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.registryID; +} + +- (MTLSize)maxThreadsPerThreadgroup API_AVAILABLE(macos(10.11), ios(9.0)) +{ + return self.real.maxThreadsPerThreadgroup; +} + +- (BOOL)isLowPower API_AVAILABLE(macos(10.11), macCatalyst(13.0))API_UNAVAILABLE(ios) +{ + return self.real.lowPower; +} + +- (BOOL)isHeadless API_AVAILABLE(macos(10.11), macCatalyst(13.0))API_UNAVAILABLE(ios) +{ + return self.real.headless; +} + +- (BOOL)isRemovable API_AVAILABLE(macos(10.13), macCatalyst(13.0))API_UNAVAILABLE(ios) +{ + return self.real.removable; +} + +- (BOOL)hasUnifiedMemory API_AVAILABLE(macos(10.15), ios(13.0)) +{ + return self.real.hasUnifiedMemory; +} + +- (uint64_t)recommendedMaxWorkingSetSize API_AVAILABLE(macos(10.12), macCatalyst(13.0)) + API_UNAVAILABLE(ios) +{ + return self.real.recommendedMaxWorkingSetSize; +} + +- (MTLDeviceLocation)location API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.location; +} + +- (NSUInteger)locationNumber API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.locationNumber; +} + +- (uint64_t)maxTransferRate API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.maxTransferRate; +} + +- (BOOL)isDepth24Stencil8PixelFormatSupported API_AVAILABLE(macos(10.11), macCatalyst(13.0)) + API_UNAVAILABLE(ios) +{ + return self.real.depth24Stencil8PixelFormatSupported; +} + +- (MTLReadWriteTextureTier)readWriteTextureSupport API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.readWriteTextureSupport; +} + +- (MTLArgumentBuffersTier)argumentBuffersSupport API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.argumentBuffersSupport; +} + +- (BOOL)areRasterOrderGroupsSupported API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.areRasterOrderGroupsSupported; +} + +- (BOOL)supports32BitFloatFiltering API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supports32BitFloatFiltering; +} + +- (BOOL)supports32BitMSAA API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supports32BitMSAA; +} + +- (BOOL)supportsQueryTextureLOD API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsQueryTextureLOD; +} + +- (BOOL)supportsBCTextureCompression API_AVAILABLE(macos(11.0))API_UNAVAILABLE(ios) +{ + return self.real.supportsBCTextureCompression; +} + +- (BOOL)supportsPullModelInterpolation API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsPullModelInterpolation; +} + +- (BOOL)areBarycentricCoordsSupported API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.barycentricCoordsSupported; +} + +- (BOOL)supportsShaderBarycentricCoordinates API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.supportsShaderBarycentricCoordinates; +} + +- (NSUInteger)currentAllocatedSize API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.currentAllocatedSize; +} + +- (nullable id)newCommandQueue +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newCommandQueue]; +} + +- (nullable id)newCommandQueueWithMaxCommandBufferCount:(NSUInteger)maxCommandBufferCount +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]; +} + +- (MTLSizeAndAlign)heapTextureSizeAndAlignWithDescriptor:(MTLTextureDescriptor *)desc + API_AVAILABLE(macos(10.13), ios(10.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real heapTextureSizeAndAlignWithDescriptor:desc]; +} + +- (MTLSizeAndAlign)heapBufferSizeAndAlignWithLength:(NSUInteger)length + options:(MTLResourceOptions)options + API_AVAILABLE(macos(10.13), ios(10.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real heapBufferSizeAndAlignWithLength:length options:options]; +} + +- (nullable id)newHeapWithDescriptor:(MTLHeapDescriptor *)descriptor + API_AVAILABLE(macos(10.13), ios(10.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newHeapWithDescriptor:descriptor]; +} + +- (nullable id)newBufferWithLength:(NSUInteger)length options:(MTLResourceOptions)options +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newBufferWithLength:length options:options]; +} + +- (nullable id)newBufferWithBytes:(const void *)pointer + length:(NSUInteger)length + options:(MTLResourceOptions)options +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newBufferWithBytes:pointer length:length options:options]; +} + +- (nullable id)newBufferWithBytesNoCopy:(void *)pointer + length:(NSUInteger)length + options:(MTLResourceOptions)options + deallocator:(void (^__nullable)(void *pointer, + NSUInteger length))deallocator +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newBufferWithBytesNoCopy:pointer + length:length + options:options + deallocator:deallocator]; +} + +- (nullable id)newDepthStencilStateWithDescriptor: + (MTLDepthStencilDescriptor *)descriptor +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newDepthStencilStateWithDescriptor:descriptor]; +} + +- (nullable id)newTextureWithDescriptor:(MTLTextureDescriptor *)descriptor +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newTextureWithDescriptor:descriptor]; +} + +- (nullable id)newTextureWithDescriptor:(MTLTextureDescriptor *)descriptor + iosurface:(IOSurfaceRef)iosurface + plane:(NSUInteger)plane + API_AVAILABLE(macos(10.11), ios(11.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newTextureWithDescriptor:descriptor iosurface:iosurface plane:plane]; +} + +- (nullable id)newSharedTextureWithDescriptor:(MTLTextureDescriptor *)descriptor + API_AVAILABLE(macos(10.14), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newSharedTextureWithDescriptor:descriptor]; +} + +- (nullable id)newSharedTextureWithHandle:(MTLSharedTextureHandle *)sharedHandle + API_AVAILABLE(macos(10.14), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newSharedTextureWithHandle:sharedHandle]; +} + +- (nullable id)newSamplerStateWithDescriptor:(MTLSamplerDescriptor *)descriptor +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newSamplerStateWithDescriptor:descriptor]; +} + +- (nullable id)newDefaultLibrary +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newDefaultLibrary]; +} + +- (nullable id)newDefaultLibraryWithBundle:(NSBundle *)bundle + error:(__autoreleasing NSError **)error + API_AVAILABLE(macos(10.12), ios(10.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newDefaultLibraryWithBundle:bundle error:error]; +} + +- (nullable id)newLibraryWithFile:(NSString *)filepath + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newLibraryWithFile:filepath error:error]; +} + +- (nullable id)newLibraryWithURL:(NSURL *)url + error:(__autoreleasing NSError **)error + API_AVAILABLE(macos(10.13), ios(11.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newLibraryWithURL:url error:error]; +} + +- (nullable id)newLibraryWithData:(dispatch_data_t)data + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newLibraryWithData:data error:error]; +} + +- (nullable id)newLibraryWithSource:(NSString *)source + options:(nullable MTLCompileOptions *)options + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newLibraryWithSource:source options:options error:error]; +} + +- (void)newLibraryWithSource:(NSString *)source + options:(nullable MTLCompileOptions *)options + completionHandler:(MTLNewLibraryCompletionHandler)completionHandler +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return + [self.real newLibraryWithSource:source options:options completionHandler:completionHandler]; +} + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (nullable id)newLibraryWithStitchedDescriptor:(MTLStitchedLibraryDescriptor *)descriptor + error:(__autoreleasing NSError **)error + API_AVAILABLE(macos(12.0), ios(15.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newLibraryWithStitchedDescriptor:descriptor error:error]; +} +#endif + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (void)newLibraryWithStitchedDescriptor:(MTLStitchedLibraryDescriptor *)descriptor + completionHandler:(MTLNewLibraryCompletionHandler)completionHandler + API_AVAILABLE(macos(12.0), ios(15.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + [self.real newLibraryWithStitchedDescriptor:descriptor completionHandler:completionHandler]; +} +#endif + +- (nullable id) +newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithDescriptor:descriptor error:error]; +} + +- (nullable id) +newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + reflection:(MTLAutoreleasedRenderPipelineReflection *__nullable)reflection + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithDescriptor:descriptor + options:options + reflection:reflection + error:error]; +} + +- (void)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor + completionHandler:(MTLNewRenderPipelineStateCompletionHandler)completionHandler +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithDescriptor:descriptor + completionHandler:completionHandler]; +} + +- (void)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + completionHandler: + (MTLNewRenderPipelineStateWithReflectionCompletionHandler)completionHandler +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithDescriptor:descriptor + options:options + completionHandler:completionHandler]; +} + +- (nullable id) +newComputePipelineStateWithFunction:(id)computeFunction + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithFunction:computeFunction error:error]; +} + +- (nullable id) +newComputePipelineStateWithFunction:(id)computeFunction + options:(MTLPipelineOption)options + reflection:(MTLAutoreleasedComputePipelineReflection *__nullable)reflection + error:(__autoreleasing NSError **)error +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithFunction:computeFunction + options:options + reflection:reflection + error:error]; +} + +- (void)newComputePipelineStateWithFunction:(id)computeFunction + completionHandler:(MTLNewComputePipelineStateCompletionHandler)completionHandler +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithFunction:computeFunction + completionHandler:completionHandler]; +} + +- (void)newComputePipelineStateWithFunction:(id)computeFunction + options:(MTLPipelineOption)options + completionHandler: + (MTLNewComputePipelineStateWithReflectionCompletionHandler)completionHandler +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithFunction:computeFunction + options:options + completionHandler:completionHandler]; +} + +- (nullable id) +newComputePipelineStateWithDescriptor:(MTLComputePipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + reflection:(MTLAutoreleasedComputePipelineReflection *__nullable)reflection + error:(__autoreleasing NSError **)error + API_AVAILABLE(macos(10.11), ios(9.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithDescriptor:descriptor + options:options + reflection:reflection + error:error]; +} + +- (void)newComputePipelineStateWithDescriptor:(MTLComputePipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + completionHandler: + (MTLNewComputePipelineStateWithReflectionCompletionHandler)completionHandler + API_AVAILABLE(macos(10.11), ios(9.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newComputePipelineStateWithDescriptor:descriptor + options:options + completionHandler:completionHandler]; +} + +- (nullable id)newFence API_AVAILABLE(macos(10.13), ios(10.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newFence]; +} + +- (BOOL)supportsFeatureSet:(MTLFeatureSet)featureSet +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsFeatureSet:featureSet]; +} + +- (BOOL)supportsFamily:(MTLGPUFamily)gpuFamily API_AVAILABLE(macos(10.15), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsFamily:gpuFamily]; +} + +- (BOOL)supportsTextureSampleCount:(NSUInteger)sampleCount API_AVAILABLE(macos(10.11), ios(9.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsTextureSampleCount:sampleCount]; +} + +- (NSUInteger)minimumLinearTextureAlignmentForPixelFormat:(MTLPixelFormat)format + API_AVAILABLE(macos(10.13), ios(11.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real minimumLinearTextureAlignmentForPixelFormat:format]; +} + +- (NSUInteger)minimumTextureBufferAlignmentForPixelFormat:(MTLPixelFormat)format + API_AVAILABLE(macos(10.14), ios(12.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real minimumTextureBufferAlignmentForPixelFormat:format]; +} + +- (nullable id) +newRenderPipelineStateWithTileDescriptor:(MTLTileRenderPipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + reflection:(MTLAutoreleasedRenderPipelineReflection *__nullable)reflection + error:(__autoreleasing NSError **)error + API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(11.0), tvos(14.5)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithTileDescriptor:descriptor + options:options + reflection:reflection + error:error]; +} + +- (void)newRenderPipelineStateWithTileDescriptor:(MTLTileRenderPipelineDescriptor *)descriptor + options:(MTLPipelineOption)options + completionHandler: + (MTLNewRenderPipelineStateWithReflectionCompletionHandler)completionHandler + API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(11.0), tvos(14.5)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRenderPipelineStateWithTileDescriptor:descriptor + options:options + completionHandler:completionHandler]; +} + +- (NSUInteger)maxThreadgroupMemoryLength API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.maxThreadgroupMemoryLength; +} + +- (NSUInteger)maxArgumentBufferSamplerCount API_AVAILABLE(macos(10.14), ios(12.0)) +{ + return self.real.maxArgumentBufferSamplerCount; +} + +- (BOOL)areProgrammableSamplePositionsSupported API_AVAILABLE(macos(10.13), ios(11.0)) +{ + return self.real.programmableSamplePositionsSupported; +} + +- (void)getDefaultSamplePositions:(MTLSamplePosition *)positions + count:(NSUInteger)count API_AVAILABLE(macos(10.13), ios(11.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real getDefaultSamplePositions:positions count:count]; +} + +- (nullable id)newArgumentEncoderWithArguments: + (NSArray *)arguments API_AVAILABLE(macos(10.13), ios(11.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newArgumentEncoderWithArguments:arguments]; +} + +- (BOOL)supportsRasterizationRateMapWithLayerCount:(NSUInteger)layerCount + API_AVAILABLE(macos(10.15.4), ios(13.0), macCatalyst(13.4)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsRasterizationRateMapWithLayerCount:layerCount]; +} + +- (nullable id)newRasterizationRateMapWithDescriptor: + (MTLRasterizationRateMapDescriptor *)descriptor + API_AVAILABLE(macos(10.15.4), ios(13.0), macCatalyst(13.4)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newRasterizationRateMapWithDescriptor:descriptor]; +} + +- (nullable id) +newIndirectCommandBufferWithDescriptor:(MTLIndirectCommandBufferDescriptor *)descriptor + maxCommandCount:(NSUInteger)maxCount + options:(MTLResourceOptions)options + API_AVAILABLE(macos(10.14), ios(12.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newIndirectCommandBufferWithDescriptor:descriptor + maxCommandCount:maxCount + options:options]; +} + +- (nullable id)newEvent API_AVAILABLE(macos(10.14), ios(12.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newEvent]; +} + +- (nullable id)newSharedEvent API_AVAILABLE(macos(10.14), ios(12.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newSharedEvent]; +} + +- (nullable id)newSharedEventWithHandle:(MTLSharedEventHandle *)sharedEventHandle + API_AVAILABLE(macos(10.14), ios(12.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newSharedEventWithHandle:sharedEventHandle]; +} + +- (uint64_t)peerGroupID API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.peerGroupID; +} + +- (uint32_t)peerIndex API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.peerIndex; +} + +- (uint32_t)peerCount API_AVAILABLE(macos(10.15))API_UNAVAILABLE(ios) +{ + return self.real.peerCount; +} + +- (MTLSize)sparseTileSizeWithTextureType:(MTLTextureType)textureType + pixelFormat:(MTLPixelFormat)pixelFormat + sampleCount:(NSUInteger)sampleCount + API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real sparseTileSizeWithTextureType:textureType + pixelFormat:pixelFormat + sampleCount:sampleCount]; +} + +- (NSUInteger)sparseTileSizeInBytes API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(13.0)) +{ + return self.real.sparseTileSizeInBytes; +} + +- (void)convertSparsePixelRegions:(const MTLRegion[_Nonnull])pixelRegions + toTileRegions:(MTLRegion[_Nonnull])tileRegions + withTileSize:(MTLSize)tileSize + alignmentMode:(MTLSparseTextureRegionAlignmentMode)mode + numRegions:(NSUInteger)numRegions + API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real convertSparsePixelRegions:pixelRegions + toTileRegions:tileRegions + withTileSize:tileSize + alignmentMode:mode + numRegions:numRegions]; +} + +- (void)convertSparseTileRegions:(const MTLRegion[_Nonnull])tileRegions + toPixelRegions:(MTLRegion[_Nonnull])pixelRegions + withTileSize:(MTLSize)tileSize + numRegions:(NSUInteger)numRegions + API_AVAILABLE(macos(11.0), macCatalyst(14.0), ios(13.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real convertSparseTileRegions:tileRegions + toPixelRegions:pixelRegions + withTileSize:tileSize + numRegions:numRegions]; +} + +- (NSUInteger)maxBufferLength API_AVAILABLE(macos(10.14), ios(12.0)) +{ + return self.real.maxBufferLength; +} + +- (NSArray> *)counterSets API_AVAILABLE(macos(10.15), ios(14.0)) +{ + return self.real.counterSets; +} + +- (nullable id)newCounterSampleBufferWithDescriptor: + (MTLCounterSampleBufferDescriptor *)descriptor + error:(NSError **)error + API_AVAILABLE(macos(10.15), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newCounterSampleBufferWithDescriptor:descriptor error:error]; +} + +- (void)sampleTimestamps:(MTLTimestamp *)cpuTimestamp + gpuTimestamp:(MTLTimestamp *)gpuTimestamp API_AVAILABLE(macos(10.15), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real sampleTimestamps:cpuTimestamp gpuTimestamp:gpuTimestamp]; +} + +- (BOOL)supportsCounterSampling:(MTLCounterSamplingPoint)samplingPoint + API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsCounterSampling:samplingPoint]; +} + +- (BOOL)supportsVertexAmplificationCount:(NSUInteger)count + API_AVAILABLE(macos(10.15.4), ios(13.0), macCatalyst(13.4)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real supportsVertexAmplificationCount:count]; +} + +- (BOOL)supportsDynamicLibraries API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsDynamicLibraries; +} + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (BOOL)supportsRenderDynamicLibraries API_AVAILABLE(macos(12.0), ios(15.0)) +{ + return self.real.supportsRenderDynamicLibraries; +} +#endif + +- (nullable id)newDynamicLibrary:(id)library + error:(NSError **)error + API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newDynamicLibrary:library error:error]; +} + +- (nullable id)newDynamicLibraryWithURL:(NSURL *)url + error:(NSError **)error + API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newDynamicLibraryWithURL:url error:error]; +} + +- (nullable id)newBinaryArchiveWithDescriptor:(MTLBinaryArchiveDescriptor *)descriptor + error:(NSError **)error + API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newBinaryArchiveWithDescriptor:descriptor error:error]; +} + +- (BOOL)supportsRaytracing API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsRaytracing; +} + +- (MTLAccelerationStructureSizes)accelerationStructureSizesWithDescriptor: + (MTLAccelerationStructureDescriptor *)descriptor API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real accelerationStructureSizesWithDescriptor:descriptor]; +} + +- (nullable id)newAccelerationStructureWithSize:(NSUInteger)size + API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newAccelerationStructureWithSize:size]; +} + +- (nullable id)newAccelerationStructureWithDescriptor: + (MTLAccelerationStructureDescriptor *)descriptor API_AVAILABLE(macos(11.0), ios(14.0)) +{ + NSLog(@"Not hooked %@", NSStringFromSelector(_cmd)); + return [self.real newAccelerationStructureWithDescriptor:descriptor]; +} + +- (BOOL)supportsFunctionPointers API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsFunctionPointers; +} + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (BOOL)supportsFunctionPointersFromRender API_AVAILABLE(macos(12.0), ios(15.0)) +{ + return self.real.supportsFunctionPointersFromRender; +} +#endif + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (BOOL)supportsRaytracingFromRender API_AVAILABLE(macos(12.0), ios(15.0)) +{ + return self.real.supportsRaytracingFromRender; +} +#endif + +// Treat as if the API is available from SDK 12.0 +// It is marked as available from SDK 11.0, however it was not present in SDK 11.1 MTLDevice.h +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0 +- (BOOL)supportsPrimitiveMotionBlur API_AVAILABLE(macos(11.0), ios(14.0)) +{ + return self.real.supportsPrimitiveMotionBlur; +} +#endif + +@end diff --git a/renderdoc/driver/metal/metal_dispatch_table_bridge.h b/renderdoc/driver/metal/metal_dispatch_table_bridge.h new file mode 100644 index 000000000..3353863f1 --- /dev/null +++ b/renderdoc/driver/metal/metal_dispatch_table_bridge.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * 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 + +#import +#include "common/common.h" + +// Global scope Metal functions from MTLDevice.h +typedef id (*PFN_MTLCreateSystemDefaultDevice)(void); +typedef NSArray> *(*PFN_MTLCopyAllDevices)(void); +typedef NSArray> *(*PFN_MTLCopyAllDevicesWithObserver)( + id *observer, MTLDeviceNotificationHandler handler); +typedef void (*PFN_MTLRemoveDeviceObserver)(id observer); + +// TODO: Global scope Metal device method from CGDirectDisplayMetal.h +// CG_EXTERN id __nullable CGDirectDisplayCopyCurrentMetalDevice(CGDirectDisplayID +// display) +// NS_RETURNS_RETAINED CG_AVAILABLE_STARTING(10.11); + +#define METAL_HOOKED_SYMBOLS(FUNC) FUNC(MTLCreateSystemDefaultDevice); + +#define METAL_NONHOOKED_SYMBOLS(FUNC) \ + FUNC(MTLCopyAllDevices); \ + FUNC(MTLCopyAllDevicesWithObserver); \ + FUNC(MTLRemoveDeviceObserver); + +struct MetalDispatchTable +{ + bool PopulateForReplay(); + +#define METAL_PTR_GEN(func) CONCAT(PFN_, func) func; + METAL_HOOKED_SYMBOLS(METAL_PTR_GEN) + METAL_NONHOOKED_SYMBOLS(METAL_PTR_GEN) +#undef METAL_PTR_GEN +}; + +extern MetalDispatchTable METAL; diff --git a/renderdoc/driver/metal/metal_dispatch_table_bridge.mm b/renderdoc/driver/metal/metal_dispatch_table_bridge.mm new file mode 100644 index 000000000..ba2073600 --- /dev/null +++ b/renderdoc/driver/metal/metal_dispatch_table_bridge.mm @@ -0,0 +1,47 @@ +/****************************************************************************** + * 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_dispatch_table_bridge.h" + +MetalDispatchTable METAL = {}; + +bool MetalDispatchTable::PopulateForReplay() +{ + bool symbols_ok = true; +#define LOAD_FUNC(func) \ + if(!this->func) \ + this->func = &::func; \ + \ + if(!this->func) \ + { \ + symbols_ok = false; \ + RDCWARN("Unable to load '%s'", STRINGIZE(func)); \ + } + + METAL_HOOKED_SYMBOLS(LOAD_FUNC) + METAL_NONHOOKED_SYMBOLS(LOAD_FUNC) + +#undef LOAD_FUNC + return symbols_ok; +} diff --git a/renderdoc/driver/metal/metal_hook.cpp b/renderdoc/driver/metal/metal_hook.cpp new file mode 100644 index 000000000..481e79a16 --- /dev/null +++ b/renderdoc/driver/metal/metal_hook.cpp @@ -0,0 +1,54 @@ +/****************************************************************************** + * 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_hook.h" +#include "core/core.h" + +static MetalHook metalhook; + +static void MetalHooked(void *handle) +{ + RDCDEBUG("Metal library hooked"); + + // store the handle for any pass-through implementations that need to look up their onward + // pointers + metalhook.handle = handle; + + // as a hook callback this is only called while capturing + RDCASSERT(!RenderDoc::Inst().IsReplayApp()); + + MetalHook::RegisterGlobalNonHookedMetalFunctions(); +} + +void MetalHook::RegisterHooks() +{ + RDCLOG("Registering Metal hooks"); + + // Library hooks : this should be framework hooks? + LibraryHooks::RegisterLibraryHook( + "/System/Library/Frameworks/Metal.framework/Versions/Current/Metal", &MetalHooked); + + // Function hooks + MetalHook::RegisterGlobalHookedMetalFunctions(); +} diff --git a/renderdoc/driver/metal/metal_hook.h b/renderdoc/driver/metal/metal_hook.h new file mode 100644 index 000000000..83fbbb5b8 --- /dev/null +++ b/renderdoc/driver/metal/metal_hook.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * 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 + +#include "hooks/hooks.h" + +class MetalHook : LibraryHook +{ +public: + MetalHook() {} + void RegisterHooks(); + static void RegisterGlobalNonHookedMetalFunctions(); + static void RegisterGlobalHookedMetalFunctions(); + + // default to RTLD_NEXT if we haven't gotten a more specific library handle + void *handle = RTLD_NEXT; +}; diff --git a/renderdoc/driver/metal/metal_hook_bridge.mm b/renderdoc/driver/metal/metal_hook_bridge.mm new file mode 100644 index 000000000..900b3a5cd --- /dev/null +++ b/renderdoc/driver/metal/metal_hook_bridge.mm @@ -0,0 +1,93 @@ +/****************************************************************************** + * 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_hook.h" +#include "core/core.h" +#include "hooks/hooks.h" +#include "metal_device.h" +#include "metal_dispatch_table_bridge.h" +#include "metal_types_bridge.h" + +#define METAL_EXPORT_NAME(function) CONCAT(interposed_, function) + +#define DECL_HOOK_EXPORT(function) \ + __attribute__((used)) static struct \ + { \ + const void *replacment; \ + const void *replacee; \ + } _interpose_def_##function __attribute__((section("__DATA,__interpose"))) = { \ + (const void *)(unsigned long)&METAL_EXPORT_NAME(function), \ + (const void *)(unsigned long)&function, \ + }; + +#define ForEachMetalSupported() METAL_FUNC(MTLCreateSystemDefaultDevice) + +id METAL_EXPORT_NAME(MTLCreateSystemDefaultDevice)(void) +{ + if(RenderDoc::Inst().IsReplayApp()) + { + if(!METAL.MTLCreateSystemDefaultDevice) + METAL.PopulateForReplay(); + + return METAL.MTLCreateSystemDefaultDevice(); + } + + id device = METAL.MTLCreateSystemDefaultDevice(); + return id(WrappedMTLDevice::MTLCreateSystemDefaultDevice((MTL::Device *)device)); +} + +/* + + APIs not currently hooked + +*** MTLDevice.h *** +NSArray > *METAL_EXPORT_NAME(MTLCopyAllDevices)(void); +NSArray > *METAL_EXPORT_NAME(MTLCopyAllDevicesWithObserver)(id* observer, +MTLDeviceNotificationHandler handler); +void METAL_EXPORT_NAME(MTLRemoveDeviceObserver)(id observer); + + *** CGDirectDisplayMetal.h *** + CG_EXTERN id __nullable CGDirectDisplayCopyCurrentMetalDevice(CGDirectDisplayID display) +NS_RETURNS_RETAINED CG_AVAILABLE_STARTING(10.11); + + */ + +void MetalHook::RegisterGlobalNonHookedMetalFunctions() +{ +// fetch non-hooked functions into our dispatch table +#define METAL_FETCH(func) METAL.func = &::func; + METAL_NONHOOKED_SYMBOLS(METAL_FETCH) +#undef METAL_FETCH +} + +void MetalHook::RegisterGlobalHookedMetalFunctions() +{ +#define METAL_FUNC(func) METAL.func = &::func; + ForEachMetalSupported(); +#undef METAL_FUNC +} + +#define METAL_FUNC(function) DECL_HOOK_EXPORT(function) +ForEachMetalSupported(); +#undef METAL_FUNC diff --git a/renderdoc/driver/metal/metal_resources.h b/renderdoc/driver/metal/metal_resources.h new file mode 100644 index 000000000..ecb9b6b09 --- /dev/null +++ b/renderdoc/driver/metal/metal_resources.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * 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 "core/resource_manager.h" +#include "metal_types.h" + +struct WrappedMTLObject +{ + WrappedMTLObject() = delete; + WrappedMTLObject(void *mtlObject, ResourceId objId, WrappedMTLDevice *wrappedMTLDevice) + : wrappedObjC(NULL), real(mtlObject), id(objId), m_WrappedMTLDevice(wrappedMTLDevice) + { + } + ~WrappedMTLObject() = default; + + void *wrappedObjC; + void *real; + ResourceId id; + WrappedMTLDevice *m_WrappedMTLDevice; +}; + +template +RealType Unwrap(WrappedMTLObject *obj) +{ + if(obj == NULL) + return RealType(); + + return (RealType)obj->real; +} + +template +RealType UnwrapObjC(WrappedMTLObject *obj) +{ + if(obj == NULL) + return RealType(); + + return (RealType)obj->wrappedObjC; +} diff --git a/renderdoc/driver/metal/metal_types.h b/renderdoc/driver/metal/metal_types.h new file mode 100644 index 000000000..0fe3d51b0 --- /dev/null +++ b/renderdoc/driver/metal/metal_types.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * 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 "official/metal-cpp.h" + +#define METALCPP_WRAPPED_PROTOCOLS(FUNC) FUNC(Device); + +#define DECLARE_OBJC_HELPERS(CPPTYPE) \ + class WrappedMTL##CPPTYPE; \ + extern MTL::CPPTYPE *AllocateObjCWrapper(WrappedMTL##CPPTYPE *wrapped); + +METALCPP_WRAPPED_PROTOCOLS(DECLARE_OBJC_HELPERS) +#undef DECLARE_OBJC_HELPERS diff --git a/renderdoc/driver/metal/metal_types_bridge.h b/renderdoc/driver/metal/metal_types_bridge.h new file mode 100644 index 000000000..1c96effd9 --- /dev/null +++ b/renderdoc/driver/metal/metal_types_bridge.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * 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_types.h" + +#import + +// clang-format off +#define DECLARE_OBJC_WRAPPED_INTERFACES(CPPTYPE) \ + @interface ObjCWrappedMTL##CPPTYPE : NSObject \ + @property(assign) WrappedMTL##CPPTYPE *wrappedCPP; \ + @property(readonly) id real; \ + @end +// clang-format on + +METALCPP_WRAPPED_PROTOCOLS(DECLARE_OBJC_WRAPPED_INTERFACES) +#undef DECLARE_OBJC_WRAPPED_INTERFACES diff --git a/renderdoc/driver/metal/metal_types_bridge.mm b/renderdoc/driver/metal/metal_types_bridge.mm new file mode 100644 index 000000000..6731079f6 --- /dev/null +++ b/renderdoc/driver/metal/metal_types_bridge.mm @@ -0,0 +1,43 @@ +/****************************************************************************** + * 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_types_bridge.h" +#include "metal_device.h" + +#define DEFINE_OBJC_HELPERS(CPPTYPE) \ + MTL::CPPTYPE *AllocateObjCWrapper(WrappedMTL##CPPTYPE *wrappedCPP) \ + { \ + ObjCWrappedMTL##CPPTYPE *objC = [ObjCWrappedMTL##CPPTYPE alloc]; \ + objC.wrappedCPP = wrappedCPP; \ + MTL::CPPTYPE *real = (MTL::CPPTYPE *)objC.real; \ + if(real) \ + { \ + objc_setAssociatedObject((id)real, objC, (id)objC, OBJC_ASSOCIATION_RETAIN); \ + [objC release]; \ + } \ + return (MTL::CPPTYPE *)objC; \ + } + +METALCPP_WRAPPED_PROTOCOLS(DEFINE_OBJC_HELPERS) +#undef DEFINE_OBJC_HELPERS