Flutter Engine
The Flutter Engine
android_context_gl_skia.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/android/android_context_gl_skia.h"
6
7#include <utility>
8
9#include "flutter/fml/trace_event.h"
10#include "flutter/shell/platform/android/android_egl_surface.h"
11
12namespace flutter {
13
14template <class T>
15using EGLResult = std::pair<bool, T>;
16
17static EGLResult<EGLContext> CreateContext(EGLDisplay display,
18 EGLConfig config,
19 EGLContext share = EGL_NO_CONTEXT) {
20 EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
21
22 EGLContext context = eglCreateContext(display, config, share, attributes);
23
24 return {context != EGL_NO_CONTEXT, context};
25}
26
27static EGLResult<EGLConfig> ChooseEGLConfiguration(EGLDisplay display) {
28 EGLint attributes[] = {
29 // clang-format off
30 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
31 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
32 EGL_RED_SIZE, 8,
33 EGL_GREEN_SIZE, 8,
34 EGL_BLUE_SIZE, 8,
35 EGL_ALPHA_SIZE, 8,
36 EGL_DEPTH_SIZE, 0,
37 EGL_STENCIL_SIZE, 0,
38 EGL_NONE, // termination sentinel
39 // clang-format on
40 };
41
42 EGLint config_count = 0;
43 EGLConfig egl_config = nullptr;
44
45 if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) !=
46 EGL_TRUE) {
47 return {false, nullptr};
48 }
49
50 bool success = config_count > 0 && egl_config != nullptr;
51
52 return {success, success ? egl_config : nullptr};
53}
54
55static bool TeardownContext(EGLDisplay display, EGLContext context) {
56 if (context != EGL_NO_CONTEXT) {
57 return eglDestroyContext(display, context) == EGL_TRUE;
58 }
59
60 return true;
61}
62
65 const TaskRunners& task_runners)
67 environment_(std::move(environment)),
68 task_runners_(task_runners) {
69 if (!environment_->IsValid()) {
70 FML_LOG(ERROR) << "Could not create an Android GL environment.";
71 return;
72 }
73
74 bool success = false;
75
76 // Choose a valid configuration.
77 std::tie(success, config_) = ChooseEGLConfiguration(environment_->Display());
78 if (!success) {
79 FML_LOG(ERROR) << "Could not choose an EGL configuration.";
81 return;
82 }
83
84 // Create a context for the configuration.
85 std::tie(success, context_) =
86 CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT);
87 if (!success) {
88 FML_LOG(ERROR) << "Could not create an EGL context";
90 return;
91 }
92
93 std::tie(success, resource_context_) =
94 CreateContext(environment_->Display(), config_, context_);
95 if (!success) {
96 FML_LOG(ERROR) << "Could not create an EGL resource context";
98 return;
99 }
100
101 // All done!
102 valid_ = true;
103}
104
108 SetMainSkiaContext(nullptr);
110 // This context needs to be deallocated from the raster thread in order to
111 // keep a coherent usage of egl from a single thread.
113 if (main_context) {
114 std::unique_ptr<AndroidEGLSurface> pbuffer_surface =
115 CreatePbufferSurface();
116 auto status = pbuffer_surface->MakeCurrent();
117 if (status != AndroidEGLSurfaceMakeCurrentStatus::kFailure) {
118 main_context->releaseResourcesAndAbandonContext();
119 main_context.reset();
120 ClearCurrent();
121 }
122 }
123 latch.Signal();
124 });
125 latch.Wait();
126
127 if (!TeardownContext(environment_->Display(), context_)) {
129 << "Could not tear down the EGL context. Possible resource leak.";
131 }
132
133 if (!TeardownContext(environment_->Display(), resource_context_)) {
134 FML_LOG(ERROR) << "Could not tear down the EGL resource context. Possible "
135 "resource leak.";
137 }
138}
139
140std::unique_ptr<AndroidEGLSurface> AndroidContextGLSkia::CreateOnscreenSurface(
142 if (window->IsFakeWindow()) {
143 return CreatePbufferSurface();
144 } else {
145 EGLDisplay display = environment_->Display();
146
147 const EGLint attribs[] = {EGL_NONE};
148
149 EGLSurface surface = eglCreateWindowSurface(
150 display, config_,
151 reinterpret_cast<EGLNativeWindowType>(window->handle()), attribs);
152 return std::make_unique<AndroidEGLSurface>(surface, display, context_);
153 }
154}
155
156std::unique_ptr<AndroidEGLSurface>
157AndroidContextGLSkia::CreateOffscreenSurface() const {
158 // We only ever create pbuffer surfaces for background resource loading
159 // contexts. We never bind the pbuffer to anything.
160 EGLDisplay display = environment_->Display();
161
162 const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
163
164 EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
165 return std::make_unique<AndroidEGLSurface>(surface, display,
166 resource_context_);
167}
168
169std::unique_ptr<AndroidEGLSurface> AndroidContextGLSkia::CreatePbufferSurface()
170 const {
171 EGLDisplay display = environment_->Display();
172
173 const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
174
175 EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
176 return std::make_unique<AndroidEGLSurface>(surface, display, context_);
177}
178
179fml::RefPtr<AndroidEnvironmentGL> AndroidContextGLSkia::Environment() const {
180 return environment_;
181}
182
183bool AndroidContextGLSkia::IsValid() const {
184 return valid_;
185}
186
187bool AndroidContextGLSkia::ClearCurrent() const {
188 if (eglGetCurrentContext() != context_) {
189 return true;
190 }
191 if (eglMakeCurrent(environment_->Display(), EGL_NO_SURFACE, EGL_NO_SURFACE,
192 EGL_NO_CONTEXT) != EGL_TRUE) {
193 FML_LOG(ERROR) << "Could not clear the current context";
195 return false;
196 }
197 return true;
198}
199
200EGLContext AndroidContextGLSkia::GetEGLContext() const {
201 return context_;
202}
203
204EGLDisplay AndroidContextGLSkia::GetEGLDisplay() const {
205 return environment_->Display();
206}
207
208EGLContext AndroidContextGLSkia::CreateNewContext() const {
209 bool success;
210 EGLContext context;
211 std::tie(success, context) =
212 CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT);
213 return success ? context : EGL_NO_CONTEXT;
214}
215
216} // namespace flutter
AndroidContextGLSkia(fml::RefPtr< AndroidEnvironmentGL > environment, const TaskRunners &taskRunners)
Holds state that is shared across Android surfaces.
void SetMainSkiaContext(const sk_sp< GrDirectContext > &main_context)
Setter for the Skia context to be used by subsequent AndroidSurfaces.
sk_sp< GrDirectContext > GetMainSkiaContext() const
Accessor for the Skia context associated with AndroidSurfaces and the raster thread.
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
Definition: task_runner.cc:55
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
TaskRunners task_runners_
GLFWwindow * window
Definition: main.cc:45
VkSurfaceKHR surface
Definition: main.cc:49
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_DCHECK(condition)
Definition: logging.h:103
static dart::SimpleHashMap * environment
Definition: gen_snapshot.cc:59
static bool TeardownContext(EGLDisplay display, EGLContext context)
void LogLastEGLError()
AndroidRenderingAPI
Definition: settings.h:26
std::pair< bool, T > EGLResult
static EGLResult< EGLConfig > ChooseEGLConfiguration(EGLDisplay display)
static EGLResult< EGLContext > CreateContext(EGLDisplay display, EGLConfig config, EGLContext share=EGL_NO_CONTEXT)
Definition: ref_ptr.h:256
#define ERROR(message)
Definition: elf_loader.cc:260