测试托管缓冲区的最佳实践?
Best Practice for testing Managed Buffers?
在配备独立显卡的 Mac 上,应使用托管缓冲区而不是共享缓冲区,但是使用 [MTLBuffer:didModifyRange:] 保持同步还有其他要求。
但是在 Apple Silicon 上,如果我通过假装 [MTLDevice hasUnifiedMemory] returns NO
并删除对 didModifyRange:
的调用来强制使用托管缓冲区,则渲染是工作正常。
在统一 GPU 内存的 Apple Silicon 上测试托管缓冲区的最佳方法是什么,以便我可以确定我的代码可以在旧 Mac 上运行?
测试硬件兼容性的最佳做法是在您测试兼容性的实际硬件上进行。如果您计划支持与 Apple Silicon 本质上 不同的离散 GPU,最好能够访问一个进行测试。
您可能会有近似的行为,但请记住,这只是一种模拟,无法确保实际硬件的工作方式相同。
这类似于仅使用模拟器进行开发,这根本不是一个好的做法。
更新:有许多服务可以租用裸机 Mac。 MacInCloud 服务允许您配置带有外部 GPU 的机器(例如 AMD RX 580)。前 24 小时只需 0.99 美元。
那里有许多类似的服务,但这是我能够验证离散 GPU 是一种选择的第一项服务。
根据我的经验,在渲染 api 时没有测试代码的最佳实践,因为这里有许多不同的因素:
GPU 和 CPU 供应商(Apple、AMD、英特尔)、操作系统、驱动程序。
我同意Jeshua:
The best practice for testing hardware compatibility is on the actual
hardware in which you are testing compatibility.
有许多有用的方法可以使开发和测试更容易:
您可以检测 供应商 ID:
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
NSString* appleGPU = [device.name containsString:@"Apple"];
NSString* intelGPU = [device.name containsString:@"Intel"];
NSString* amdGPU = [device.name containsString:@"AMD"];
NSString* nvidiaGPU = [device.name containsString:@"Nvidia"];
使用 following method 你可以找到你的 gpu 类型:
bool externalGPU = [device isRemovable] == true;
bool integratedGPU = [device isLowPower] == true;
bool discreteGPU = [device isLowPower] == false;
注:
[device isLowPower];
On a Mac with an Apple silicon M1 chip, the property is NO because the
GPU runs with both high performance and low power.
确定TBDRGPU架构:
if (@available(macOS 10.15, *)) {
if ([device supportsFamily: MTLGPUFamilyApple4])
{
// The GPU does support Tile-Based Deferred Rendering technique
}
}
In a unified memory model, a resource with a MTLStorageModeManaged
mode resides in system memory accessible to both the CPU and the GPU.
行为类似于 MTLStorageModeShared
,只有一份内容。
注:
In a unified memory model, Metal may ignore
synchronization calls completely because it only creates a single
memory allocation for the resource.
您还可以检查其他开发人员的一些实现:
HgiMetalCapabilities::HgiMetalCapabilities(id<MTLDevice> device)
{
if (@available(macOS 10.14.5, ios 12.0, *)) {
_SetFlag(HgiDeviceCapabilitiesBitsConcurrentDispatch, true);
}
defaultStorageMode = MTLResourceStorageModeShared;
bool unifiedMemory = false;
if (@available(macOS 100.100, ios 12.0, *)) {
unifiedMemory = true;
} else if (@available(macOS 10.15, ios 13.0, *)) {
#if defined(ARCH_OS_IOS) || (defined(__MAC_10_15) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15)
unifiedMemory = [device hasUnifiedMemory];
#else
unifiedMemory = [device isLowPower];
#endif
}
_SetFlag(HgiDeviceCapabilitiesBitsUnifiedMemory, unifiedMemory);
#if defined(ARCH_OS_MACOS)
if (!unifiedMemory) {
defaultStorageMode = MTLResourceStorageModeManaged;
}
#endif
}
// Metal Managed:
// - applies to both buffers and textures
// - default mode for textures on macOS
// - two copies of each buffer or texture when discrete memory available
// - convenience of shared mode, performance of private mode
// - on unified systems behaves like shared memory and has only one copy of content
// - when writing, use:
// - buffer didModifyRange:
// - texture replaceRegion:
// - when reading, use:
// - encoder synchronizeResource: followed by
// - cmdbuff waitUntilCompleted (or completion handler)
// - buffer/texture getBytes:
在配备独立显卡的 Mac 上,应使用托管缓冲区而不是共享缓冲区,但是使用 [MTLBuffer:didModifyRange:] 保持同步还有其他要求。
但是在 Apple Silicon 上,如果我通过假装 [MTLDevice hasUnifiedMemory] returns NO
并删除对 didModifyRange:
的调用来强制使用托管缓冲区,则渲染是工作正常。
在统一 GPU 内存的 Apple Silicon 上测试托管缓冲区的最佳方法是什么,以便我可以确定我的代码可以在旧 Mac 上运行?
测试硬件兼容性的最佳做法是在您测试兼容性的实际硬件上进行。如果您计划支持与 Apple Silicon 本质上 不同的离散 GPU,最好能够访问一个进行测试。
您可能会有近似的行为,但请记住,这只是一种模拟,无法确保实际硬件的工作方式相同。
这类似于仅使用模拟器进行开发,这根本不是一个好的做法。
更新:有许多服务可以租用裸机 Mac。 MacInCloud 服务允许您配置带有外部 GPU 的机器(例如 AMD RX 580)。前 24 小时只需 0.99 美元。
那里有许多类似的服务,但这是我能够验证离散 GPU 是一种选择的第一项服务。
根据我的经验,在渲染 api 时没有测试代码的最佳实践,因为这里有许多不同的因素: GPU 和 CPU 供应商(Apple、AMD、英特尔)、操作系统、驱动程序。
我同意Jeshua:
The best practice for testing hardware compatibility is on the actual hardware in which you are testing compatibility.
有许多有用的方法可以使开发和测试更容易:
您可以检测 供应商 ID:
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
NSString* appleGPU = [device.name containsString:@"Apple"];
NSString* intelGPU = [device.name containsString:@"Intel"];
NSString* amdGPU = [device.name containsString:@"AMD"];
NSString* nvidiaGPU = [device.name containsString:@"Nvidia"];
使用 following method 你可以找到你的 gpu 类型:
bool externalGPU = [device isRemovable] == true;
bool integratedGPU = [device isLowPower] == true;
bool discreteGPU = [device isLowPower] == false;
注:
[device isLowPower];
On a Mac with an Apple silicon M1 chip, the property is NO because the GPU runs with both high performance and low power.
确定TBDRGPU架构:
if (@available(macOS 10.15, *)) {
if ([device supportsFamily: MTLGPUFamilyApple4])
{
// The GPU does support Tile-Based Deferred Rendering technique
}
}
In a unified memory model, a resource with a MTLStorageModeManaged mode resides in system memory accessible to both the CPU and the GPU.
行为类似于 MTLStorageModeShared
,只有一份内容。
注:
In a unified memory model, Metal may ignore synchronization calls completely because it only creates a single memory allocation for the resource.
您还可以检查其他开发人员的一些实现:
HgiMetalCapabilities::HgiMetalCapabilities(id<MTLDevice> device)
{
if (@available(macOS 10.14.5, ios 12.0, *)) {
_SetFlag(HgiDeviceCapabilitiesBitsConcurrentDispatch, true);
}
defaultStorageMode = MTLResourceStorageModeShared;
bool unifiedMemory = false;
if (@available(macOS 100.100, ios 12.0, *)) {
unifiedMemory = true;
} else if (@available(macOS 10.15, ios 13.0, *)) {
#if defined(ARCH_OS_IOS) || (defined(__MAC_10_15) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15)
unifiedMemory = [device hasUnifiedMemory];
#else
unifiedMemory = [device isLowPower];
#endif
}
_SetFlag(HgiDeviceCapabilitiesBitsUnifiedMemory, unifiedMemory);
#if defined(ARCH_OS_MACOS)
if (!unifiedMemory) {
defaultStorageMode = MTLResourceStorageModeManaged;
}
#endif
}
// Metal Managed:
// - applies to both buffers and textures
// - default mode for textures on macOS
// - two copies of each buffer or texture when discrete memory available
// - convenience of shared mode, performance of private mode
// - on unified systems behaves like shared memory and has only one copy of content
// - when writing, use:
// - buffer didModifyRange:
// - texture replaceRegion:
// - when reading, use:
// - encoder synchronizeResource: followed by
// - cmdbuff waitUntilCompleted (or completion handler)
// - buffer/texture getBytes: