我正在尝试使用苹果提供的默认 MPSKernal
滤镜和自定义 compute Shaders
通过 Metal 应用实时相机滤镜。
在计算着色器中,我使用 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)
}
}
但有时就地纹理往往会失败,最终会在屏幕上产生 SCSS 效果。
因此,如果有人可以在不使用就地纹理或如何使用 fallbackCopyAllocator
或以不同方式使用 compute shaders
的情况下向我建议解决方案,那将非常有帮助.
最佳答案
我在这方面做了足够的编码(将计算着色器应用于来自相机的视频流),您遇到的最常见问题是“像素缓冲区重用”问题。
您从样本缓冲区创建的 Metal 纹理备份到一个像素缓冲区,该缓冲区由视频 session 管理,并且可以重新用于后续视频帧,除非您保留对样本缓冲区的引用(保留仅提及 Metal 质感是不够的)。
请随时查看我的代码 https://github.com/snakajima/vs-metal ,它将各种计算着色器应用于实时视频流。
VSContext:set() 方法除了纹理参数外还接受可选的 sampleBuffer 参数,并保留对 sampleBuffer 的引用,直到计算着色器的计算完成(在 VSRuntime:encode() 方法中)。
关于ios - 如何使用 Metal 自定义计算着色器并获得非常流畅的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45214852/