CIKernel ROI Callback Leak

The ROI callback that is passed to a CIKernel’s apply(…) method seems to be referenced beyond the render call and is not released properly. That also means that any captured state is retained longer than expected.

I noticed this in a camera capture scenario because the capture session stopped delivering new frames after the initial batch. The output ran out of buffers because they were not properly returned to the pool. I was capturing the filter’s input image in the ROI callback like in this simplified case:

override var outputImage: CIImage? {
    guard let inputImage = inputImage else { return nil }
    let roiCallback: CIKernelROICallback = { _, _ in
        return inputImage.extent
    }
    return Self.kernel.apply(extent: inputImage.extent, roiCallback: roiCallback, arguments: [inputImage])
}

While it is avoidable in this case, it is also very unexpected that the ROI callback is retained longer than needed for rendering the output image. Even when not capturing a lot of state, this would still unnecessarily accumulate over time.

Note that calling ciContext.clearCaches() does actually seem to release the captured ROI callbacks. But I don’t want to do that after every frame since there are also resources worth caching.

Is there a reason why Core Image caches the ROI callbacks beyond the rendering calls they are involved in?

Also filed as FB9989184.

CIKernel ROI Callback Leak
 
 
Q