fix: Fix Metal NativeBuffer flickering issue #2372
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
William and I experienced a flickering issue that appeared after a while when playing back a video using the NativeBuffer APIs.
After 5 hours of debugging and countless of print statements and renderer code rewrites, I figured out that the
CVMetalTextureCacheRef
apparently felt free to overwrite old MTLTexture buffers after a while because we didn't hold a strong reference to the texture holder!In our case
CVMetalTextureCacheCreateTextureFromImage
gave us aCVMetalTextureRef
, which we only used for the lifetime of thegetSkiaTextureForCVPixelBufferPlane
method, when in reality we should've held a reference on this for longer.Effectively this
CFRelease
was the reason our metal texture cache pool felt free to overwrite old buffers:// 1. Get Metal Texture from Sample Buffer CVMetalTextureRef textureHolder; CVReturn result = CVMetalTextureCacheCreateTextureFromImage( kCFAllocatorDefault, textureCache, pixelBuffer, nil, pixelFormat, width, height, planeIndex, &textureHolder); // 2. Unwrap the underlying MTLTexture id<MTLTexture> mtlTexture = CVMetalTextureGetTexture(textureHolder); if (mtlTexture == nil) [[unlikely]] { throw std::runtime_error( "Failed to get MTLTexture from CVMetalTextureRef!"); } // 3. Wrap MTLTexture in Skia's GrBackendTexture GrMtlTextureInfo textureInfo; textureInfo.fTexture.retain((__bridge void *)mtlTexture); GrBackendTexture texture = GrBackendTexture((int)mtlTexture.width, (int)mtlTexture.height, skgpu::Mipmapped::kNo, textureInfo); - CFRelease(textureHolder); return texture;
With this PR this is now fixed, and
CFRelease(textureHolder)
is now only called when theSkImage
is destroyed.cc @wcandillon