如何在 CIImageProcessorKernel 子类中为 Metal Compute 指定设备?

How to specify device for Metal Compute in CIImageProcessorKernel subclass?

我有一个自定义 CIFilter,使用 CIImageProcessorKernel 的子类实现。内核本身很简单:

@implementation ErosionFilterKernel

+ (BOOL)processWithInputs:(NSArray<id<CIImageProcessorInput>> *)inputs
                arguments:(NSDictionary<NSString *,id> *)arguments
                   output:(id<CIImageProcessorOutput>)output
                    error:(NSError *__autoreleasing *)error
{
    error = error ?: &(NSError * __autoreleasing){ nil };

    id<MTLCommandBuffer> commandBuffer = output.metalCommandBuffer;
    id<MTLTexture> sourceTexture = [inputs.firstObject metalTexture];
    id<MTLTexture> destinationTexture = output.metalTexture;

    NSInteger distance = [arguments[@"erosionDistance"] integerValue] ?: 1;

    MPSImageAreaMin *erodeFilter = [[MPSImageAreaMin alloc] initWithDevice:commandBuffer.device
                                                               kernelWidth:distance
                                                              kernelHeight:distance];
    [erodeFilter encodeToCommandBuffer:commandBuffer sourceTexture:sourceTexture destinationTexture:destinationTexture];
    return YES;
}

@end

这很好用,因为它产生了预期的结果。 我遇到的问题 是它在具有两个 GPU 的 MacBook Pro 上使用集成 GPU,我希望它使用独立 GPU。如果我将 MTLCreateSystemDefaultDevice()(离散 GPU)的结果传递给 -[MPSImageAreaMin initWithDevice:...],我会得到断言失败:

-[MTLDebugComputeCommandEncoder setComputePipelineState:] failed assertion computePipelineState is associated with a different device

这大概是因为负责运行-encodeToCommandBuffer:sourceTexture:destinationTexture:的机器内部使用的MTLComputeCommandEncoder实例已经设置为使用集成GPU。我认为这来自从CIImageProcessorOutput对象中提取的commandBuffer

我的问题: 可以指定-encodeToCommandBuffer:sourceTexture:destinationTexture:使用的GPU吗?据推测,这涉及自定义 output/metal 命令缓冲区,但我不确定。

使用哪个GPU应该由执行图像处理的CIContext决定。您应该能够使用 [CIContext contextWithMTLDevice:] 初始值设定项指定设备。

顺便说一句,从 macOS 10.15 开始,还有一个内置的 CIMorphologyRectangleMinimum filter that does the same. And there's also a circular version 从 10.13 开始可用。