复杂的 CoreImage CIFilter 管道递归地消耗 GB 的内存

Complex CoreImage CIFilter pipeline recursively eats GBs of memory

我正在编写一个 macOS 应用程序,它对图像执行一系列复杂的 CIFilter 操作,以极大地改变高分辨率照片的外观,通常是 24 兆像素或更大。

其中一些效果包括高斯模糊、反锐化蒙版、泛光、暗淡,以及我使用自定义 CIKernel 在 Metal 中编写的自定义“颗粒”片段着色器。 CIContext 正在使用 Metal 设备渲染它。本质上,它是 initialImage -> CIFilter -> outputImage -> CIFilter -> outputImage -> CIFilter -> ...

的长链

不仅所有这些 CIFilters 必须按顺序 运行 用于最终输出,它们还必须在全分辨率上 运行 才能正确缩放效果。

我面临的问题是执行整个过程会导致大量使用内存。对于 6000x4000 输入图像,渲染时内存使用量跃升至 6.6GiB。

我使用 Xcode 中的 Metal 检测来诊断问题,似乎 CoreImage 正在为每个过滤器递归分配内存,因此内存不断堆积,直到它最终可以释放所有的内存资源在最后。

我希望这是顺序的,在下一个操作之前释放每个源缓冲区。我不确定如何帮助这种情况。有什么方法可以将每个输出图像传递给下一个过滤器,首先强制清理每个输入 CIImage 渲染?

if let device = self.device,
   let texture = device.makeTexture(descriptor: descriptor),
   let queue = device.makeCommandQueue(),
   let buffer = queue.makeCommandBuffer() {
    
    let destination = CIRenderDestination(
        width: descriptor.width,
        height: descriptor.height,
        pixelFormat: self.colorPixelFormat,
        commandBuffer: buffer) {
            return texture
        }
    
    try! metalImage.context.context.startTask(toRender: metalImage.image, to: destination)
    self.renderedImage = texture
    
    buffer.commit()
}

在没有任何 CIContext 的情况下向 NSImageView 显示 24 兆像素 CIImage 时,这似乎只使用了几百 MB 的内存。

let image = // Create CIImage from complex CIFilter pipeline

let rep = NSBitmapImageRep(ciImage: image)
let previewImage = NSImage(size: rep.size)
previewImage.addRepresentation(rep)
previewImageView?.image = previewImage

在 5K iMac 上,它会非常高效地进行预览渲染(更新时间不到半秒)。在使用 CGImageDestination.

导出图像之前不需要 CIContexts