Hello Skia Community,
We are working on tile rendering in a background thread using Skia with Metal on macOS. Our workflow involves:
Creating an MTLTexture in Objective-C++.
Wrapping it in a GrBackendTexture.
Creating a surface using SkSurfaces::WrapBackendTexture.
According to the documentation:
The caller must ensure the MTLTexture remains valid for the lifetime of the returned SkSurface.
If a textureReleaseProc is provided, it will be called when Skia determines the texture can be safely released.
In main thread, we also wrap the GrBackendTexture into an SkImage using SkImages::AdoptTextureFrom, which transfers ownership to Skia so that it releases the resource when no longer needed.
The Problem
We are seeing that GPU memory does not decrease as expected after tile rendering completes, even when textures should no longer be in use. We are uncertain about the proper lifetime management of the original MTLTexture, especially when both surfaces and images are involved. It is not always clear whether Skia will reliably trigger the release callback or handle cleanup internally.
Our Questions
When and how should the MTLTexture be released to ensure GPU memory is actually freed?
Is providing a custom textureReleaseProc always necessary? If so, what is the safest way to associate this with both SkSurfaces::WrapBackendTexture and SkImages::AdoptTextureFrom?
When using SkImages::AdoptTextureFrom, does Skia handle all cleanup for the underlying MTLTexture, or does the client still need to take additional steps?
Are there any best practices or reference-counting patterns recommended for tracking and releasing GPU textures across these APIs, especially in multi-threaded tile rendering scenarios?
Background
The relevant workflow is:
On a background thread, we create the Metal texture, wrap it as a GrBackendTexture, and generate a surface with SkSurfaces::WrapBackendTexture.
We perform drawing, flush with GrDirectContext::flushAndSubmit, and store the backend texture in an LRU dictionary.
Later, on the main thread, we call SkImages::AdoptTextureFrom for GPU-backed canvas rendering.
code snippet:
Cleanup Attempt
The LRU dictionary evicts the oldest texture when capacity is exceeded. In the custom deleter, we attempt to release the texture:
This custom deleter is invoked as expected when the texture is evicted. However, GPU memory usage does not decrease.
Could you clarify the correct way to manage Metal texture lifetimes when used with Skia in this workflow? Specifically, how can we ensure that GPU memory is properly released when textures are no longer needed?
Any advice, best practices, or concrete examples would be greatly appreciated.
Thanks in advance!