mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 07:26:34 +00:00
Metal: basic hooking and MTLDevice wrapping
This commit is contained in:
committed by
Baldur Karlsson
parent
9d6526ff6e
commit
b72bdb2b9a
@@ -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)
|
||||
|
||||
|
||||
@@ -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<MTL::Device *>(wrappedMTLDevice);
|
||||
}
|
||||
@@ -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:
|
||||
};
|
||||
@@ -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 <Availability.h>
|
||||
#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<MTLDevice>)real
|
||||
{
|
||||
MTL::Device *real = Unwrap<MTL::Device *>(self.wrappedCPP);
|
||||
return id<MTLDevice>(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<MTLCommandQueue>)newCommandQueue
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newCommandQueue];
|
||||
}
|
||||
|
||||
- (nullable id<MTLCommandQueue>)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<MTLHeap>)newHeapWithDescriptor:(MTLHeapDescriptor *)descriptor
|
||||
API_AVAILABLE(macos(10.13), ios(10.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newHeapWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
- (nullable id<MTLBuffer>)newBufferWithLength:(NSUInteger)length options:(MTLResourceOptions)options
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newBufferWithLength:length options:options];
|
||||
}
|
||||
|
||||
- (nullable id<MTLBuffer>)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<MTLBuffer>)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<MTLDepthStencilState>)newDepthStencilStateWithDescriptor:
|
||||
(MTLDepthStencilDescriptor *)descriptor
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newDepthStencilStateWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
- (nullable id<MTLTexture>)newTextureWithDescriptor:(MTLTextureDescriptor *)descriptor
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newTextureWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
- (nullable id<MTLTexture>)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<MTLTexture>)newSharedTextureWithDescriptor:(MTLTextureDescriptor *)descriptor
|
||||
API_AVAILABLE(macos(10.14), ios(13.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newSharedTextureWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
- (nullable id<MTLTexture>)newSharedTextureWithHandle:(MTLSharedTextureHandle *)sharedHandle
|
||||
API_AVAILABLE(macos(10.14), ios(13.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newSharedTextureWithHandle:sharedHandle];
|
||||
}
|
||||
|
||||
- (nullable id<MTLSamplerState>)newSamplerStateWithDescriptor:(MTLSamplerDescriptor *)descriptor
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newSamplerStateWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
- (nullable id<MTLLibrary>)newDefaultLibrary
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newDefaultLibrary];
|
||||
}
|
||||
|
||||
- (nullable id<MTLLibrary>)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<MTLLibrary>)newLibraryWithFile:(NSString *)filepath
|
||||
error:(__autoreleasing NSError **)error
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newLibraryWithFile:filepath error:error];
|
||||
}
|
||||
|
||||
- (nullable id<MTLLibrary>)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<MTLLibrary>)newLibraryWithData:(dispatch_data_t)data
|
||||
error:(__autoreleasing NSError **)error
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newLibraryWithData:data error:error];
|
||||
}
|
||||
|
||||
- (nullable id<MTLLibrary>)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<MTLLibrary>)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<MTLRenderPipelineState>)
|
||||
newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor
|
||||
error:(__autoreleasing NSError **)error
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newRenderPipelineStateWithDescriptor:descriptor error:error];
|
||||
}
|
||||
|
||||
- (nullable id<MTLRenderPipelineState>)
|
||||
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<MTLComputePipelineState>)
|
||||
newComputePipelineStateWithFunction:(id<MTLFunction>)computeFunction
|
||||
error:(__autoreleasing NSError **)error
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newComputePipelineStateWithFunction:computeFunction error:error];
|
||||
}
|
||||
|
||||
- (nullable id<MTLComputePipelineState>)
|
||||
newComputePipelineStateWithFunction:(id<MTLFunction>)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<MTLFunction>)computeFunction
|
||||
completionHandler:(MTLNewComputePipelineStateCompletionHandler)completionHandler
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newComputePipelineStateWithFunction:computeFunction
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)newComputePipelineStateWithFunction:(id<MTLFunction>)computeFunction
|
||||
options:(MTLPipelineOption)options
|
||||
completionHandler:
|
||||
(MTLNewComputePipelineStateWithReflectionCompletionHandler)completionHandler
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newComputePipelineStateWithFunction:computeFunction
|
||||
options:options
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (nullable id<MTLComputePipelineState>)
|
||||
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<MTLFence>)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<MTLRenderPipelineState>)
|
||||
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<MTLArgumentEncoder>)newArgumentEncoderWithArguments:
|
||||
(NSArray<MTLArgumentDescriptor *> *)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<MTLRasterizationRateMap>)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<MTLIndirectCommandBuffer>)
|
||||
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<MTLEvent>)newEvent API_AVAILABLE(macos(10.14), ios(12.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newEvent];
|
||||
}
|
||||
|
||||
- (nullable id<MTLSharedEvent>)newSharedEvent API_AVAILABLE(macos(10.14), ios(12.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newSharedEvent];
|
||||
}
|
||||
|
||||
- (nullable id<MTLSharedEvent>)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<id<MTLCounterSet>> *)counterSets API_AVAILABLE(macos(10.15), ios(14.0))
|
||||
{
|
||||
return self.real.counterSets;
|
||||
}
|
||||
|
||||
- (nullable id<MTLCounterSampleBuffer>)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<MTLDynamicLibrary>)newDynamicLibrary:(id<MTLLibrary>)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<MTLDynamicLibrary>)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<MTLBinaryArchive>)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<MTLAccelerationStructure>)newAccelerationStructureWithSize:(NSUInteger)size
|
||||
API_AVAILABLE(macos(11.0), ios(14.0))
|
||||
{
|
||||
NSLog(@"Not hooked %@", NSStringFromSelector(_cmd));
|
||||
return [self.real newAccelerationStructureWithSize:size];
|
||||
}
|
||||
|
||||
- (nullable id<MTLAccelerationStructure>)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
|
||||
@@ -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 <Metal/MTLDevice.h>
|
||||
#include "common/common.h"
|
||||
|
||||
// Global scope Metal functions from MTLDevice.h
|
||||
typedef id<MTLDevice> (*PFN_MTLCreateSystemDefaultDevice)(void);
|
||||
typedef NSArray<id<MTLDevice>> *(*PFN_MTLCopyAllDevices)(void);
|
||||
typedef NSArray<id<MTLDevice>> *(*PFN_MTLCopyAllDevicesWithObserver)(
|
||||
id<NSObject> *observer, MTLDeviceNotificationHandler handler);
|
||||
typedef void (*PFN_MTLRemoveDeviceObserver)(id<NSObject> observer);
|
||||
|
||||
// TODO: Global scope Metal device method from CGDirectDisplayMetal.h
|
||||
// CG_EXTERN id<MTLDevice> __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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 <dlfcn.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
@@ -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<MTLDevice> METAL_EXPORT_NAME(MTLCreateSystemDefaultDevice)(void)
|
||||
{
|
||||
if(RenderDoc::Inst().IsReplayApp())
|
||||
{
|
||||
if(!METAL.MTLCreateSystemDefaultDevice)
|
||||
METAL.PopulateForReplay();
|
||||
|
||||
return METAL.MTLCreateSystemDefaultDevice();
|
||||
}
|
||||
|
||||
id<MTLDevice> device = METAL.MTLCreateSystemDefaultDevice();
|
||||
return id<MTLDevice>(WrappedMTLDevice::MTLCreateSystemDefaultDevice((MTL::Device *)device));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
APIs not currently hooked
|
||||
|
||||
*** MTLDevice.h ***
|
||||
NSArray <id<MTLDevice>> *METAL_EXPORT_NAME(MTLCopyAllDevices)(void);
|
||||
NSArray <id<MTLDevice>> *METAL_EXPORT_NAME(MTLCopyAllDevicesWithObserver)(id<NSObject>* observer,
|
||||
MTLDeviceNotificationHandler handler);
|
||||
void METAL_EXPORT_NAME(MTLRemoveDeviceObserver)(id <NSObject> observer);
|
||||
|
||||
*** CGDirectDisplayMetal.h ***
|
||||
CG_EXTERN id<MTLDevice> __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
|
||||
@@ -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 <typename RealType>
|
||||
RealType Unwrap(WrappedMTLObject *obj)
|
||||
{
|
||||
if(obj == NULL)
|
||||
return RealType();
|
||||
|
||||
return (RealType)obj->real;
|
||||
}
|
||||
|
||||
template <typename RealType>
|
||||
RealType UnwrapObjC(WrappedMTLObject *obj)
|
||||
{
|
||||
if(obj == NULL)
|
||||
return RealType();
|
||||
|
||||
return (RealType)obj->wrappedObjC;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <Metal/MTLDevice.h>
|
||||
|
||||
// clang-format off
|
||||
#define DECLARE_OBJC_WRAPPED_INTERFACES(CPPTYPE) \
|
||||
@interface ObjCWrappedMTL##CPPTYPE : NSObject<MTL##CPPTYPE> \
|
||||
@property(assign) WrappedMTL##CPPTYPE *wrappedCPP; \
|
||||
@property(readonly) id<MTL##CPPTYPE> real; \
|
||||
@end
|
||||
// clang-format on
|
||||
|
||||
METALCPP_WRAPPED_PROTOCOLS(DECLARE_OBJC_WRAPPED_INTERFACES)
|
||||
#undef DECLARE_OBJC_WRAPPED_INTERFACES
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user