| 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/public/flutter_linux/fl_dart_project.h"
15 #include "flutter/shell/platform/linux/testing/mock_epoxy.h"
16 #include "flutter/shell/platform/linux/testing/mock_renderable.h"
17
18 #include <epoxy/egl.h>
19
20 TEST(FlCompositorOpenGLTest, RestoresGLState) {
21 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
22 g_autoptr(FlDartProject) project = fl_dart_project_new();
23 g_autoptr(FlEngine) engine = fl_engine_new(project);
24
25 constexpr int kWidth = 100;
26 constexpr int kHeight = 100;
27
28 // OpenGL 3.0
29 ON_CALL(epoxy, glGetString(GL_VENDOR))
30 .WillByDefault(
31 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
32 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
33 ON_CALL(epoxy, epoxy_gl_version).WillByDefault(::testing::Return(30));
34
35 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
36 g_autoptr(FlCompositorOpenGL) compositor =
37 fl_compositor_opengl_new(engine, nullptr);
38 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
39 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
40
41 fml::AutoResetWaitableEvent latch;
42
43 g_autoptr(FlFramebuffer) framebuffer =
44 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
45 FlutterBackingStore backing_store = {
46 .type = kFlutterBackingStoreTypeOpenGL,
47 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
48 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
49 .backing_store = &backing_store,
50 .offset = {0, 0},
51 .size = {kWidth, kHeight}};
52 const FlutterLayer* layers[1] = {&layer};
53
54 constexpr GLuint kFakeTextureName = 123;
55 glBindTexture(GL_TEXTURE_2D, kFakeTextureName);
56
57 // Simulate raster thread.
58 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
59 std::thread([&]() {
60 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
61 g_main_loop_quit(loop);
62 latch.Signal();
63 }).detach();
64
65 g_main_loop_run(loop);
66
67 fl_compositor_opengl_render(compositor, kWidth, kHeight);
68
69 GLuint texture_2d_binding;
70 glGetIntegerv(GL_TEXTURE_BINDING_2D,
71 reinterpret_cast<GLint*>(&texture_2d_binding));
72 EXPECT_EQ(texture_2d_binding, kFakeTextureName);
73
74 // Wait until the raster thread has finished before letting
75 // the engine go out of scope.
76 latch.Wait();
77 }
78
79 TEST(FlCompositorOpenGLTest, BlitFramebuffer) {
80 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
81 g_autoptr(FlDartProject) project = fl_dart_project_new();
82 g_autoptr(FlEngine) engine = fl_engine_new(project);
83
84 constexpr int kWidth = 100;
85 constexpr int kHeight = 100;
86
87 // OpenGL 3.0
88 ON_CALL(epoxy, glGetString(GL_VENDOR))
89 .WillByDefault(
90 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
91 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
92 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
93
94 EXPECT_CALL(epoxy, glBlitFramebuffer);
95
96 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
97 g_autoptr(FlCompositorOpenGL) compositor =
98 fl_compositor_opengl_new(engine, nullptr);
99 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
100 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
101
102 fml::AutoResetWaitableEvent latch;
103
104 g_autoptr(FlFramebuffer) framebuffer =
105 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
106 FlutterBackingStore backing_store = {
107 .type = kFlutterBackingStoreTypeOpenGL,
108 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
109 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
110 .backing_store = &backing_store,
111 .offset = {0, 0},
112 .size = {kWidth, kHeight}};
113 const FlutterLayer* layers[1] = {&layer};
114
115 // Simulate raster thread.
116 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
117 std::thread([&]() {
118 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
119 g_main_loop_quit(loop);
120 latch.Signal();
121 }).detach();
122
123 g_main_loop_run(loop);
124
125 fl_compositor_opengl_render(compositor, kWidth, kHeight);
126
127 latch.Wait();
128 }
129
130 TEST(FlCompositorOpenGLTest, BlitFramebufferExtension) {
131 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
132 g_autoptr(FlDartProject) project = fl_dart_project_new();
133 g_autoptr(FlEngine) engine = fl_engine_new(project);
134
135 constexpr int kWidth = 100;
136 constexpr int kHeight = 100;
137
138 // OpenGL 2.0 with GL_EXT_framebuffer_blit extension
139 ON_CALL(epoxy, glGetString(GL_VENDOR))
140 .WillByDefault(
141 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
142 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
143 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
144 EXPECT_CALL(epoxy, epoxy_has_gl_extension(::testing::_))
145 .WillRepeatedly(::testing::Return(false));
146 EXPECT_CALL(epoxy, epoxy_has_gl_extension(
147 ::testing::StrEq("GL_EXT_framebuffer_blit")))
148 .WillRepeatedly(::testing::Return(true));
149
150 EXPECT_CALL(epoxy, glBlitFramebuffer);
151
152 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
153 g_autoptr(FlCompositorOpenGL) compositor =
154 fl_compositor_opengl_new(engine, nullptr);
155 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
156 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
157
158 fml::AutoResetWaitableEvent latch;
159
160 g_autoptr(FlFramebuffer) framebuffer =
161 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
162 FlutterBackingStore backing_store = {
163 .type = kFlutterBackingStoreTypeOpenGL,
164 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
165 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
166 .backing_store = &backing_store,
167 .offset = {0, 0},
168 .size = {kWidth, kHeight}};
169 const FlutterLayer* layers[1] = {&layer};
170
171 // Simulate raster thread.
172 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
173 std::thread([&]() {
174 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
175 g_main_loop_quit(loop);
176 latch.Signal();
177 }).detach();
178
179 g_main_loop_run(loop);
180
181 fl_compositor_opengl_render(compositor, kWidth, kHeight);
182 // Wait until the raster thread has finished before letting
183 // the engine go out of scope.
184 latch.Wait();
185 }
186
187 TEST(FlCompositorOpenGLTest, NoBlitFramebuffer) {
188 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
189 g_autoptr(FlDartProject) project = fl_dart_project_new();
190 g_autoptr(FlEngine) engine = fl_engine_new(project);
191
192 constexpr int kWidth = 100;
193 constexpr int kHeight = 100;
194
195 // OpenGL 2.0
196 ON_CALL(epoxy, glGetString(GL_VENDOR))
197 .WillByDefault(
198 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
199 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
200 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
201
202 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
203 g_autoptr(FlCompositorOpenGL) compositor =
204 fl_compositor_opengl_new(engine, nullptr);
205 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
206 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
207
208 fml::AutoResetWaitableEvent latch;
209
210 g_autoptr(FlFramebuffer) framebuffer =
211 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
212 FlutterBackingStore backing_store = {
213 .type = kFlutterBackingStoreTypeOpenGL,
214 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
215 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
216 .backing_store = &backing_store,
217 .offset = {0, 0},
218 .size = {kWidth, kHeight}};
219 const FlutterLayer* layers[1] = {&layer};
220
221 // Simulate raster thread.
222 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
223 std::thread([&]() {
224 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
225 g_main_loop_quit(loop);
226 latch.Signal();
227 }).detach();
228
229 g_main_loop_run(loop);
230
231 fl_compositor_opengl_render(compositor, kWidth, kHeight);
232
233 // Wait until the raster thread has finished before letting
234 // the engine go out of scope.
235 latch.Wait();
236 }
237
238 TEST(FlCompositorOpenGLTest, BlitFramebufferNvidia) {
239 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
240 g_autoptr(FlDartProject) project = fl_dart_project_new();
241 g_autoptr(FlEngine) engine = fl_engine_new(project);
242
243 constexpr int kWidth = 100;
244 constexpr int kHeight = 100;
245
246 // OpenGL 3.0, but on NVIDIA driver so temporarily disabled due to
247 // https://github.com/flutter/flutter/issues/152099
248 ON_CALL(epoxy, glGetString(GL_VENDOR))
249 .WillByDefault(
250 ::testing::Return(reinterpret_cast<const GLubyte*>("NVIDIA")));
251 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
252 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
253
254 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
255 g_autoptr(FlCompositorOpenGL) compositor =
256 fl_compositor_opengl_new(engine, nullptr);
257 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
258 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
259
260 fml::AutoResetWaitableEvent latch;
261
262 g_autoptr(FlFramebuffer) framebuffer =
263 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
264 FlutterBackingStore backing_store = {
265 .type = kFlutterBackingStoreTypeOpenGL,
266 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
267 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
268 .backing_store = &backing_store,
269 .offset = {0, 0},
270 .size = {kWidth, kHeight}};
271 const FlutterLayer* layers[1] = {&layer};
272
273 // Simulate raster thread.
274 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
275 std::thread([&]() {
276 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
277 g_main_loop_quit(loop);
278 latch.Signal();
279 }).detach();
280
281 g_main_loop_run(loop);
282
283 fl_compositor_opengl_render(compositor, kWidth, kHeight);
284
285 // Wait until the raster thread has finished before letting
286 // the engine go out of scope.
287 latch.Wait();
288 }
289
290 TEST(FlCompositorOpenGLTest, MultiView) {
291 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
292 g_autoptr(FlDartProject) project = fl_dart_project_new();
293 g_autoptr(FlEngine) engine = fl_engine_new(project);
294
295 constexpr int kWidth = 100;
296 constexpr int kHeight = 100;
297
298 // OpenGL 3.0
299 ON_CALL(epoxy, glGetString(GL_VENDOR))
300 .WillByDefault(
301 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
302 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
303 ON_CALL(epoxy, epoxy_gl_version).WillByDefault(::testing::Return(30));
304
305 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
306 g_autoptr(FlMockRenderable) secondary_renderable = fl_mock_renderable_new();
307
308 g_autoptr(FlCompositorOpenGL) compositor =
309 fl_compositor_opengl_new(engine, nullptr);
310 fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable));
311 fl_engine_add_view(engine, FL_RENDERABLE(secondary_renderable), 1024, 768,
312 1.0, nullptr, nullptr, nullptr);
313 fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), kWidth, kHeight);
314
315 fml::AutoResetWaitableEvent latch;
316
317 g_autoptr(FlFramebuffer) framebuffer =
318 fl_framebuffer_new(GL_RGB, kWidth, kHeight);
319 FlutterBackingStore backing_store = {
320 .type = kFlutterBackingStoreTypeOpenGL,
321 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
322 FlutterLayer layer = {.type = kFlutterLayerContentTypeBackingStore,
323 .backing_store = &backing_store,
324 .offset = {0, 0},
325 .size = {kWidth, kHeight}};
326 const FlutterLayer* layers[1] = {&layer};
327
328 // Simulate raster thread.
329 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
330 std::thread([&]() {
331 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
332 g_main_loop_quit(loop);
333 latch.Signal();
334 }).detach();
335
336 g_main_loop_run(loop);
337
338 // FIXME
339 // EXPECT_EQ(fl_mock_renderable_get_present_count(renderable),
340 // static_cast<size_t>(0));
341 // EXPECT_EQ(fl_mock_renderable_get_present_count(secondary_renderable),
342 // static_cast<size_t>(1));
343
344 // Wait until the raster thread has finished before letting
345 // the engine go out of scope.
346 latch.Wait();
347 }
fl_compositor_wait_for_frame
void fl_compositor_wait_for_frame(FlCompositor *self, int target_width, int target_height)
Definition: fl_compositor.cc:21
fl_compositor_present_layers
gboolean fl_compositor_present_layers(FlCompositor *self, const FlutterLayer **layers, size_t layers_count)
Definition: fl_compositor.cc:29
fl_compositor_opengl_new
FlCompositorOpenGL * fl_compositor_opengl_new(FlEngine *engine, GdkGLContext *context)
Definition: fl_compositor_opengl.cc:520
fl_compositor_opengl_render
void fl_compositor_opengl_render(FlCompositorOpenGL *self, int width, int height)
Definition: fl_compositor_opengl.cc:545
fl_compositor_opengl.h
TEST
TEST(FlCompositorOpenGLTest, RestoresGLState)
Definition: fl_compositor_opengl_test.cc:20
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:875
fl_engine_add_view
FlutterViewId fl_engine_add_view(FlEngine *self, FlRenderable *renderable, size_t width, size_t height, double pixel_ratio, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:882
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:691
fl_engine_private.h
fl_framebuffer_new
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height)
Definition: fl_framebuffer.cc:46
fl_framebuffer.h