在两个金属计算编码器之间快速传递可变MTLBuffer

时间:2018-06-08 23:21:23

标签: metal

在某些目标c类中,我有一个缓冲区,由两个连续的金属管道使用。一个内核根据图像的rgb亮度处理值并写入可变缓冲区,然后根据第一个中的数据绘制波形图。它基于此处描述的osx着色器USING METAL PERFORMANCE SHADERS WITH CORE IMAGE

我设法将这个从osx转换为IOS,这很有效,但我现在正试图将其转换为swift,以便将来更灵活。我还有其他我想写的过滤器,翻译过程也教会了我很多金属管道的工作原理。

这是它崩溃的地方。它绘制的图形有一条水平彩色线条上下飘动。关闭但没有雪茄。我想知道它是否与如何在swift vs objective c中创建缓冲区有关。这是原作的一个例子:

size_t columnBufSize = sizeof(UInt64)*inputTexture.width*inputTexture.height;
id<MTLBuffer> columnDataRed = [kDevice newBufferWithLength:columnBufSize options:0];

但是当我快速翻译它时,它的表现并不像预期的那样。

 let columnBufSize: size_t = MemoryLayout<UInt64>.size * inputTexture!.width  * inputTexture!.height
 let columnDataRed: MTLBuffer  = kDevice.makeBuffer( length: columnBufSize, options: .storageModeShared)!

看起来只有最后一个值传递给第二个computeEncoder。

我错过了什么?

完成,这是目标c

中的完整代码
+ (BOOL)processWithInputs:(NSArray<id<CIImageProcessorInput>> *)inputs arguments:(NSDictionary<NSString *,id> *)arguments output:(id<CIImageProcessorOutput>)output error:(NSError * _Nullable *)error
{
    id<MTLComputePipelineState> renderComputerState = kParadeComputePipelineState;



    id<CIImageProcessorInput> input = inputs.firstObject;

    id<MTLCommandBuffer> commandBuffer = output.metalCommandBuffer;
    commandBuffer.label = @"com.martinhering.WaveformKernel";
    id<MTLTexture> inputTexture = input.metalTexture;
    id<MTLTexture> outputTexture = output.metalTexture;

    MTLSize threadgroupCount = MTLSizeMake(inputTexture.width, inputTexture.height, 1);
    MTLSize _threadgroupSize = MTLSizeMake(16, 16, 1);

    threadgroupCount.width  = (inputTexture.width  + _threadgroupSize.width -  1) / _threadgroupSize.width;
    threadgroupCount.height = (inputTexture.height + _threadgroupSize.height - 1) / _threadgroupSize.height;


    size_t columnBufSize = sizeof(UInt64)*inputTexture.width*inputTexture.height;
    id<MTLBuffer> columnDataRed = [kDevice newBufferWithLength:columnBufSize options:0];
    id<MTLBuffer> columnDataGreen = [kDevice newBufferWithLength:columnBufSize options:0];
    id<MTLBuffer> columnDataBlue = [kDevice newBufferWithLength:columnBufSize options:0];

    id<MTLComputeCommandEncoder> computeEncoder;

    computeEncoder = [commandBuffer computeCommandEncoder];
    [computeEncoder setComputePipelineState:kWaveformComputePipelineState];
    [computeEncoder setTexture:inputTexture atIndex:0];
    [computeEncoder setBuffer:columnDataRed offset:0 atIndex:0];
    [computeEncoder setBuffer:columnDataGreen offset:0 atIndex:1];
    [computeEncoder setBuffer:columnDataBlue offset:0 atIndex:2];
    [computeEncoder setSamplerState:kSamplerState atIndex:0];
    [computeEncoder dispatchThreadgroups:threadgroupCount
                   threadsPerThreadgroup:_threadgroupSize];

    [computeEncoder endEncoding];


    computeEncoder = [commandBuffer computeCommandEncoder];
    [computeEncoder setComputePipelineState:renderComputerState];
    [computeEncoder setTexture:inputTexture atIndex:0];
    [computeEncoder setTexture:outputTexture atIndex:1];
    [computeEncoder setBuffer:columnDataRed offset:0 atIndex:0];
    [computeEncoder setBuffer:columnDataGreen offset:0 atIndex:1];
    [computeEncoder setBuffer:columnDataBlue offset:0 atIndex:2];
    [computeEncoder setSamplerState:kSamplerState atIndex:0];
    [computeEncoder dispatchThreadgroups:threadgroupCount
                   threadsPerThreadgroup:_threadgroupSize];

    [computeEncoder endEncoding];
    return YES;
}

