Skip to content

Commit 43828e8

Browse files
Workaround for an Android emulator EGL bug that can cause inaccurate GL version strings (flutter#21258)
1 parent 88fd4ce commit 43828e8

File tree

5 files changed

+59
-1
lines changed

5 files changed

+59
-1
lines changed

shell/gpu/gpu_surface_gl_delegate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
5757
// flushed.
5858
virtual SkMatrix GLContextSurfaceTransformation() const;
5959

60-
sk_sp<const GrGLInterface> GetGLInterface() const;
60+
virtual sk_sp<const GrGLInterface> GetGLInterface() const;
6161

6262
// TODO(chinmaygarde): The presence of this method is to work around the fact
6363
// that not all platforms can accept a custom GL proc table. Migrate all

shell/platform/android/android_context_gl.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,12 @@ bool AndroidContextGL::ClearCurrent() {
248248
return true;
249249
}
250250

251+
EGLContext AndroidContextGL::CreateNewContext() const {
252+
bool success;
253+
EGLContext context;
254+
std::tie(success, context) =
255+
CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT);
256+
return success ? context : EGL_NO_CONTEXT;
257+
}
258+
251259
} // namespace flutter

shell/platform/android/android_context_gl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ class AndroidContextGL : public AndroidContext {
110110
///
111111
bool ClearCurrent();
112112

113+
//----------------------------------------------------------------------------
114+
/// @brief Create a new EGLContext using the same EGLConfig.
115+
///
116+
/// @return The EGLContext.
117+
///
118+
EGLContext CreateNewContext() const;
119+
113120
private:
114121
fml::RefPtr<AndroidEnvironmentGL> environment_;
115122
EGLConfig config_;

shell/platform/android/android_surface_gl.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "flutter/shell/platform/android/android_surface_gl.h"
66

7+
#include <GLES/gl.h>
78
#include <utility>
89

910
#include "flutter/fml/logging.h"
@@ -12,6 +13,12 @@
1213

1314
namespace flutter {
1415

16+
namespace {
17+
// GL renderer string prefix used by the Android emulator GLES implementation.
18+
constexpr char kEmulatorRendererPrefix[] =
19+
"Android Emulator OpenGL ES Translator";
20+
} // anonymous namespace
21+
1522
AndroidSurfaceGL::AndroidSurfaceGL(
1623
std::shared_ptr<AndroidContext> android_context,
1724
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
@@ -133,4 +140,37 @@ ExternalViewEmbedder* AndroidSurfaceGL::GetExternalViewEmbedder() {
133140
return external_view_embedder_.get();
134141
}
135142

143+
// |GPUSurfaceGLDelegate|
144+
sk_sp<const GrGLInterface> AndroidSurfaceGL::GetGLInterface() const {
145+
// This is a workaround for a bug in the Android emulator EGL/GLES
146+
// implementation. Some versions of the emulator will not update the
147+
// GL version string when the process switches to a new EGL context
148+
// unless the EGL context is being made current for the first time.
149+
// The inaccurate version string will be rejected by Skia when it
150+
// tries to build the GrGLInterface. Flutter can work around this
151+
// by creating a new context, making it current to force an update
152+
// of the version, and then reverting to the previous context.
153+
const char* gl_renderer =
154+
reinterpret_cast<const char*>(glGetString(GL_RENDERER));
155+
if (gl_renderer && strncmp(gl_renderer, kEmulatorRendererPrefix,
156+
strlen(kEmulatorRendererPrefix)) == 0) {
157+
EGLContext new_context = android_context_->CreateNewContext();
158+
if (new_context != EGL_NO_CONTEXT) {
159+
EGLContext old_context = eglGetCurrentContext();
160+
EGLDisplay display = eglGetCurrentDisplay();
161+
EGLSurface draw_surface = eglGetCurrentSurface(EGL_DRAW);
162+
EGLSurface read_surface = eglGetCurrentSurface(EGL_READ);
163+
EGLBoolean result =
164+
eglMakeCurrent(display, draw_surface, read_surface, new_context);
165+
FML_DCHECK(result == EGL_TRUE);
166+
result = eglMakeCurrent(display, draw_surface, read_surface, old_context);
167+
FML_DCHECK(result == EGL_TRUE);
168+
result = eglDestroyContext(display, new_context);
169+
FML_DCHECK(result == EGL_TRUE);
170+
}
171+
}
172+
173+
return GPUSurfaceGLDelegate::GetGLInterface();
174+
}
175+
136176
} // namespace flutter

shell/platform/android/android_surface_gl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
6565
// |GPUSurfaceGLDelegate|
6666
ExternalViewEmbedder* GetExternalViewEmbedder() override;
6767

68+
// |GPUSurfaceGLDelegate|
69+
sk_sp<const GrGLInterface> GetGLInterface() const override;
70+
6871
private:
6972
const std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
7073
const std::shared_ptr<AndroidContextGL> android_context_;

0 commit comments

Comments
 (0)