mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[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:
parent
ae96c36c55
commit
2e738ee40e
@ -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);
|
||||
};
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user