Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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);
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 size_t frame_width, frame_height;
51 fl_compositor_get_frame_size(FL_COMPOSITOR(compositor), &frame_width,
52 &frame_height);
53 EXPECT_EQ(frame_width, width);
54 EXPECT_EQ(frame_height, height);
55
56 // Render presented layer.
57 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
58 g_autofree unsigned char* image_data =
59 static_cast<unsigned char*>(malloc(height * stride));
60 cairo_surface_t* surface = cairo_image_surface_create_for_data(
61 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
62 cairo_t* cr = cairo_create(surface);
63 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
64 cairo_surface_destroy(surface);
65 cairo_destroy(cr);
66}
67
68TEST(FlCompositorOpenGLTest, Resize) {
69 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
70 g_autoptr(FlDartProject) project = fl_dart_project_new();
71 g_autoptr(FlEngine) engine = fl_engine_new(project);
72 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
74
75 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
76 g_autoptr(FlCompositorOpenGL) compositor =
77 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
79
80 // Present a layer that is the old size.
81 constexpr size_t width1 = 90;
82 constexpr size_t height1 = 90;
83 g_autoptr(FlFramebuffer) framebuffer1 =
84 fl_framebuffer_new(GL_RGB, width1, height1, FALSE);
85 FlutterBackingStore backing_store1 = {
87 .open_gl = {.framebuffer = {.user_data = framebuffer1}}};
89 .backing_store = &backing_store1,
90 .offset = {0, 0},
91 .size = {width1, height1}};
92 const FlutterLayer* layers1[1] = {&layer1};
93 std::thread([&]() {
94 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers1, 1);
95 }).join();
96
97 // Present layer in current size.
98 constexpr size_t width2 = 100;
99 constexpr size_t height2 = 100;
100 g_autoptr(FlFramebuffer) framebuffer2 =
101 fl_framebuffer_new(GL_RGB, width2, height2, FALSE);
102 FlutterBackingStore backing_store2 = {
104 .open_gl = {.framebuffer = {.user_data = framebuffer2}}};
106 .backing_store = &backing_store2,
107 .offset = {0, 0},
108 .size = {width2, height2}};
109 const FlutterLayer* layers2[1] = {&layer2};
111 std::thread([&]() {
112 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers2, 1);
113 latch.Signal();
114 }).detach();
115
116 // Render, will wait for the second layer if necessary.
117 int stride2 = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width2);
118 g_autofree unsigned char* image_data =
119 static_cast<unsigned char*>(malloc(height2 * stride2));
120 cairo_surface_t* surface = cairo_image_surface_create_for_data(
121 image_data, CAIRO_FORMAT_ARGB32, width2, height2, stride2);
122 cairo_t* cr = cairo_create(surface);
123 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
124 cairo_surface_destroy(surface);
125 cairo_destroy(cr);
126
127 latch.Wait();
128}
129
130TEST(FlCompositorOpenGLTest, RestoresGLState) {
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 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
136
137 constexpr size_t width = 100;
138 constexpr size_t height = 100;
139
140 // OpenGL 3.0
141 ON_CALL(epoxy, glGetString(GL_VENDOR))
142 .WillByDefault(
143 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
144 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
145 ON_CALL(epoxy, epoxy_gl_version).WillByDefault(::testing::Return(30));
146
147 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
148 g_autoptr(FlCompositorOpenGL) compositor =
149 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
151
152 g_autoptr(FlFramebuffer) framebuffer =
153 fl_framebuffer_new(GL_RGB, width, height, FALSE);
154 FlutterBackingStore backing_store = {
156 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
158 .backing_store = &backing_store,
159 .offset = {0, 0},
160 .size = {width, height}};
161 const FlutterLayer* layers[1] = {&layer};
162
163 constexpr GLuint kFakeTextureName = 123;
164 glBindTexture(GL_TEXTURE_2D, kFakeTextureName);
165 glDisable(GL_BLEND);
166 glEnable(GL_SCISSOR_TEST);
167
168 // Present layer and render.
169 std::thread([&]() {
170 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
171 }).join();
172 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
173 g_autofree unsigned char* image_data =
174 static_cast<unsigned char*>(malloc(height * stride));
175 cairo_surface_t* surface = cairo_image_surface_create_for_data(
176 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
177 cairo_t* cr = cairo_create(surface);
178 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
179 cairo_surface_destroy(surface);
180 cairo_destroy(cr);
181
182 GLuint texture_2d_binding;
183 glGetIntegerv(GL_TEXTURE_BINDING_2D,
184 reinterpret_cast<GLint*>(&texture_2d_binding));
185 EXPECT_EQ(texture_2d_binding, kFakeTextureName);
186 EXPECT_EQ(glIsEnabled(GL_BLEND), GL_FALSE);
187 EXPECT_EQ(glIsEnabled(GL_SCISSOR_TEST), GL_TRUE);
188}
189
190TEST(FlCompositorOpenGLTest, BlitFramebuffer) {
191 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
192 g_autoptr(FlDartProject) project = fl_dart_project_new();
193 g_autoptr(FlEngine) engine = fl_engine_new(project);
194 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
196
197 constexpr size_t width = 100;
198 constexpr size_t height = 100;
199
200 // OpenGL 3.0
201 ON_CALL(epoxy, glGetString(GL_VENDOR))
202 .WillByDefault(
203 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
204 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
205 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
206
207 EXPECT_CALL(epoxy, glBlitFramebuffer);
208
209 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
210 g_autoptr(FlCompositorOpenGL) compositor =
211 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
213
214 g_autoptr(FlFramebuffer) framebuffer =
215 fl_framebuffer_new(GL_RGB, width, height, FALSE);
216 FlutterBackingStore backing_store = {
218 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
220 .backing_store = &backing_store,
221 .offset = {0, 0},
222 .size = {width, height}};
223 const FlutterLayer* layers[1] = {&layer};
224
225 // Present layer and render.
226 std::thread([&]() {
227 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
228 }).join();
229 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
230 g_autofree unsigned char* image_data =
231 static_cast<unsigned char*>(malloc(height * stride));
232 cairo_surface_t* surface = cairo_image_surface_create_for_data(
233 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
234 cairo_t* cr = cairo_create(surface);
235 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
236 cairo_surface_destroy(surface);
237 cairo_destroy(cr);
238}
239
240TEST(FlCompositorOpenGLTest, BlitFramebufferExtension) {
241 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
242 g_autoptr(FlDartProject) project = fl_dart_project_new();
243 g_autoptr(FlEngine) engine = fl_engine_new(project);
244 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
246
247 constexpr size_t width = 100;
248 constexpr size_t height = 100;
249
250 // OpenGL 2.0 with GL_EXT_framebuffer_blit extension
251 ON_CALL(epoxy, glGetString(GL_VENDOR))
252 .WillByDefault(
253 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
254 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
255 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
256 EXPECT_CALL(epoxy, epoxy_has_gl_extension(::testing::_))
257 .WillRepeatedly(::testing::Return(false));
258 EXPECT_CALL(epoxy, epoxy_has_gl_extension(
259 ::testing::StrEq("GL_EXT_framebuffer_blit")))
260 .WillRepeatedly(::testing::Return(true));
261
262 EXPECT_CALL(epoxy, glBlitFramebuffer);
263
264 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
265 g_autoptr(FlCompositorOpenGL) compositor =
266 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
268
269 g_autoptr(FlFramebuffer) framebuffer =
270 fl_framebuffer_new(GL_RGB, width, height, FALSE);
271 FlutterBackingStore backing_store = {
273 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
275 .backing_store = &backing_store,
276 .offset = {0, 0},
277 .size = {width, height}};
278 const FlutterLayer* layers[1] = {&layer};
279
280 // Present layer and render.
281 std::thread([&]() {
282 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
283 }).join();
284 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
285 g_autofree unsigned char* image_data =
286 static_cast<unsigned char*>(malloc(height * stride));
287 cairo_surface_t* surface = cairo_image_surface_create_for_data(
288 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
289 cairo_t* cr = cairo_create(surface);
290 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
291 cairo_surface_destroy(surface);
292 cairo_destroy(cr);
293}
294
295TEST(FlCompositorOpenGLTest, NoBlitFramebuffer) {
296 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
297 g_autoptr(FlDartProject) project = fl_dart_project_new();
298 g_autoptr(FlEngine) engine = fl_engine_new(project);
299 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
301
302 constexpr size_t width = 100;
303 constexpr size_t height = 100;
304
305 // OpenGL 2.0
306 ON_CALL(epoxy, glGetString(GL_VENDOR))
307 .WillByDefault(
308 ::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
309 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
310 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
311
312 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
313 g_autoptr(FlCompositorOpenGL) compositor =
314 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
316
317 g_autoptr(FlFramebuffer) framebuffer =
318 fl_framebuffer_new(GL_RGB, width, height, FALSE);
319 FlutterBackingStore backing_store = {
321 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
323 .backing_store = &backing_store,
324 .offset = {0, 0},
325 .size = {width, height}};
326 const FlutterLayer* layers[1] = {&layer};
327
328 // Present layer and render.
329 std::thread([&]() {
330 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
331 }).join();
332 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
333 g_autofree unsigned char* image_data =
334 static_cast<unsigned char*>(malloc(height * stride));
335 cairo_surface_t* surface = cairo_image_surface_create_for_data(
336 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
337 cairo_t* cr = cairo_create(surface);
338 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
339 cairo_surface_destroy(surface);
340 cairo_destroy(cr);
341}
342
343TEST(FlCompositorOpenGLTest, BlitFramebufferNvidia) {
344 ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
345 g_autoptr(FlDartProject) project = fl_dart_project_new();
346 g_autoptr(FlEngine) engine = fl_engine_new(project);
347 g_autoptr(FlTaskRunner) task_runner = fl_task_runner_new(engine);
349
350 constexpr size_t width = 100;
351 constexpr size_t height = 100;
352
353 // OpenGL 3.0, but on NVIDIA driver so temporarily disabled due to
354 // https://github.com/flutter/flutter/issues/152099
355 ON_CALL(epoxy, glGetString(GL_VENDOR))
356 .WillByDefault(
357 ::testing::Return(reinterpret_cast<const GLubyte*>("NVIDIA")));
358 ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
359 EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
360
361 g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
362 g_autoptr(FlCompositorOpenGL) compositor =
363 fl_compositor_opengl_new(task_runner, opengl_manager, FALSE);
365
366 g_autoptr(FlFramebuffer) framebuffer =
367 fl_framebuffer_new(GL_RGB, width, height, FALSE);
368 FlutterBackingStore backing_store = {
370 .open_gl = {.framebuffer = {.user_data = framebuffer}}};
372 .backing_store = &backing_store,
373 .offset = {0, 0},
374 .size = {width, height}};
375 const FlutterLayer* layers[1] = {&layer};
376
377 // Present layer and render.
378 std::thread([&]() {
379 fl_compositor_present_layers(FL_COMPOSITOR(compositor), layers, 1);
380 }).join();
381 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
382 g_autofree unsigned char* image_data =
383 static_cast<unsigned char*>(malloc(height * stride));
384 cairo_surface_t* surface = cairo_image_surface_create_for_data(
385 image_data, CAIRO_FORMAT_ARGB32, width, height, stride);
386 cairo_t* cr = cairo_create(surface);
387 fl_compositor_render(FL_COMPOSITOR(compositor), cr, nullptr, TRUE);
388 cairo_surface_destroy(surface);
389 cairo_destroy(cr);
390}
@ kFlutterLayerContentTypeBackingStore
Definition embedder.h:2140
@ kFlutterBackingStoreTypeOpenGL
Definition embedder.h:2089
FlutterEngine engine
Definition main.cc:84
VkSurfaceKHR surface
Definition main.cc:65
g_autoptr(FlEngine) engine
FlRenderable * renderable
gboolean fl_compositor_render(FlCompositor *self, cairo_t *cr, GdkWindow *window, gboolean wait_for_frame)
void fl_compositor_get_frame_size(FlCompositor *self, size_t *width, size_t *height)
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
return TRUE
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
void fl_engine_set_implicit_view(FlEngine *self, FlRenderable *renderable)
Definition fl_engine.cc:920
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition fl_engine.cc:730
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:2109
FlutterLayerContentType type
Definition embedder.h:2172