| Flutter Linux Embedder |

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
8 #include "flutter/common/constants.h"
9 #include "flutter/fml/logging.h"
10 #include "flutter/fml/synchronization/waitable_event.h"
11 #include "flutter/shell/platform/linux/fl_compositor_opengl.h"
12 #include "flutter/shell/platform/linux/fl_engine_private.h"
13 #include "flutter/shell/platform/linux/fl_framebuffer.h"
14 #include "flutter/shell/platform/linux/fl_opengl_manager.h"
15 #include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
16 #include "flutter/shell/platform/linux/testing/mock_epoxy.h"
17 #include "flutter/shell/platform/linux/testing/mock_renderable.h"
18
19 #include <epoxy/egl.h>
20
21 TEST(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);
26 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
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 = {
39 .type = kFlutterBackingStoreTypeOpenGL,
40 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
41 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
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
62 TEST(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);
67 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
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 = {
80 .type = kFlutterBackingStoreTypeOpenGL,
81 .open_gl = {.framebuffer = {.user_data = framebuffer1}}};
82 FlutterLayer layer1 = {.type = kFlutterLayerContentTypeBackingStore,
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 = {
97 .type = kFlutterBackingStoreTypeOpenGL,
98 .open_gl = {.framebuffer = {.user_data = framebuffer2}}};
99 FlutterLayer layer2 = {.type = kFlutterLayerContentTypeBackingStore,
100 .backing_store = &backing_store2,
101 .offset = {0, 0},
102 .size = {width2, height2}};
103 const FlutterLayer* layers2[1] = {&layer2};
104 fml::AutoResetWaitableEvent latch;
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
124 TEST(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);
129 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
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 = {
149 .type = kFlutterBackingStoreTypeOpenGL,
150 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
151 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
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 glDisable(GL_BLEND);
160 glEnable(GL_SCISSOR_TEST);
161
162 // Present layer and render.
163 std::thread([&]() {
164 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
165 }).join();
166 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
167 g_autofree unsigned char* image_data =
168 static_cast<unsigned char*>(malloc(height * stride));
169 cairo_surface_t* surface = cairo_image_surface_create_for_data(
170 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
171 cairo_t* cr = cairo_create(surface);
172 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
173 cairo_surface_destroy(surface);
174 cairo_destroy(cr);
175
176 GLuint texture_2d_binding;
177 glGetIntegerv(GL_TEXTURE_BINDING_2D,
178 reinterpret_cast<GLint*>(&texture_2d_binding));
179 EXPECT_EQ(texture_2d_binding, kFakeTextureName);
180 EXPECT_EQ(glIsEnabled(GL_BLEND), GL_FALSE);
181 EXPECT_EQ(glIsEnabled(GL_SCISSOR_TEST), GL_TRUE);
182 }
183
184 TEST(FlCompositorOpenGLTest, BlitFramebuffer) {
185 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
186 g_autoptr(FlDartProject) project = fl_dart_project_new();
187 g_autoptr(FlEngine) engine = fl_engine_new(project);
188 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
189 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
190
191 constexpr size_t width = 100;
192 constexpr size_t height = 100;
193
194 // OpenGL 3.0
195 ON_CALL(epoxy, glGetString(GL_VENDOR))
196 .WillByDefault(
197 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
198 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
199 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
200
201 EXPECT_CALL(epoxy, glBlitFramebuffer);
202
203 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
204 g_autoptr(FlCompositorOpenGL) compositor =
205 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
206 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
207
208 g_autoptr(FlFramebuffer) framebuffer =
209 fl_framebuffer_new(GL_RGB, width, height, FALSE);
210 FlutterBackingStore backing_store = {
211 .type = kFlutterBackingStoreTypeOpenGL,
212 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
213 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
214 .backing_store = &backing_store,
215 .offset = {0, 0},
216 .size = {width, height}};
217 const FlutterLayer* layers[1] = {&layer};
218
219 // Present layer and render.
220 std::thread([&]() {
221 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
222 }).join();
223 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
224 g_autofree unsigned char* image_data =
225 static_cast<unsigned char*>(malloc(height * stride));
226 cairo_surface_t* surface = cairo_image_surface_create_for_data(
227 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
228 cairo_t* cr = cairo_create(surface);
229 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
230 cairo_surface_destroy(surface);
231 cairo_destroy(cr);
232 }
233
234 TEST(FlCompositorOpenGLTest, BlitFramebufferExtension) {
235 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
236 g_autoptr(FlDartProject) project = fl_dart_project_new();
237 g_autoptr(FlEngine) engine = fl_engine_new(project);
238 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
239 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
240
241 constexpr size_t width = 100;
242 constexpr size_t height = 100;
243
244 // OpenGL 2.0 with GL_EXT_framebuffer_blit extension
245 ON_CALL(epoxy, glGetString(GL_VENDOR))
246 .WillByDefault(
247 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
248 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
249 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
250 EXPECT_CALL(epoxy, epoxy_has_gl_extension(::testing::_))
251 .WillRepeatedly(::testing::Return(false));
252 EXPECT_CALL(epoxy, epoxy_has_gl_extension(
253 ::testing::StrEq("GL_EXT_framebuffer_blit")))
254 .WillRepeatedly(::testing::Return(true));
255
256 EXPECT_CALL(epoxy, glBlitFramebuffer);
257
258 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
259 g_autoptr(FlCompositorOpenGL) compositor =
260 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
261 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
262
263 g_autoptr(FlFramebuffer) framebuffer =
264 fl_framebuffer_new(GL_RGB, width, height, FALSE);
265 FlutterBackingStore backing_store = {
266 .type = kFlutterBackingStoreTypeOpenGL,
267 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
268 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
269 .backing_store = &backing_store,
270 .offset = {0, 0},
271 .size = {width, height}};
272 const FlutterLayer* layers[1] = {&layer};
273
274 // Present layer and render.
275 std::thread([&]() {
276 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
277 }).join();
278 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
279 g_autofree unsigned char* image_data =
280 static_cast<unsigned char*>(malloc(height * stride));
281 cairo_surface_t* surface = cairo_image_surface_create_for_data(
282 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
283 cairo_t* cr = cairo_create(surface);
284 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
285 cairo_surface_destroy(surface);
286 cairo_destroy(cr);
287 }
288
289 TEST(FlCompositorOpenGLTest, NoBlitFramebuffer) {
290 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
291 g_autoptr(FlDartProject) project = fl_dart_project_new();
292 g_autoptr(FlEngine) engine = fl_engine_new(project);
293 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
294 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
295
296 constexpr size_t width = 100;
297 constexpr size_t height = 100;
298
299 // OpenGL 2.0
300 ON_CALL(epoxy, glGetString(GL_VENDOR))
301 .WillByDefault(
302 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
303 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
304 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
305
306 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
307 g_autoptr(FlCompositorOpenGL) compositor =
308 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
309 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
310
311 g_autoptr(FlFramebuffer) framebuffer =
312 fl_framebuffer_new(GL_RGB, width, height, FALSE);
313 FlutterBackingStore backing_store = {
314 .type = kFlutterBackingStoreTypeOpenGL,
315 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
316 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
317 .backing_store = &backing_store,
318 .offset = {0, 0},
319 .size = {width, height}};
320 const FlutterLayer* layers[1] = {&layer};
321
322 // Present layer and render.
323 std::thread([&]() {
324 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
325 }).join();
326 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
327 g_autofree unsigned char* image_data =
328 static_cast<unsigned char*>(malloc(height * stride));
329 cairo_surface_t* surface = cairo_image_surface_create_for_data(
330 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
331 cairo_t* cr = cairo_create(surface);
332 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
333 cairo_surface_destroy(surface);
334 cairo_destroy(cr);
335 }
336
337 TEST(FlCompositorOpenGLTest, BlitFramebufferNvidia) {
338 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
339 g_autoptr(FlDartProject) project = fl_dart_project_new();
340 g_autoptr(FlEngine) engine = fl_engine_new(project);
341 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
342 g_autoptr(FlOpenGLManager) opengl_manager = fl_opengl_manager_new();
343
344 constexpr size_t width = 100;
345 constexpr size_t height = 100;
346
347 // OpenGL 3.0, but on NVIDIA driver so temporarily disabled due to
348 // https://github.com/flutter/flutter/issues/152099
349 ON_CALL(epoxy, glGetString(GL_VENDOR))
350 .WillByDefault(
351 ::testing::Return(reinterpret_cast<const GLubyte*>("NVIDIA")));
352 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
353 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
354
355 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
356 g_autoptr(FlCompositorOpenGL) compositor =
357 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
358 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
359
360 g_autoptr(FlFramebuffer) framebuffer =
361 fl_framebuffer_new(GL_RGB, width, height, FALSE);
362 FlutterBackingStore backing_store = {
363 .type = kFlutterBackingStoreTypeOpenGL,
364 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
365 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
366 .backing_store = &backing_store,
367 .offset = {0, 0},
368 .size = {width, height}};
369 const FlutterLayer* layers[1] = {&layer};
370
371 // Present layer and render.
372 std::thread([&]() {
373 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
374 }).join();
375 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
376 g_autofree unsigned char* image_data =
377 static_cast<unsigned char*>(malloc(height * stride));
378 cairo_surface_t* surface = cairo_image_surface_create_for_data(
379 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
380 cairo_t* cr = cairo_create(surface);
381 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr);
382 cairo_surface_destroy(surface);
383 cairo_destroy(cr);
384 }
fl_compositor_render
gboolean fl_compositor_render(FlCompositor *self, cairo_t *cr, GdkWindow *window)
Definition: fl_compositor.cc:23
fl_compositor_present_layers
gboolean fl_compositor_present_layers(FlCompositor *self, const FlutterLayer **layers, size_t layers_count)
Definition: fl_compositor.cc:15
fl_compositor_opengl_new
FlCompositorOpenGL * fl_compositor_opengl_new(FlTaskRunner *task_runner, FlOpenGLManager *opengl_manager, gboolean shareable)
Definition: fl_compositor_opengl.cc:442
fl_compositor_opengl.h
opengl_manager
G_BEGIN_DECLS FlOpenGLManager * opengl_manager
Definition: fl_compositor_opengl.h:42
TEST
TEST(FlCompositorOpenGLTest, Render)
Definition: fl_compositor_opengl_test.cc:21
layers
const FlutterLayer ** layers
Definition: fl_compositor_software.cc:32
height
self height
Definition: fl_compositor_software.cc:43
g_autoptr
g_autoptr(GMutexLocker) locker
width
self width
Definition: fl_compositor_software.cc:42
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:52
fl_dart_project.h
fl_engine_set_implicit_view
void fl_engine_set_implicit_view(FlEngine *self, FlRenderable *renderable)
Definition: fl_engine.cc:881
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:697
fl_engine_private.h
fl_framebuffer_new
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height, gboolean shareable)
Definition: fl_framebuffer.cc:69
fl_framebuffer.h
fl_opengl_manager_new
FlOpenGLManager * fl_opengl_manager_new()
Definition: fl_opengl_manager.cc:70
fl_opengl_manager.h
fl_task_runner_new
FlTaskRunner * fl_task_runner_new(FlEngine *engine)
Definition: fl_task_runner.cc:147