Shreesha Kedlaya
Shreesha Kedlaya

Reputation: 350

Memory leak when I use custom compute shaders in Metal

Im trying to apply the live camera filters through metal using the default MPSKernal filters given by apple and custom compute Shaders.

Im applying the custom filters on a collection view in a grid with the combination of default and the custom kernel functions.

It looks like in the app Clips.

enter image description here

But what I observed is that using the custom filters there is a lot of memory leaks compared to the default kernel functions given by apple.

I don't know what mistakes I made though if any.

Here is my custom compute shader.

kernel void customFunction1(

                       texture2d<float, access::read> inTexture [[texture(0)]],

                       texture2d<float, access::write> outTexture [[texture(1)]],

                       uint2 gid [[thread_position_in_grid]]){

const float4 colorAtPixel = inTexture.read(gid);
const float4 outputColor = float4(colorAtPixel.r, colorAtPixel.g, colorAtPixel.b, 1);

outTexture.write(outputColor, gid);

}

Regarding to my creating my pipeline and the dispatching through thread groups the code goes here

let blur = MPSImageGaussianBlur(device: device, sigma: 0)

    let threadsPerThreadgroup = MTLSizeMake(4, 4, 1)
    let threadgroupsPerGrid = MTLSizeMake(destinationTexture.width / threadsPerThreadgroup.width, destinationTexture.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 {
        let inPlaceTexture = UnsafeMutablePointer<MTLTexture>.allocate(capacity: 1)
        inPlaceTexture.initialize(to: destinationTexture)
        blur.encode(commandBuffer: commandBuffer, inPlaceTexture: inPlaceTexture, fallbackCopyAllocator: nil)
    }

The Pipeline state with the custom Shader is created like this.

        let defaultLibrary = device.newDefaultLibrary()

        let kernelFunction = defaultLibrary!.makeFunction(name: name)

        do {
            pipelineState = try device.makeComputePipelineState(function: kernelFunction!)
        } catch {
            fatalError("Unable to create pipeline state")
        }

And in instrumentation it shows there is a leak in some Malloc 16 bytes and in [Mtkview draw] method.

The screenshot is shown below.

enter image description here

I want help in finding where and how the issue is occurring from.

Thanks.

Upvotes: 0

Views: 1159

Answers (1)

warrenm
warrenm

Reputation: 31782

There's no reason to explicitly allocate an UnsafeMutablePointer to store the in-place texture parameter. Incidentally, that's the source of your leak: you allocate the pointer and then never deallocate it.

Use a local variable to pass the texture instead:

var inPlaceTexture = destinationTexture
blur.encode(commandBuffer: commandBuffer, inPlaceTexture: &inPlaceTexture, fallbackCopyAllocator: nil)

By the way, you're (eventually) going to have a bad time if you call the in-place encode method without providing a fallback allocator or checking the return value. In-place encoding will fail in certain situations, so you should provide a closure that allocates an appropriate texture in the event of failure.

Upvotes: 2

Related Questions