Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
tester_context_gles_factory.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#define FML_USED_ON_EMBEDDER
6
8
9#include <EGL/egl.h>
10#include <EGL/eglext.h>
11#include <EGL/eglplatform.h>
12#include <cstring>
13#include <memory>
14#include <vector>
15
17#include "flutter/fml/logging.h"
19#include "flutter/fml/mapping.h"
25#include "impeller/entity/gles/entity_shaders_gles.h"
26#include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
27#include "impeller/entity/gles/modern_shaders_gles.h"
30#include "third_party/abseil-cpp/absl/status/statusor.h"
31
32namespace flutter {
33
34namespace {
35
36class TesterGLContext : public SwitchableGLContext {
37 public:
38 TesterGLContext(EGLDisplay display, EGLSurface surface, EGLContext context)
39 : display_(display), surface_(surface), context_(context) {}
40
41 bool SetCurrent() override {
42 return ::eglMakeCurrent(display_, surface_, surface_, context_) == EGL_TRUE;
43 }
44
45 bool RemoveCurrent() override {
46 ::eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
47 return true;
48 }
49
50 private:
51 EGLDisplay display_;
52 EGLSurface surface_;
53 EGLContext context_;
54};
55
56class TesterGLESDelegate : public GPUSurfaceGLDelegate {
57 public:
58 static absl::StatusOr<TesterGLESDelegate> Create() {
59 EGLDisplay display = flutter::testing::CreateSwangleDisplay();
60 if (display == EGL_NO_DISPLAY) {
61 return absl::InternalError("Could not create EGL display.");
62 }
63
64 if (::eglInitialize(display, nullptr, nullptr) != EGL_TRUE) {
65 return absl::InternalError("Could not initialize EGL display.");
66 }
67
68 EGLint num_config = 0;
69 const EGLint attribute_list[] = {EGL_RED_SIZE,
70 8,
71 EGL_GREEN_SIZE,
72 8,
73 EGL_BLUE_SIZE,
74 8,
75 EGL_ALPHA_SIZE,
76 8,
77 EGL_DEPTH_SIZE,
78 24,
79 EGL_STENCIL_SIZE,
80 8,
81 EGL_SURFACE_TYPE,
82 EGL_PBUFFER_BIT,
83 EGL_CONFORMANT,
84 EGL_OPENGL_ES2_BIT,
85 EGL_RENDERABLE_TYPE,
86 EGL_OPENGL_ES2_BIT,
87 EGL_NONE};
88
89 EGLConfig config = nullptr;
90 if (::eglChooseConfig(display, attribute_list, &config, 1, &num_config) !=
91 EGL_TRUE ||
92 num_config != 1) {
93 return absl::InternalError("Could not choose EGL config.");
94 }
95
96 const EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
97 EGL_NONE};
98
99 EGLContext context =
100 ::eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
101 if (context == EGL_NO_CONTEXT) {
102 return absl::InternalError("Could not create EGL context.");
103 }
104
105 // Create a pbuffer surface to make current
106 const EGLint surface_attributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
107 EGLSurface surface =
108 ::eglCreatePbufferSurface(display, config, surface_attributes);
109 if (surface == EGL_NO_SURFACE) {
110 ::eglDestroyContext(display, context);
111 return absl::InternalError("Could not create EGL pbuffer surface.");
112 }
113
114 return TesterGLESDelegate(display, context, surface);
115 }
116
117 TesterGLESDelegate(TesterGLESDelegate&& other)
118 : display_(other.display_),
119 context_(other.context_),
120 surface_(other.surface_) {
121 other.display_ = EGL_NO_DISPLAY;
122 other.context_ = EGL_NO_CONTEXT;
123 other.surface_ = EGL_NO_SURFACE;
124 }
125
126 virtual ~TesterGLESDelegate() {
127 if (display_ != EGL_NO_DISPLAY) {
128 if (surface_ != EGL_NO_SURFACE) {
129 ::eglDestroySurface(display_, surface_);
130 }
131 if (context_ != EGL_NO_CONTEXT) {
132 ::eglDestroyContext(display_, context_);
133 }
134 ::eglTerminate(display_);
135 }
136 }
137
138 bool IsContextCurrent() const { return ::eglGetCurrentContext() == context_; }
139
140 // |GPUSurfaceGLDelegate|
141 std::unique_ptr<GLContextResult> GLContextMakeCurrent() override {
142 if (IsContextCurrent()) {
143 return std::make_unique<GLContextDefaultResult>(true);
144 }
145
146 // Set the current context by instantiating a GLContextSwitch with a
147 // TesterGLContext. This clears the current context on destruction of the
148 // GLContextSwitch.
149 return std::make_unique<GLContextSwitch>(
150 std::make_unique<TesterGLContext>(display_, surface_, context_));
151 }
152
153 // |GPUSurfaceGLDelegate|
154 bool GLContextClearCurrent() override {
155 return ::eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
156 EGL_NO_CONTEXT) == EGL_TRUE;
157 }
158
159 // |GPUSurfaceGLDelegate|
160 bool GLContextPresent(const GLPresentInfo& present_info) override {
161 return true;
162 }
163
164 // |GPUSurfaceGLDelegate|
165 GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override {
166 return GLFBOInfo{0, std::nullopt};
167 }
168
169 // |GPUSurfaceGLDelegate|
170 SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override {
171 return SurfaceFrame::FramebufferInfo{.supports_readback = true};
172 }
173
174 private:
175 TesterGLESDelegate(EGLDisplay display, EGLContext context, EGLSurface surface)
176 : display_(display), context_(context), surface_(surface) {}
177
178 EGLDisplay display_ = EGL_NO_DISPLAY;
179 EGLContext context_ = EGL_NO_CONTEXT;
180 EGLSurface surface_ = EGL_NO_SURFACE;
181
182 FML_DISALLOW_COPY_AND_ASSIGN(TesterGLESDelegate);
183};
184
185class TesterGLESWorker : public impeller::ReactorGLES::Worker {
186 public:
187 explicit TesterGLESWorker(TesterGLESDelegate* delegate)
188 : delegate_(delegate) {}
189
190 bool CanReactorReactOnCurrentThreadNow(
191 const impeller::ReactorGLES& reactor) const override {
192 if (delegate_->IsContextCurrent()) {
193 return true;
194 }
195 std::unique_ptr<GLContextResult> result = delegate_->GLContextMakeCurrent();
196 if (!result->GetResult()) {
197 return false;
198 }
199 // Move the result into a TaskObserver to ensure it is destroyed (and the
200 // current egl context cleared) at the end of the current task.
202 reinterpret_cast<intptr_t>(this),
203 fml::MakeCopyable([this, result = std::move(result)]() {
205 reinterpret_cast<intptr_t>(this));
206 }));
207 return true;
208 }
209
210 private:
211 TesterGLESDelegate* delegate_;
212};
213
214class TesterContextGLES : public TesterContext {
215 public:
216 TesterContextGLES() = default;
217
218 ~TesterContextGLES() override {
219 if (context_) {
220 std::shared_ptr<impeller::Context> raw_context = context_;
221 raw_context->Shutdown();
222 }
223 }
224
225 bool Initialize() {
226 auto delegate_status = TesterGLESDelegate::Create();
227 if (!delegate_status.ok()) {
228 FML_LOG(ERROR) << delegate_status.status().message();
229 return false;
230 }
231 delegate_ = std::make_unique<TesterGLESDelegate>(
232 std::move(delegate_status.value()));
233
234 auto switch_result = delegate_->GLContextMakeCurrent();
235 if (!switch_result->GetResult()) {
236 FML_LOG(ERROR) << "Could not make GLES context current.";
237 return false;
238 }
239
240 auto resolver = [](const char* name) -> void* {
241 return reinterpret_cast<void*>(eglGetProcAddress(name));
242 };
243
244 auto gl = std::make_unique<impeller::ProcTableGLES>(resolver);
245 if (!gl->IsValid()) {
246 FML_LOG(ERROR) << "Could not create valid proc table.";
247 return false;
248 }
249
250 std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
251 std::make_shared<fml::NonOwnedMapping>(
252 impeller_entity_shaders_gles_data,
253 impeller_entity_shaders_gles_length),
254 std::make_shared<fml::NonOwnedMapping>(
255 impeller_modern_shaders_gles_data,
256 impeller_modern_shaders_gles_length),
257 std::make_shared<fml::NonOwnedMapping>(
258 impeller_framebuffer_blend_shaders_gles_data,
259 impeller_framebuffer_blend_shaders_gles_length),
260 };
261 context_ = impeller::ContextGLES::Create(impeller::Flags{}, std::move(gl),
262 shader_mappings, false);
263
264 if (!context_ ||
265 !static_cast<std::shared_ptr<impeller::Context>>(context_)->IsValid()) {
266 FML_LOG(ERROR) << "Could not create OpenGLES context.";
267 return false;
268 }
269
270 worker_ = std::make_shared<TesterGLESWorker>(delegate_.get());
271 context_->AddReactorWorker(worker_);
272
273 return true;
274 }
275
276 // |TesterContext|
277 std::shared_ptr<impeller::Context> GetImpellerContext() const override {
278 return context_;
279 }
280
281 // |TesterContext|
282 std::unique_ptr<Surface> CreateRenderingSurface() override {
283 auto surface = std::make_unique<GPUSurfaceGLImpeller>(
284 delegate_.get(), context_, /*render_to_surface=*/true);
285 if (!surface->IsValid()) {
286 return nullptr;
287 }
288 return surface;
289 }
290
291 private:
292 std::unique_ptr<TesterGLESDelegate> delegate_;
293 std::shared_ptr<TesterGLESWorker> worker_;
294 std::shared_ptr<impeller::ContextGLES> context_;
295};
296
297} // namespace
298
299std::unique_ptr<TesterContext> TesterContextGLESFactory::Create() {
301 auto context = std::make_unique<TesterContextGLES>();
302 if (!context->Initialize()) {
303 FML_LOG(ERROR) << "Unable to create TesterContextGLESFactory";
304 return nullptr;
305 }
306 return context;
307}
308
309} // namespace flutter
static std::unique_ptr< TesterContext > Create()
void RemoveTaskObserver(intptr_t key)
void AddTaskObserver(intptr_t key, const fml::closure &callback)
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static std::shared_ptr< ContextGLES > Create(const Flags &flags, std::unique_ptr< ProcTableGLES > gl, const std::vector< std::shared_ptr< fml::Mapping > > &shader_libraries, bool enable_gpu_tracing)
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
MockDelegate delegate_
VkSurfaceKHR surface
Definition main.cc:65
#define FML_LOG(severity)
Definition logging.h:101
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
EGLDisplay display_
EGLSurface surface_
EGLDisplay CreateSwangleDisplay()
Creates an EGLDisplay using ANGLE with the Vulkan backend and SwiftShader as the device type.
void SetupSwiftshaderOnce(bool use_swiftshader)
Find and setup the installable client driver for a locally built SwiftShader at known paths....
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
internal::CopyableLambda< T > MakeCopyable(T lambda)