Ios 如何使用自定义计算着色器使用金属并获得非常平滑的性能?

Ios 如何使用自定义计算着色器使用金属并获得非常平滑的性能?,ios,swift,metal,metal-performance-shaders,Ios,Swift,Metal,Metal Performance Shaders,我正在尝试使用苹果提供的默认MPSKernal过滤器和自定义compute着色器通过金属应用实时相机过滤器 在计算着色器中,我使用MPSImageGaussianBlur进行了就地编码 代码在这里 func encode(to commandBuffer: MTLCommandBuffer, sourceTexture: MTLTexture, destinationTexture: MTLTexture, cropRect: MTLRegion = MTLRegion.init(), offs

我正在尝试使用苹果提供的默认
MPSKernal
过滤器和自定义
compute着色器
通过金属应用实时相机过滤器

在计算着色器中,我使用MPSImageGaussianBlur进行了就地编码 代码在这里

func encode(to commandBuffer: MTLCommandBuffer, sourceTexture: MTLTexture, destinationTexture: MTLTexture, cropRect: MTLRegion = MTLRegion.init(), offset : CGPoint) {

    let blur = MPSImageGaussianBlur(device: device, sigma: 0)
    blur.clipRect = cropRect
    blur.offset = MPSOffset(x: Int(offset.x), y: Int(offset.y), z: 0)

    let threadsPerThreadgroup = MTLSizeMake(4, 4, 1)
    let threadgroupsPerGrid = MTLSizeMake(sourceTexture.width / threadsPerThreadgroup.width, sourceTexture.height / threadsPerThreadgroup.height, 1)

    let commandEncoder = commandBuffer.makeComputeCommandEncoder()
    commandEncoder.setComputePipelineState(pipelineState!)
    commandEncoder.setTexture(sourceTexture, at: 0)
    commandEncoder.setTexture(destinationTexture, at: 1)

    commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup)

    commandEncoder.endEncoding()

    autoreleasepool {
        var inPlaceTexture = destinationTexture
        blur.encode(commandBuffer: commandBuffer, inPlaceTexture: &inPlaceTexture, fallbackCopyAllocator: nil)
    }
}
但有时,内置纹理往往会失败,最终会在屏幕上产生一种抖动效果


因此,如果有人可以向我推荐解决方案,而不必使用inplace纹理或如何使用
fallbackCopyAllocator
,或者以不同的方式使用
计算着色器
,这将非常有帮助。

我在这方面已经做了足够的编码(将计算着色器应用于来自摄影机的视频流),您遇到的最常见的问题是“像素缓冲区重用”问题

从采样缓冲区创建的金属纹理将备份一个像素缓冲区,该缓冲区由视频会话管理,并可重新用于后续视频帧,除非保留对采样缓冲区的引用(仅保留对金属纹理的引用是不够的)

请随意查看我的代码,它将各种计算着色器应用于实时视频流


VSContext:set()方法除了纹理参数外,还接受可选的sampleBuffer参数,并保留对sampleBuffer的引用,直到计算着色器的计算完成(在VSRuntime:encode()方法中)

根据底层过滤器的操作,可以命中或未命中就地操作方法。如果某些参数是单通滤波器,那么在这些情况下,您将无法使用它

自从添加了该方法之后,MPS已经添加了一个底层MTLHeap,以便对内存进行更透明的管理。如果您的MPS图像不需要CPU查看,并且在GPU上只存在很短的一段时间,建议您只使用MPS图像。当readCount达到0时,备份存储将通过MPS堆回收,并可用于其他MPS临时图像和下游使用的其他临时资源。类似地,在绝对必要(例如,将纹理写入或调用.texture)为每个命令缓冲区分配单独的堆之前,不会从堆中实际分配它的备份存储


使用临时映像应有助于大大减少内存使用。例如,在一个具有100多次传递的Inception v3神经网络图中,堆能够自动将该图减少到仅四次分配。

为什么在调用
endEncoding()后要对
模糊进行编码
在命令编码器上?@MatthijsHollemans我使用命令编码器将管道状态编码为GPU可理解语言。这是通过创建MTLLibrary并创建函数,然后创建管道状态以编码到命令编码器来完成的。命令编码器的目的是设置进程的状态(在本例中,将计算着色器编码到GPU)。完成编码后,告诉GPU它已准备好将其编码到GPU。谢谢等待建议。我的错,我误读了你的代码。顺便说一句,试着做这个
let blur=MPSImageGaussianBlur(device:device,sigma:0)
就一次,不是每次你调用这个编码函数。@MatthijsHollemans是的,我真的这么做了。但是我不能使用内置纹理进行裁剪和设置偏移,这就是为什么我要问如何使用内置纹理以不同的方式进行裁剪和偏移纹理。如果你有什么想法,建议我。非常感谢。这些信息足够我做我必须做的事情。谢谢你提供的信息。一旦我在我的应用程序中集成并测试它,我将对此进行更新。