diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index 8f2c3df04006f..e35be2c6232bb 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -57,7 +57,7 @@ class GPUSurfaceGLDelegate : public GPUSurfaceDelegate { // flushed. virtual SkMatrix GLContextSurfaceTransformation() const; - sk_sp GetGLInterface() const; + virtual sk_sp GetGLInterface() const; // TODO(chinmaygarde): The presence of this method is to work around the fact // that not all platforms can accept a custom GL proc table. Migrate all diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index 91e2628e1fc1b..1a17a9a8f0444 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -248,4 +248,12 @@ bool AndroidContextGL::ClearCurrent() { return true; } +EGLContext AndroidContextGL::CreateNewContext() const { + bool success; + EGLContext context; + std::tie(success, context) = + CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT); + return success ? context : EGL_NO_CONTEXT; +} + } // namespace flutter diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index dc9fc3212303e..a0e4f99e81489 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -110,6 +110,13 @@ class AndroidContextGL : public AndroidContext { /// bool ClearCurrent(); + //---------------------------------------------------------------------------- + /// @brief Create a new EGLContext using the same EGLConfig. + /// + /// @return The EGLContext. + /// + EGLContext CreateNewContext() const; + private: fml::RefPtr environment_; EGLConfig config_; diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index 642fd4f0c65cb..c9a9a130c59c4 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -4,6 +4,7 @@ #include "flutter/shell/platform/android/android_surface_gl.h" +#include #include #include "flutter/fml/logging.h" @@ -12,6 +13,12 @@ namespace flutter { +namespace { +// GL renderer string prefix used by the Android emulator GLES implementation. +constexpr char kEmulatorRendererPrefix[] = + "Android Emulator OpenGL ES Translator"; +} // anonymous namespace + AndroidSurfaceGL::AndroidSurfaceGL( std::shared_ptr android_context, std::shared_ptr jni_facade, @@ -133,4 +140,37 @@ ExternalViewEmbedder* AndroidSurfaceGL::GetExternalViewEmbedder() { return external_view_embedder_.get(); } +// |GPUSurfaceGLDelegate| +sk_sp AndroidSurfaceGL::GetGLInterface() const { + // This is a workaround for a bug in the Android emulator EGL/GLES + // implementation. Some versions of the emulator will not update the + // GL version string when the process switches to a new EGL context + // unless the EGL context is being made current for the first time. + // The inaccurate version string will be rejected by Skia when it + // tries to build the GrGLInterface. Flutter can work around this + // by creating a new context, making it current to force an update + // of the version, and then reverting to the previous context. + const char* gl_renderer = + reinterpret_cast(glGetString(GL_RENDERER)); + if (gl_renderer && strncmp(gl_renderer, kEmulatorRendererPrefix, + strlen(kEmulatorRendererPrefix)) == 0) { + EGLContext new_context = android_context_->CreateNewContext(); + if (new_context != EGL_NO_CONTEXT) { + EGLContext old_context = eglGetCurrentContext(); + EGLDisplay display = eglGetCurrentDisplay(); + EGLSurface draw_surface = eglGetCurrentSurface(EGL_DRAW); + EGLSurface read_surface = eglGetCurrentSurface(EGL_READ); + EGLBoolean result = + eglMakeCurrent(display, draw_surface, read_surface, new_context); + FML_DCHECK(result == EGL_TRUE); + result = eglMakeCurrent(display, draw_surface, read_surface, old_context); + FML_DCHECK(result == EGL_TRUE); + result = eglDestroyContext(display, new_context); + FML_DCHECK(result == EGL_TRUE); + } + } + + return GPUSurfaceGLDelegate::GetGLInterface(); +} + } // namespace flutter diff --git a/shell/platform/android/android_surface_gl.h b/shell/platform/android/android_surface_gl.h index 8af382a521e27..771fbfea41a80 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -65,6 +65,9 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, // |GPUSurfaceGLDelegate| ExternalViewEmbedder* GetExternalViewEmbedder() override; + // |GPUSurfaceGLDelegate| + sk_sp GetGLInterface() const override; + private: const std::unique_ptr external_view_embedder_; const std::shared_ptr android_context_;