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