Flutter Engine
The Flutter Engine
test_gl_surface.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/testing/test_gl_surface.h"
6
7#include <EGL/egl.h>
8#include <EGL/eglext.h>
9#include <EGL/eglplatform.h>
10#include <GLES2/gl2.h>
11
12#include <sstream>
13#include <string>
14
15#include "flutter/fml/build_config.h"
16#include "flutter/fml/logging.h"
26
27namespace flutter {
28namespace testing {
29
30static std::string GetEGLError() {
31 std::stringstream stream;
32
33 auto error = ::eglGetError();
34
35 stream << "EGL Result: '";
36
37 switch (error) {
38 case EGL_SUCCESS:
39 stream << "EGL_SUCCESS";
40 break;
41 case EGL_NOT_INITIALIZED:
42 stream << "EGL_NOT_INITIALIZED";
43 break;
44 case EGL_BAD_ACCESS:
45 stream << "EGL_BAD_ACCESS";
46 break;
47 case EGL_BAD_ALLOC:
48 stream << "EGL_BAD_ALLOC";
49 break;
50 case EGL_BAD_ATTRIBUTE:
51 stream << "EGL_BAD_ATTRIBUTE";
52 break;
53 case EGL_BAD_CONTEXT:
54 stream << "EGL_BAD_CONTEXT";
55 break;
56 case EGL_BAD_CONFIG:
57 stream << "EGL_BAD_CONFIG";
58 break;
59 case EGL_BAD_CURRENT_SURFACE:
60 stream << "EGL_BAD_CURRENT_SURFACE";
61 break;
62 case EGL_BAD_DISPLAY:
63 stream << "EGL_BAD_DISPLAY";
64 break;
65 case EGL_BAD_SURFACE:
66 stream << "EGL_BAD_SURFACE";
67 break;
68 case EGL_BAD_MATCH:
69 stream << "EGL_BAD_MATCH";
70 break;
71 case EGL_BAD_PARAMETER:
72 stream << "EGL_BAD_PARAMETER";
73 break;
74 case EGL_BAD_NATIVE_PIXMAP:
75 stream << "EGL_BAD_NATIVE_PIXMAP";
76 break;
77 case EGL_BAD_NATIVE_WINDOW:
78 stream << "EGL_BAD_NATIVE_WINDOW";
79 break;
80 case EGL_CONTEXT_LOST:
81 stream << "EGL_CONTEXT_LOST";
82 break;
83 default:
84 stream << "Unknown";
85 }
86
87 stream << "' (0x" << std::hex << error << std::dec << ").";
88 return stream.str();
89}
90
91static bool HasExtension(const char* extensions, const char* name) {
92 const char* r = strstr(extensions, name);
93 auto len = strlen(name);
94 // check that the extension name is terminated by space or null terminator
95 return r != nullptr && (r[len] == ' ' || r[len] == 0);
96}
97
99 const char* extensions = ::eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
100 FML_CHECK(HasExtension(extensions, "EGL_EXT_platform_base")) << extensions;
101 FML_CHECK(HasExtension(extensions, "EGL_ANGLE_platform_angle_vulkan"))
102 << extensions;
104 "EGL_ANGLE_platform_angle_device_type_swiftshader"))
105 << extensions;
106}
107
108static EGLDisplay CreateSwangleDisplay() {
110
111 PFNEGLGETPLATFORMDISPLAYEXTPROC egl_get_platform_display_EXT =
112 reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
113 eglGetProcAddress("eglGetPlatformDisplayEXT"));
114 FML_CHECK(egl_get_platform_display_EXT)
115 << "eglGetPlatformDisplayEXT not available.";
116
117 const EGLint display_config[] = {
119 EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
120 EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
121 EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE,
122 EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE,
123 EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE,
124 EGL_NONE,
125 };
126
127 return egl_get_platform_display_EXT(
129 reinterpret_cast<EGLNativeDisplayType*>(EGL_DEFAULT_DISPLAY),
130 display_config);
131}
132
134 : surface_size_(surface_size) {
135 display_ = CreateSwangleDisplay();
136 FML_CHECK(display_ != EGL_NO_DISPLAY);
137
138 auto result = ::eglInitialize(display_, nullptr, nullptr);
139 FML_CHECK(result == EGL_TRUE) << GetEGLError();
140
141 EGLConfig config = {0};
142
143 EGLint num_config = 0;
144 const EGLint attribute_list[] = {EGL_RED_SIZE,
145 8,
146 EGL_GREEN_SIZE,
147 8,
148 EGL_BLUE_SIZE,
149 8,
150 EGL_ALPHA_SIZE,
151 8,
152 EGL_SURFACE_TYPE,
153 EGL_PBUFFER_BIT,
154 EGL_CONFORMANT,
155 EGL_OPENGL_ES2_BIT,
156 EGL_RENDERABLE_TYPE,
157 EGL_OPENGL_ES2_BIT,
158 EGL_NONE};
159
160 result = ::eglChooseConfig(display_, attribute_list, &config, 1, &num_config);
161 FML_CHECK(result == EGL_TRUE) << GetEGLError();
162 FML_CHECK(num_config == 1) << GetEGLError();
163
164 {
165 const EGLint onscreen_surface_attributes[] = {
166 EGL_WIDTH, surface_size_.width(), //
167 EGL_HEIGHT, surface_size_.height(), //
168 EGL_NONE,
169 };
170
171 onscreen_surface_ = ::eglCreatePbufferSurface(
172 display_, // display connection
173 config, // config
174 onscreen_surface_attributes // surface attributes
175 );
176 FML_CHECK(onscreen_surface_ != EGL_NO_SURFACE) << GetEGLError();
177 }
178
179 {
180 const EGLint offscreen_surface_attributes[] = {
181 EGL_WIDTH, 1, //
182 EGL_HEIGHT, 1, //
183 EGL_NONE,
184 };
185 offscreen_surface_ = ::eglCreatePbufferSurface(
186 display_, // display connection
187 config, // config
188 offscreen_surface_attributes // surface attributes
189 );
190 FML_CHECK(offscreen_surface_ != EGL_NO_SURFACE) << GetEGLError();
191 }
192
193 {
194 const EGLint context_attributes[] = {
195 EGL_CONTEXT_CLIENT_VERSION, //
196 2, //
197 EGL_NONE //
198 };
199
200 onscreen_context_ =
201 ::eglCreateContext(display_, // display connection
202 config, // config
203 EGL_NO_CONTEXT, // sharegroup
204 context_attributes // context attributes
205 );
206 FML_CHECK(onscreen_context_ != EGL_NO_CONTEXT) << GetEGLError();
207
208 offscreen_context_ =
209 ::eglCreateContext(display_, // display connection
210 config, // config
211 onscreen_context_, // sharegroup
212 context_attributes // context attributes
213 );
214 FML_CHECK(offscreen_context_ != EGL_NO_CONTEXT) << GetEGLError();
215 }
216}
217
219 context_ = nullptr;
220
221 auto result = ::eglDestroyContext(display_, onscreen_context_);
222 FML_CHECK(result == EGL_TRUE) << GetEGLError();
223
224 result = ::eglDestroyContext(display_, offscreen_context_);
225 FML_CHECK(result == EGL_TRUE) << GetEGLError();
226
227 result = ::eglDestroySurface(display_, onscreen_surface_);
228 FML_CHECK(result == EGL_TRUE) << GetEGLError();
229
230 result = ::eglDestroySurface(display_, offscreen_surface_);
231 FML_CHECK(result == EGL_TRUE) << GetEGLError();
232
233 result = ::eglTerminate(display_);
234 FML_CHECK(result == EGL_TRUE);
235}
236
238 return surface_size_;
239}
240
242 auto result = ::eglMakeCurrent(display_, onscreen_surface_, onscreen_surface_,
243 onscreen_context_);
244
245 if (result == EGL_FALSE) {
246 FML_LOG(ERROR) << "Could not make the context current. " << GetEGLError();
247 }
248
249 return result == EGL_TRUE;
250}
251
253 auto result = ::eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
254 EGL_NO_CONTEXT);
255
256 if (result == EGL_FALSE) {
257 FML_LOG(ERROR) << "Could not clear the current context. " << GetEGLError();
258 }
259
260 return result == EGL_TRUE;
261}
262
264 auto result = ::eglSwapBuffers(display_, onscreen_surface_);
265
266 if (result == EGL_FALSE) {
267 FML_LOG(ERROR) << "Could not swap buffers. " << GetEGLError();
268 }
269
270 return result == EGL_TRUE;
271}
272
273uint32_t TestGLSurface::GetFramebuffer(uint32_t width, uint32_t height) const {
274 return GetWindowFBOId();
275}
276
278 auto result = ::eglMakeCurrent(display_, offscreen_surface_,
279 offscreen_surface_, offscreen_context_);
280
281 if (result == EGL_FALSE) {
282 FML_LOG(ERROR) << "Could not make the resource context current. "
283 << GetEGLError();
284 }
285
286 return result == EGL_TRUE;
287}
288
289void* TestGLSurface::GetProcAddress(const char* name) const {
290 if (name == nullptr) {
291 return nullptr;
292 }
293 auto symbol = ::eglGetProcAddress(name);
294 if (symbol == NULL) {
295 FML_LOG(ERROR) << "Could not fetch symbol for name: " << name;
296 }
297 return reinterpret_cast<void*>(symbol);
298}
299
301 if (context_) {
302 return context_;
303 }
304
305 return CreateGrContext();
306}
307
309 if (!MakeCurrent()) {
310 return nullptr;
311 }
312
313 auto get_string =
314 reinterpret_cast<PFNGLGETSTRINGPROC>(GetProcAddress("glGetString"));
315
316 if (!get_string) {
317 return nullptr;
318 }
319
320 auto c_version = reinterpret_cast<const char*>(get_string(GL_VERSION));
321
322 if (c_version == NULL) {
323 return nullptr;
324 }
325
326 GrGLGetProc get_proc = [](void* context, const char name[]) -> GrGLFuncPtr {
327 return reinterpret_cast<GrGLFuncPtr>(
328 reinterpret_cast<TestGLSurface*>(context)->GetProcAddress(name));
329 };
330
331 std::string version(c_version);
332 auto interface = version.find("OpenGL ES") == std::string::npos
333 ? GrGLMakeAssembledGLInterface(this, get_proc)
334 : GrGLMakeAssembledGLESInterface(this, get_proc);
335
336 if (!interface) {
337 return nullptr;
338 }
339
340 context_ = GrDirectContexts::MakeGL(interface);
341 return context_;
342}
343
345 FML_CHECK(::eglGetCurrentContext() != EGL_NO_CONTEXT);
346
347 GrGLFramebufferInfo framebuffer_info = {};
348 const uint32_t width = surface_size_.width();
349 const uint32_t height = surface_size_.height();
350 framebuffer_info.fFBOID = GetFramebuffer(width, height);
351#if FML_OS_MACOSX
352 framebuffer_info.fFormat = 0x8058; // GL_RGBA8
353#else
354 framebuffer_info.fFormat = 0x93A1; // GL_BGRA8;
355#endif
356
357 auto backend_render_target =
359 height, // height
360 1, // sample count
361 8, // stencil bits
362 framebuffer_info // framebuffer info
363 );
364
365 SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
366
368 GetGrContext().get(), // context
369 backend_render_target, // backend render target
370 kBottomLeft_GrSurfaceOrigin, // surface origin
371 kN32_SkColorType, // color type
372 SkColorSpace::MakeSRGB(), // color space
373 &surface_properties, // surface properties
374 nullptr, // release proc
375 nullptr // release context
376 );
377
378 if (!surface) {
379 FML_LOG(ERROR) << "Could not wrap the surface while attempting to "
380 "snapshot the GL surface.";
381 return nullptr;
382 }
383
384 return surface;
385}
386
389
390 if (!surface) {
391 FML_LOG(ERROR) << "Aborting snapshot because of on-screen surface "
392 "acquisition failure.";
393 return nullptr;
394 }
395
396 auto device_snapshot = surface->makeImageSnapshot();
397
398 if (!device_snapshot) {
399 FML_LOG(ERROR) << "Could not create the device snapshot while attempting "
400 "to snapshot the GL surface.";
401 return nullptr;
402 }
403
404 auto host_snapshot = device_snapshot->makeRasterImage();
405
406 if (!host_snapshot) {
407 FML_LOG(ERROR) << "Could not create the host snapshot while attempting to "
408 "snapshot the GL surface.";
409 return nullptr;
410 }
411
412 return host_snapshot;
413}
414
416 return 0u;
417}
418
419} // namespace testing
420} // namespace flutter
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE
#define EGL_PLATFORM_ANGLE_ANGLE
SK_API sk_sp< const GrGLInterface > GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get)
GrGLFuncPtr(* GrGLGetProc)(void *ctx, const char name[])
SK_API sk_sp< const GrGLInterface > GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get)
void(* GrGLFuncPtr)()
Definition: GrGLInterface.h:17
@ kBottomLeft_GrSurfaceOrigin
Definition: GrTypes.h:149
static const char * get_string(FcPattern *pattern, const char field[], int index=0)
@ kUnknown_SkPixelGeometry
static sk_sp< SkColorSpace > MakeSRGB()
uint32_t GetFramebuffer(uint32_t width, uint32_t height) const
sk_sp< GrDirectContext > GetGrContext()
void * GetProcAddress(const char *name) const
sk_sp< GrDirectContext > CreateGrContext()
sk_sp< SkImage > GetRasterSurfaceSnapshot()
const SkISize & GetSurfaceSize() const
sk_sp< SkSurface > GetOnscreenSurface()
TestGLSurface(SkISize surface_size)
VkSurfaceKHR surface
Definition: main.cc:49
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
SK_API GrBackendRenderTarget MakeGL(int width, int height, int sampleCnt, int stencilBits, const GrGLFramebufferInfo &glInfo)
SK_API sk_sp< GrDirectContext > MakeGL(sk_sp< const GrGLInterface >, const GrContextOptions &)
SK_API sk_sp< SkSurface > WrapBackendRenderTarget(GrRecordingContext *context, const GrBackendRenderTarget &backendRenderTarget, GrSurfaceOrigin origin, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, RenderTargetReleaseProc releaseProc=nullptr, ReleaseContext releaseContext=nullptr)
static void CheckSwanglekExtensions()
static bool HasExtension(const char *extensions, const char *name)
static EGLDisplay CreateSwangleDisplay()
static std::string GetEGLError()
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
const myers::Point & get(const myers::Segment &)
int32_t height
int32_t width
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
#define ERROR(message)
Definition: elf_loader.cc:260