[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
This commit is contained in:
Chinmay Garde 2020-04-29 13:27:00 -07:00 committed by GitHub
parent ae96c36c55
commit 2e738ee40e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 4 deletions

View File

@ -31,6 +31,7 @@ class IOSExternalTextureMetal final : public Texture {
fml::CFRef<CVMetalTextureCacheRef> texture_cache_;
fml::scoped_nsobject<NSObject<FlutterTexture>> external_texture_;
std::atomic_bool texture_frame_available_;
fml::CFRef<CVPixelBufferRef> last_pixel_buffer_;
sk_sp<SkImage> external_image_;
// |Texture|
@ -48,7 +49,8 @@ class IOSExternalTextureMetal final : public Texture {
// |Texture|
void OnTextureUnregistered() override;
sk_sp<SkImage> WrapExternalPixelBuffer(GrContext* context) const;
sk_sp<SkImage> WrapExternalPixelBuffer(fml::CFRef<CVPixelBufferRef> pixel_buffer,
GrContext* context) const;
FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalTextureMetal);
};

View File

@ -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<CVPixelBufferRef>([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<SkImage> IOSExternalTextureMetal::WrapExternalPixelBuffer(GrContext* context) const {
auto pixel_buffer = fml::CFRef<CVPixelBufferRef>([external_texture_ copyPixelBuffer]);
sk_sp<SkImage> IOSExternalTextureMetal::WrapExternalPixelBuffer(
fml::CFRef<CVPixelBufferRef> 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)