From 2e738ee40eeab407f31723fafd0336706cf889c1 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 29 Apr 2020 13:27:00 -0700 Subject: [PATCH] [Metal] On context loss with a paused texture source, preserve external pixel buffer. (#18022) Fixes https://github.com/flutter/flutter/issues/55783 Requires follow-up https://github.com/flutter/flutter/issues/55926 --- .../darwin/ios/ios_external_texture_metal.h | 4 +++- .../darwin/ios/ios_external_texture_metal.mm | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/ios_external_texture_metal.h b/shell/platform/darwin/ios/ios_external_texture_metal.h index efedc9f19f4..9bcce844d39 100644 --- a/shell/platform/darwin/ios/ios_external_texture_metal.h +++ b/shell/platform/darwin/ios/ios_external_texture_metal.h @@ -31,6 +31,7 @@ class IOSExternalTextureMetal final : public Texture { fml::CFRef texture_cache_; fml::scoped_nsobject> external_texture_; std::atomic_bool texture_frame_available_; + fml::CFRef last_pixel_buffer_; sk_sp external_image_; // |Texture| @@ -48,7 +49,8 @@ class IOSExternalTextureMetal final : public Texture { // |Texture| void OnTextureUnregistered() override; - sk_sp WrapExternalPixelBuffer(GrContext* context) const; + sk_sp WrapExternalPixelBuffer(fml::CFRef pixel_buffer, + GrContext* context) const; FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalTextureMetal); }; diff --git a/shell/platform/darwin/ios/ios_external_texture_metal.mm b/shell/platform/darwin/ios/ios_external_texture_metal.mm index e9871327123..a5ea79fb99b 100644 --- a/shell/platform/darwin/ios/ios_external_texture_metal.mm +++ b/shell/platform/darwin/ios/ios_external_texture_metal.mm @@ -30,11 +30,17 @@ void IOSExternalTextureMetal::Paint(SkCanvas& canvas, const bool needs_updated_texture = (!freeze && texture_frame_available_) || !external_image_; if (needs_updated_texture) { + auto pixel_buffer = fml::CFRef([external_texture_ copyPixelBuffer]); + if (!pixel_buffer) { + pixel_buffer = std::move(last_pixel_buffer_); + } + // If the application told us there was a texture frame available but did not provide one when // asked for it, reuse the previous texture but make sure to ask again the next time around. - if (auto wrapped_texture = WrapExternalPixelBuffer(context)) { + if (auto wrapped_texture = WrapExternalPixelBuffer(pixel_buffer, context)) { external_image_ = wrapped_texture; texture_frame_available_ = false; + last_pixel_buffer_ = std::move(pixel_buffer); } } @@ -48,8 +54,9 @@ void IOSExternalTextureMetal::Paint(SkCanvas& canvas, } } -sk_sp IOSExternalTextureMetal::WrapExternalPixelBuffer(GrContext* context) const { - auto pixel_buffer = fml::CFRef([external_texture_ copyPixelBuffer]); +sk_sp IOSExternalTextureMetal::WrapExternalPixelBuffer( + fml::CFRef pixel_buffer, + GrContext* context) const { if (!pixel_buffer) { return nullptr; } @@ -126,6 +133,10 @@ void IOSExternalTextureMetal::OnGrContextCreated() { } void IOSExternalTextureMetal::OnGrContextDestroyed() { + // The image must be reset because it is tied to the onscreen context. But the pixel buffer that + // created the image is still around. In case of context reacquisition, that last pixel + // buffer will be used to materialize the image in case the application fails to provide a new + // one. external_image_.reset(); CVMetalTextureCacheFlush(texture_cache_, // cache 0 // options (must be zero)