Re-create texture from pixel buffer onGrContextCreate (#8792)

* Re-create texture from pixel buffer onGrContextCreate

OnGrContextDestroy we destroy the texture, this is because
we can not access it from the potentially new context that
we get on bringing the app back to foreground.

To show a valid texture on fg, we need to preserve the pixel
buffer, using which we will create the new texture.

* ensure texture cache exists

* only reset pixel buffer if not null.
diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.h b/shell/platform/darwin/ios/ios_external_texture_gl.h
index 3c15ac9..923f741 100644
--- a/shell/platform/darwin/ios/ios_external_texture_gl.h
+++ b/shell/platform/darwin/ios/ios_external_texture_gl.h
@@ -27,9 +27,14 @@
   void MarkNewFrameAvailable() override;
 
  private:
+  void CreateTextureFromPixelBuffer();
+
+  void EnsureTextureCacheExists();
+
   NSObject<FlutterTexture>* external_texture_;
   fml::CFRef<CVOpenGLESTextureCacheRef> cache_ref_;
   fml::CFRef<CVOpenGLESTextureRef> texture_ref_;
+  fml::CFRef<CVPixelBufferRef> buffer_ref_;
   FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalTextureGL);
 };
 
diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.mm b/shell/platform/darwin/ios/ios_external_texture_gl.mm
index ff0be31..e7e15d5 100644
--- a/shell/platform/darwin/ios/ios_external_texture_gl.mm
+++ b/shell/platform/darwin/ios/ios_external_texture_gl.mm
@@ -22,10 +22,7 @@
 
 IOSExternalTextureGL::~IOSExternalTextureGL() = default;
 
-void IOSExternalTextureGL::Paint(SkCanvas& canvas,
-                                 const SkRect& bounds,
-                                 bool freeze,
-                                 GrContext* context) {
+void IOSExternalTextureGL::EnsureTextureCacheExists() {
   if (!cache_ref_) {
     CVOpenGLESTextureCacheRef cache;
     CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL,
@@ -37,22 +34,36 @@
       return;
     }
   }
-  fml::CFRef<CVPixelBufferRef> bufferRef;
+}
+
+void IOSExternalTextureGL::CreateTextureFromPixelBuffer() {
+  if (buffer_ref_ == nullptr) {
+    return;
+  }
+  CVOpenGLESTextureRef texture;
+  CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
+      kCFAllocatorDefault, cache_ref_, buffer_ref_, nullptr, GL_TEXTURE_2D, GL_RGBA,
+      static_cast<int>(CVPixelBufferGetWidth(buffer_ref_)),
+      static_cast<int>(CVPixelBufferGetHeight(buffer_ref_)), GL_BGRA, GL_UNSIGNED_BYTE, 0,
+      &texture);
+  if (err != noErr) {
+    FML_LOG(WARNING) << "Could not create texture from pixel buffer: " << err;
+  } else {
+    texture_ref_.Reset(texture);
+  }
+}
+
+void IOSExternalTextureGL::Paint(SkCanvas& canvas,
+                                 const SkRect& bounds,
+                                 bool freeze,
+                                 GrContext* context) {
+  EnsureTextureCacheExists();
   if (!freeze) {
-    bufferRef.Reset([external_texture_ copyPixelBuffer]);
-    if (bufferRef != nullptr) {
-      CVOpenGLESTextureRef texture;
-      CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
-          kCFAllocatorDefault, cache_ref_, bufferRef, nullptr, GL_TEXTURE_2D, GL_RGBA,
-          static_cast<int>(CVPixelBufferGetWidth(bufferRef)),
-          static_cast<int>(CVPixelBufferGetHeight(bufferRef)), GL_BGRA, GL_UNSIGNED_BYTE, 0,
-          &texture);
-      texture_ref_.Reset(texture);
-      if (err != noErr) {
-        FML_LOG(WARNING) << "Could not create texture from pixel buffer: " << err;
-        return;
-      }
+    auto pixelBuffer = [external_texture_ copyPixelBuffer];
+    if (pixelBuffer) {
+      buffer_ref_.Reset(pixelBuffer);
     }
+    CreateTextureFromPixelBuffer();
   }
   if (!texture_ref_) {
     return;
@@ -69,7 +80,13 @@
   }
 }
 
-void IOSExternalTextureGL::OnGrContextCreated() {}
+void IOSExternalTextureGL::OnGrContextCreated() {
+  // Re-create texture from pixel buffer that was saved before
+  // OnGrContextDestroyed gets called.
+  // https://github.com/flutter/flutter/issues/30491
+  EnsureTextureCacheExists();
+  CreateTextureFromPixelBuffer();
+}
 
 void IOSExternalTextureGL::OnGrContextDestroyed() {
   texture_ref_.Reset(nullptr);