Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
28 uint8_t msaa_samples) {
29 EGLint sample_buffers = msaa_samples > 1 ? 1 : 0;
30 EGLint attributes[] = {
31 // clang-format off
32 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
33 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
34 EGL_RED_SIZE, 8,
35 EGL_GREEN_SIZE, 8,
36 EGL_BLUE_SIZE, 8,
37 EGL_ALPHA_SIZE, 8,
38 EGL_DEPTH_SIZE, 0,
39 EGL_STENCIL_SIZE, 0,
40 EGL_SAMPLES, static_cast<EGLint>(msaa_samples),
41 EGL_SAMPLE_BUFFERS, sample_buffers,
42 EGL_NONE, // termination sentinel
43 // clang-format on
44 };
45
46 EGLint config_count = 0;
47 EGLConfig egl_config = nullptr;
48
49 if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) !=
50 EGL_TRUE) {
51 return {false, nullptr};
52 }
53
54 bool success = config_count > 0 && egl_config != nullptr;
55
56 return {success, success ? egl_config : nullptr};
57}
58
59static bool TeardownContext(EGLDisplay display, EGLContext context) {
60 if (context != EGL_NO_CONTEXT) {
61 return eglDestroyContext(display, context) == EGL_TRUE;
62 }
63
64 return true;
65}
66
69 const TaskRunners& task_runners,
70 uint8_t msaa_samples)
72 environment_(std::move(environment)),
73 task_runners_(task_runners) {
74 if (!environment_->IsValid()) {
75 FML_LOG(ERROR) << "Could not create an Android GL environment.";
76 return;
77 }
78
79 bool success = false;
80
81 // Choose a valid configuration.
82 std::tie(success, config_) =
83 ChooseEGLConfiguration(environment_->Display(), msaa_samples);
84 if (!success) {
85 FML_LOG(ERROR) << "Could not choose an EGL configuration.";
87 return;
88 }
89
90 // Create a context for the configuration.
91 std::tie(success, context_) =
92 CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT);
93 if (!success) {
94 FML_LOG(ERROR) << "Could not create an EGL context";
96 return;
97 }
98
99 std::tie(success, resource_context_) =
100 CreateContext(environment_->Display(), config_, context_);
101 if (!success) {
102 FML_LOG(ERROR) << "Could not create an EGL resource context";
104 return;
105 }
106
107 // All done!
108 valid_ = true;
109}
110
114 SetMainSkiaContext(nullptr);
116 // This context needs to be deallocated from the raster thread in order to
117 // keep a coherent usage of egl from a single thread.
119 if (main_context) {
120 std::unique_ptr<AndroidEGLSurface> pbuffer_surface =
121 CreatePbufferSurface();
122 auto status = pbuffer_surface->MakeCurrent();
123 if (status != AndroidEGLSurfaceMakeCurrentStatus::kFailure) {
124 main_context->releaseResourcesAndAbandonContext();
125 main_context.reset();
126 ClearCurrent();
127 }
128 }
129 latch.Signal();
130 });
131 latch.Wait();
132
133 if (!TeardownContext(environment_->Display(), context_)) {
135 << "Could not tear down the EGL context. Possible resource leak.";
137 }
138
139 if (!TeardownContext(environment_->Display(), resource_context_)) {
140 FML_LOG(ERROR) << "Could not tear down the EGL resource context. Possible "
141 "resource leak.";
143 }
144}
145
146std::unique_ptr<AndroidEGLSurface> AndroidContextGLSkia::CreateOnscreenSurface(
148 if (window->IsFakeWindow()) {
149 return CreatePbufferSurface();
150 } else {
151 EGLDisplay display = environment_->Display();
152
153 const EGLint attribs[] = {EGL_NONE};
154
155 EGLSurface surface = eglCreateWindowSurface(
156 display, config_,
157 reinterpret_cast<EGLNativeWindowType>(window->handle()), attribs);
158 return std::make_unique<AndroidEGLSurface>(surface, display, context_);
159 }
160}
161
162std::unique_ptr<AndroidEGLSurface>
163AndroidContextGLSkia::CreateOffscreenSurface() const {
164 // We only ever create pbuffer surfaces for background resource loading
165 // contexts. We never bind the pbuffer to anything.
166 EGLDisplay display = environment_->Display();
167
168 const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
169
170 EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
171 return std::make_unique<AndroidEGLSurface>(surface, display,
172 resource_context_);
173}
174
175std::unique_ptr<AndroidEGLSurface> AndroidContextGLSkia::CreatePbufferSurface()
176 const {
177 EGLDisplay display = environment_->Display();
178
179 const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
180
181 EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
182 return std::make_unique<AndroidEGLSurface>(surface, display, context_);
183}
184
185fml::RefPtr<AndroidEnvironmentGL> AndroidContextGLSkia::Environment() const {
186 return environment_;
187}
188
189bool AndroidContextGLSkia::IsValid() const {
190 return valid_;
191}
192
193bool AndroidContextGLSkia::ClearCurrent() const {
194 if (eglGetCurrentContext() != context_) {
195 return true;
196 }
197 if (eglMakeCurrent(environment_->Display(), EGL_NO_SURFACE, EGL_NO_SURFACE,
198 EGL_NO_CONTEXT) != EGL_TRUE) {
199 FML_LOG(ERROR) << "Could not clear the current context";
201 return false;
202 }
203 return true;
204}
205
206EGLContext AndroidContextGLSkia::GetEGLContext() const {
207 return context_;
208}
209
210EGLDisplay AndroidContextGLSkia::GetEGLDisplay() const {
211 return environment_->Display();
212}
213
214EGLContext AndroidContextGLSkia::CreateNewContext() const {
215 bool success;
216 EGLContext context;
217 std::tie(success, context) =
218 CreateContext(environment_->Display(), config_, EGL_NO_CONTEXT);
219 return success ? context : EGL_NO_CONTEXT;
220}
221
222} // namespace flutter
AndroidContextGLSkia(fml::RefPtr< AndroidEnvironmentGL > environment, const TaskRunners &taskRunners, uint8_t msaa_samples)
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
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual bool RunsTasksOnCurrentThread()
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 bool TeardownContext(EGLDisplay display, EGLContext context)
void LogLastEGLError()
AndroidRenderingAPI
Definition settings.h:26
std::pair< bool, T > EGLResult
static EGLResult< EGLConfig > ChooseEGLConfiguration(EGLDisplay display, uint8_t msaa_samples)
static EGLResult< EGLContext > CreateContext(EGLDisplay display, EGLConfig config, EGLContext share=EGL_NO_CONTEXT)
Definition ref_ptr.h:256
#define ERROR(message)