Flutter Engine
 
Loading...
Searching...
No Matches
fl_compositor_opengl_test.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 <thread>
6#include "gtest/gtest.h"
7
18
19#include <epoxy/egl.h>
20
21TEST(FlCompositorOpenGLTest, Render) {
22 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
23 g_autoptr(FlDartProject) project = fl_dart_project_new();
24 g_autoptr(FlEngine) engine = fl_engine_new(project);
25 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
27
28 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
29 g_autoptr(FlCompositorOpenGL) compositor =
30 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
31 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
32
33 // Present layer from a thread.
34 constexpr size_t width = 100;
35 constexpr size_t height = 100;
36 g_autoptr(FlFramebuffer) framebuffer =
37 fl_framebuffer_new(GL_RGB, width, height, FALSE);
38 FlutterBackingStore backing_store = {
40 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
42 .backing_store = &backing_store,
43 .offset = {0, 0},
44 .size = {width, height}};
45 const FlutterLayer* layers[1] = {&layer};
46 std::thread([&]() {
47 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
48 }).join();
49
50 // Render presented layer.
51 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
52 g_autofree unsigned char* image_data =
53 static_cast<unsigned char*>(malloc(height * stride));
54 cairo_surface_t* surface = cairo_image_surface_create_for_data(
55 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
56 cairo_t* cr = cairo_create(surface);
57 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
58 cairo_surface_destroy(surface);
59 cairo_destroy(cr);
60}
61
62TEST(FlCompositorOpenGLTest, Resize) {
63 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
64 g_autoptr(FlDartProject) project = fl_dart_project_new();
65 g_autoptr(FlEngine) engine = fl_engine_new(project);
66 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
68
69 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
70 g_autoptr(FlCompositorOpenGL) compositor =
71 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
72 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
73
74 // Present a layer that is the old size.
75 constexpr size_t width1 = 90;
76 constexpr size_t height1 = 90;
77 g_autoptr(FlFramebuffer) framebuffer1 =
78 fl_framebuffer_new(GL_RGB, width1, height1, FALSE);
79 FlutterBackingStore backing_store1 = {
81 .open_gl = {.framebuffer = {.user_data = framebuffer1}}};
83 .backing_store = &backing_store1,
84 .offset = {0, 0},
85 .size = {width1, height1}};
86 const FlutterLayer* layers1[1] = {&layer1};
87 std::thread([&]() {
88 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers1, 1);
89 }).join();
90
91 // Present layer in current size.
92 constexpr size_t width2 = 100;
93 constexpr size_t height2 = 100;
94 g_autoptr(FlFramebuffer) framebuffer2 =
95 fl_framebuffer_new(GL_RGB, width2, height2, FALSE);
96 FlutterBackingStore backing_store2 = {
98 .open_gl = {.framebuffer = {.user_data = framebuffer2}}};
100 .backing_store = &backing_store2,
101 .offset = {0, 0},
102 .size = {width2, height2}};
103 const FlutterLayer* layers2[1] = {&layer2};
105 std::thread([&]() {
106 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers2, 1);
107 latch.Signal();
108 }).detach();
109
110 // Render, will wait for the second layer if necessary.
111 int stride2 = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width2);
112 g_autofree unsigned char* image_data =
113 static_cast<unsigned char*>(malloc(height2 * stride2));
114 cairo_surface_t* surface = cairo_image_surface_create_for_data(
115 image_data, CAIRO_FORMAT_ARGB32, width2, height2, stride2);
116 cairo_t* cr = cairo_create(surface);
117 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
118 cairo_surface_destroy(surface);
119 cairo_destroy(cr);
120
121 latch.Wait();
122}
123
124TEST(FlCompositorOpenGLTest, RestoresGLState) {
125 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
126 g_autoptr(FlDartProject) project = fl_dart_project_new();
127 g_autoptr(FlEngine) engine = fl_engine_new(project);
128 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
130
131 constexpr size_t width = 100;
132 constexpr size_t height = 100;
133
134 // OpenGL 3.0
135 ON_CALL(epoxy, glGetString(GL_VENDOR))
136 .WillByDefault(
137 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
138 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
139 ON_CALL(epoxy, epoxy_gl_version).WillByDefault(::testing::Return(30));
140
141 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
142 g_autoptr(FlCompositorOpenGL) compositor =
143 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
144 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
145
146 g_autoptr(FlFramebuffer) framebuffer =
147 fl_framebuffer_new(GL_RGB, width, height, FALSE);
148 FlutterBackingStore backing_store = {
150 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
152 .backing_store = &backing_store,
153 .offset = {0, 0},
154 .size = {width, height}};
155 const FlutterLayer* layers[1] = {&layer};
156
157 constexpr GLuint kFakeTextureName = 123;
158 glBindTexture(GL_TEXTURE_2D, kFakeTextureName);
159
160 // Present layer and render.
161 std::thread([&]() {
162 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
163 }).join();
164 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
165 g_autofree unsigned char* image_data =
166 static_cast<unsigned char*>(malloc(height * stride));
167 cairo_surface_t* surface = cairo_image_surface_create_for_data(
168 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
169 cairo_t* cr = cairo_create(surface);
170 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
171 cairo_surface_destroy(surface);
172 cairo_destroy(cr);
173
174 GLuint texture_2d_binding;
175 glGetIntegerv(GL_TEXTURE_BINDING_2D,
176 reinterpret_cast<GLint*>(&texture_2d_binding));
177 EXPECT_EQ(texture_2d_binding, kFakeTextureName);
178}
179
180TEST(FlCompositorOpenGLTest, BlitFramebuffer) {
181 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
182 g_autoptr(FlDartProject) project = fl_dart_project_new();
183 g_autoptr(FlEngine) engine = fl_engine_new(project);
184 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
186
187 constexpr size_t width = 100;
188 constexpr size_t height = 100;
189
190 // OpenGL 3.0
191 ON_CALL(epoxy, glGetString(GL_VENDOR))
192 .WillByDefault(
193 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
194 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
195 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
196
197 EXPECT_CALL(epoxy, glBlitFramebuffer);
198
199 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
200 g_autoptr(FlCompositorOpenGL) compositor =
201 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
202 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
203
204 g_autoptr(FlFramebuffer) framebuffer =
205 fl_framebuffer_new(GL_RGB, width, height, FALSE);
206 FlutterBackingStore backing_store = {
208 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
210 .backing_store = &backing_store,
211 .offset = {0, 0},
212 .size = {width, height}};
213 const FlutterLayer* layers[1] = {&layer};
214
215 // Present layer and render.
216 std::thread([&]() {
217 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
218 }).join();
219 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
220 g_autofree unsigned char* image_data =
221 static_cast<unsigned char*>(malloc(height * stride));
222 cairo_surface_t* surface = cairo_image_surface_create_for_data(
223 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
224 cairo_t* cr = cairo_create(surface);
225 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
226 cairo_surface_destroy(surface);
227 cairo_destroy(cr);
228}
229
230TEST(FlCompositorOpenGLTest, BlitFramebufferExtension) {
231 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
232 g_autoptr(FlDartProject) project = fl_dart_project_new();
233 g_autoptr(FlEngine) engine = fl_engine_new(project);
234 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
236
237 constexpr size_t width = 100;
238 constexpr size_t height = 100;
239
240 // OpenGL 2.0 with GL_EXT_framebuffer_blit extension
241 ON_CALL(epoxy, glGetString(GL_VENDOR))
242 .WillByDefault(
243 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
244 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
245 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
246 EXPECT_CALL(epoxy, epoxy_has_gl_extension(::testing::_))
247 .WillRepeatedly(::testing::Return(false));
248 EXPECT_CALL(epoxy, epoxy_has_gl_extension(
249 ::testing::StrEq("GL_EXT_framebuffer_blit")))
250 .WillRepeatedly(::testing::Return(true));
251
252 EXPECT_CALL(epoxy, glBlitFramebuffer);
253
254 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
255 g_autoptr(FlCompositorOpenGL) compositor =
256 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
257 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
258
259 g_autoptr(FlFramebuffer) framebuffer =
260 fl_framebuffer_new(GL_RGB, width, height, FALSE);
261 FlutterBackingStore backing_store = {
263 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
265 .backing_store = &backing_store,
266 .offset = {0, 0},
267 .size = {width, height}};
268 const FlutterLayer* layers[1] = {&layer};
269
270 // Present layer and render.
271 std::thread([&]() {
272 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
273 }).join();
274 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
275 g_autofree unsigned char* image_data =
276 static_cast<unsigned char*>(malloc(height * stride));
277 cairo_surface_t* surface = cairo_image_surface_create_for_data(
278 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
279 cairo_t* cr = cairo_create(surface);
280 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
281 cairo_surface_destroy(surface);
282 cairo_destroy(cr);
283}
284
285TEST(FlCompositorOpenGLTest, NoBlitFramebuffer) {
286 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
287 g_autoptr(FlDartProject) project = fl_dart_project_new();
288 g_autoptr(FlEngine) engine = fl_engine_new(project);
289 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
291
292 constexpr size_t width = 100;
293 constexpr size_t height = 100;
294
295 // OpenGL 2.0
296 ON_CALL(epoxy, glGetString(GL_VENDOR))
297 .WillByDefault(
298 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
299 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
300 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
301
302 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
303 g_autoptr(FlCompositorOpenGL) compositor =
304 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
305 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
306
307 g_autoptr(FlFramebuffer) framebuffer =
308 fl_framebuffer_new(GL_RGB, width, height, FALSE);
309 FlutterBackingStore backing_store = {
311 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
313 .backing_store = &backing_store,
314 .offset = {0, 0},
315 .size = {width, height}};
316 const FlutterLayer* layers[1] = {&layer};
317
318 // Present layer and render.
319 std::thread([&]() {
320 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
321 }).join();
322 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
323 g_autofree unsigned char* image_data =
324 static_cast<unsigned char*>(malloc(height * stride));
325 cairo_surface_t* surface = cairo_image_surface_create_for_data(
326 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
327 cairo_t* cr = cairo_create(surface);
328 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
329 cairo_surface_destroy(surface);
330 cairo_destroy(cr);
331}
332
333TEST(FlCompositorOpenGLTest, BlitFramebufferNvidia) {
334 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
335 g_autoptr(FlDartProject) project = fl_dart_project_new();
336 g_autoptr(FlEngine) engine = fl_engine_new(project);
337 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
339
340 constexpr size_t width = 100;
341 constexpr size_t height = 100;
342
343 // OpenGL 3.0, but on NVIDIA driver so temporarily disabled due to
344 // https://github.com/flutter/flutter/issues/152099
345 ON_CALL(epoxy, glGetString(GL_VENDOR))
346 .WillByDefault(
347 ::testing::Return(reinterpret_cast<const GLubyte*>("NVIDIA")));
348 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
349 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
350
351 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
352 g_autoptr(FlCompositorOpenGL) compositor =
353 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
354 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
355
356 g_autoptr(FlFramebuffer) framebuffer =
357 fl_framebuffer_new(GL_RGB, width, height, FALSE);
358 FlutterBackingStore backing_store = {
360 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
362 .backing_store = &backing_store,
363 .offset = {0, 0},
364 .size = {width, height}};
365 const FlutterLayer* layers[1] = {&layer};
366
367 // Present layer and render.
368 std::thread([&]() {
369 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
370 }).join();
371 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
372 g_autofree unsigned char* image_data =
373 static_cast<unsigned char*>(malloc(height * stride));
374 cairo_surface_t* surface = cairo_image_surface_create_for_data(
375 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
376 cairo_t* cr = cairo_create(surface);
377 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
378 cairo_surface_destroy(surface);
379 cairo_destroy(cr);
380}
@ kFlutterLayerContentTypeBackingStore
Definition embedder.h:2102
@ kFlutterBackingStoreTypeOpenGL
Definition embedder.h:2051
FlutterEngine engine
Definition main.cc:84
VkSurfaceKHR surface
Definition main.cc:65
gboolean fl_compositor_render(FlCompositor *self, cairo_t *cr, GdkWindow *window)
gboolean fl_compositor_present_layers(FlCompositor *self, const FlutterLayer **layers, size_t layers_count)
FlCompositorOpenGL * fl_compositor_opengl_new(FlTaskRunner *task_runner, FlOpenGLManager *opengl_manager, gboolean shareable)
G_BEGIN_DECLS FlOpenGLManager * opengl_manager
TEST(FlCompositorOpenGLTest, Render)
const FlutterLayer ** layers
g_autoptr(GMutexLocker) locker
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
void fl_engine_set_implicit_view(FlEngine *self, FlRenderable *renderable)
Definition fl_engine.cc:885
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition fl_engine.cc:697
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height, gboolean shareable)
FlOpenGLManager * fl_opengl_manager_new()
FlTaskRunner * fl_task_runner_new(FlEngine *engine)
bool epoxy_has_gl_extension(const char *extension)
bool epoxy_is_desktop_gl(void)
int epoxy_gl_version(void)
int32_t height
int32_t width
FlutterBackingStoreType type
Specifies the type of backing store.
Definition embedder.h:2071
FlutterLayerContentType type
Definition embedder.h:2134