这是我的翻译

override class func process(with inputs: [CIImageProcessorInput]?, arguments: [String : Any]?, output: CIImageProcessorOutput) throws {

    guard
        let kDevice = device,
        let commandBuffer = output.metalCommandBuffer,
        let input = inputs?.first,
        let defaultLibrary: MTLLibrary = kDevice.makeDefaultLibrary()
    else  {
        return
    }

     let samplerDescriptor = MTLSamplerDescriptor()
    let  kSamplerState = kDevice.makeSamplerState(descriptor: samplerDescriptor)

    samplerDescriptor.sAddressMode = .clampToEdge
    samplerDescriptor.tAddressMode = .clampToEdge
    samplerDescriptor.minFilter = .nearest
    samplerDescriptor.magFilter = .nearest
    samplerDescriptor.normalizedCoordinates = false


      var kWaveformComputePipelineState: MTLComputePipelineState?         
      var kParadeComputePipelineState: MTLComputePipelineState?


    if let aFunction = defaultLibrary.makeFunction(name: "scope_waveform_compute") {
        kWaveformComputePipelineState = try? kDevice.makeComputePipelineState(function: aFunction)
    }

    if let aFunction = defaultLibrary.makeFunction(name: "scope_waveform_parade") {
        kParadeComputePipelineState = try? kDevice.makeComputePipelineState(function: aFunction)
    }






    commandBuffer.label = "com.martinhering.WaveformKernel"

    weak var inputTexture: MTLTexture? = input.metalTexture
    weak var outputTexture: MTLTexture? = output.metalTexture

    var threadgroupCount: MTLSize = MTLSizeMake(inputTexture!.width, inputTexture!.height, 1)
    let threadgroupSize: MTLSize = MTLSizeMake(16, 16, 1)
    threadgroupCount.width = (inputTexture!.width  + threadgroupSize.width - 1) / threadgroupSize.width
    threadgroupCount.height = (inputTexture!.height + threadgroupSize.height - 1) / threadgroupSize.height


    let columnBufSize: size_t = MemoryLayout<UInt64>.size * inputTexture!.width  * inputTexture!.height

    let columnDataRed: MTLBuffer  = kDevice.makeBuffer( length: columnBufSize, options: .storageModeShared)!
    let columnDataGreen: MTLBuffer  = kDevice.makeBuffer( length: columnBufSize, options: .storageModeShared)!
    let columnDataBlue: MTLBuffer  = kDevice.makeBuffer( length: columnBufSize, options: .storageModeShared)!


    weak var computeEncoder: MTLComputeCommandEncoder?

    computeEncoder = commandBuffer.makeComputeCommandEncoder()
    computeEncoder?.setComputePipelineState(kWaveformComputePipelineState!)
    computeEncoder?.setTexture(inputTexture, index: 0)
    computeEncoder?.setBuffer(columnDataRed, offset: 0, index: 0)
    computeEncoder?.setBuffer(columnDataGreen, offset: 0, index: 1)
    computeEncoder?.setBuffer(columnDataBlue, offset: 0, index: 2)
    computeEncoder?.setSamplerState(kSamplerState, index: 0)
    computeEncoder?.dispatchThreadgroups(threadgroupCount, threadsPerThreadgroup: threadgroupSize)
    computeEncoder?.endEncoding()


    computeEncoder = commandBuffer.makeComputeCommandEncoder()
    computeEncoder?.setComputePipelineState(kParadeComputePipelineState!)
    computeEncoder?.setTexture(inputTexture, index: 0)
    computeEncoder?.setTexture(outputTexture, index: 1)
    computeEncoder?.setBuffer(columnDataRed, offset: 0, index: 0)
    computeEncoder?.setBuffer(columnDataGreen, offset: 0, index: 1)
    computeEncoder?.setBuffer(columnDataBlue, offset: 0, index: 2)
    computeEncoder?.setSamplerState(kSamplerState, index: 0)
    computeEncoder?.dispatchThreadgroups(threadgroupCount, threadsPerThreadgroup: threadgroupSize)
    computeEncoder?.endEncoding()

//返回true

}

1 个答案:

答案 0 :(得分:0)

非常感谢Ken Thomases;最后这很简单。

在创建samplerState之前,必须设置采样器描述符的属性。

sum()