| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "flutter/shell/platform/android/android_surface_gl.h" | |
| #include <GLES/gl.h> | |
| #include <utility> | |
| #include "flutter/fml/logging.h" | |
| #include "flutter/fml/memory/ref_ptr.h" | |
| #include "flutter/shell/platform/android/android_shell_holder.h" | |
| 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<AndroidContext> android_context, | |
| std::shared_ptr<PlatformViewAndroidJNI> jni_facade, | |
| const AndroidSurface::Factory& surface_factory) | |
| : external_view_embedder_( | |
| std::make_unique<AndroidExternalViewEmbedder>(android_context, | |
| jni_facade, | |
| surface_factory)), | |
| android_context_( | |
| std::static_pointer_cast<AndroidContextGL>(android_context)), | |
| native_window_(nullptr), | |
| onscreen_surface_(nullptr), | |
| offscreen_surface_(nullptr) { | |
| // Acquire the offscreen surface. | |
| offscreen_surface_ = android_context_->CreateOffscreenSurface(); | |
| if (!offscreen_surface_->IsValid()) { | |
| offscreen_surface_ = nullptr; | |
| } | |
| } | |
| AndroidSurfaceGL::~AndroidSurfaceGL() = default; | |
| void AndroidSurfaceGL::TeardownOnScreenContext() { | |
| // When the onscreen surface is destroyed, the context and the surface | |
| // instance should be deleted. Issue: | |
| // https://github.com/flutter/flutter/issues/64414 | |
| android_context_->ClearCurrent(); | |
| onscreen_surface_ = nullptr; | |
| } | |
| bool AndroidSurfaceGL::IsValid() const { | |
| return offscreen_surface_ && android_context_->IsValid(); | |
| } | |
| std::unique_ptr<Surface> AndroidSurfaceGL::CreateGPUSurface( | |
| GrDirectContext* gr_context) { | |
| if (gr_context) { | |
| return std::make_unique<GPUSurfaceGL>(sk_ref_sp(gr_context), this, true); | |
| } | |
| return std::make_unique<GPUSurfaceGL>(this, true); | |
| } | |
| bool AndroidSurfaceGL::OnScreenSurfaceResize(const SkISize& size) { | |
| FML_DCHECK(IsValid()); | |
| FML_DCHECK(onscreen_surface_); | |
| FML_DCHECK(native_window_); | |
| if (size == onscreen_surface_->GetSize()) { | |
| return true; | |
| } | |
| android_context_->ClearCurrent(); | |
| // Ensure the destructor is called since it destroys the `EGLSurface` before | |
| // creating a new onscreen surface. | |
| onscreen_surface_ = nullptr; | |
| onscreen_surface_ = android_context_->CreateOnscreenSurface(native_window_); | |
| if (!onscreen_surface_->IsValid()) { | |
| FML_LOG(ERROR) << "Unable to create EGL window surface on resize."; | |
| return false; | |
| } | |
| onscreen_surface_->MakeCurrent(); | |
| return true; | |
| } | |
| bool AndroidSurfaceGL::ResourceContextMakeCurrent() { | |
| FML_DCHECK(IsValid()); | |
| return offscreen_surface_->MakeCurrent(); | |
| } | |
| bool AndroidSurfaceGL::ResourceContextClearCurrent() { | |
| FML_DCHECK(IsValid()); | |
| return android_context_->ClearCurrent(); | |
| } | |
| bool AndroidSurfaceGL::SetNativeWindow( | |
| fml::RefPtr<AndroidNativeWindow> window) { | |
| FML_DCHECK(IsValid()); | |
| FML_DCHECK(window); | |
| native_window_ = window; | |
| // Ensure the destructor is called since it destroys the `EGLSurface` before | |
| // creating a new onscreen surface. | |
| onscreen_surface_ = nullptr; | |
| // Create the onscreen surface. | |
| onscreen_surface_ = android_context_->CreateOnscreenSurface(window); | |
| if (!onscreen_surface_->IsValid()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| std::unique_ptr<GLContextResult> AndroidSurfaceGL::GLContextMakeCurrent() { | |
| FML_DCHECK(IsValid()); | |
| FML_DCHECK(onscreen_surface_); | |
| auto default_context_result = std::make_unique<GLContextDefaultResult>( | |
| onscreen_surface_->MakeCurrent()); | |
| return std::move(default_context_result); | |
| } | |
| bool AndroidSurfaceGL::GLContextClearCurrent() { | |
| FML_DCHECK(IsValid()); | |
| return android_context_->ClearCurrent(); | |
| } | |
| bool AndroidSurfaceGL::GLContextPresent(uint32_t fbo_id) { | |
| FML_DCHECK(IsValid()); | |
| FML_DCHECK(onscreen_surface_); | |
| return onscreen_surface_->SwapBuffers(); | |
| } | |
| intptr_t AndroidSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { | |
| FML_DCHECK(IsValid()); | |
| // The default window bound framebuffer on Android. | |
| return 0; | |
| } | |
| // |GPUSurfaceGLDelegate| | |
| ExternalViewEmbedder* AndroidSurfaceGL::GetExternalViewEmbedder() { | |
| return external_view_embedder_.get(); | |
| } | |
| // |GPUSurfaceGLDelegate| | |
| sk_sp<const GrGLInterface> 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<const char*>(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 |