| Flutter Linux Embedder |

fl_renderer.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 "fl_renderer.h"
6
7 #include <epoxy/egl.h>
8 #include <epoxy/gl.h>
9
10 #include "flutter/shell/platform/embedder/embedder.h"
11 #include "flutter/shell/platform/linux/fl_backing_store_provider.h"
12 #include "flutter/shell/platform/linux/fl_engine_private.h"
13 #include "flutter/shell/platform/linux/fl_view_private.h"
14
15 // Vertex shader to draw Flutter window contents.
16 static const char* vertex_shader_src =
17 "attribute vec2 position;\n"
18 "attribute vec2 in_texcoord;\n"
19 "varying vec2 texcoord;\n"
20 "\n"
21 "void main() {\n"
22 " gl_Position = vec4(position, 0, 1);\n"
23 " texcoord = in_texcoord;\n"
24 "}\n";
25
26 // Fragment shader to draw Flutter window contents.
27 static const char* fragment_shader_src =
28 "#ifdef GL_ES\n"
29 "precision mediump float;\n"
30 "#endif\n"
31 "\n"
32 "uniform sampler2D texture;\n"
33 "varying vec2 texcoord;\n"
34 "\n"
35 "void main() {\n"
36 " gl_FragColor = texture2D(texture, texcoord);\n"
37 "}\n";
38
39 G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error)
40
41 typedef struct {
42 FlView* view;
43
44 // target dimension for resizing
45 int target_width;
46 int target_height;
47
48 // whether the renderer waits for frame render
49 bool blocking_main_thread;
50
51 // true if frame was completed; resizing is not synchronized until first frame
52 // was rendered
53 bool had_first_frame;
54
55 // Shader program.
56 GLuint program;
57
58 // Textures to render.
59 GPtrArray* textures;
60 } FlRendererPrivate;
61
62 G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
63
64 // Returns the log for the given OpenGL shader. Must be freed by the caller.
65 static gchar* get_shader_log(GLuint shader) {
66 int log_length;
67 gchar* log;
68
69 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
70
71 log = static_cast<gchar*>(g_malloc(log_length + 1));
72 glGetShaderInfoLog(shader, log_length, nullptr, log);
73
74 return log;
75 }
76
77 // Returns the log for the given OpenGL program. Must be freed by the caller.
78 static gchar* get_program_log(GLuint program) {
79 int log_length;
80 gchar* log;
81
82 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
83
84 log = static_cast<gchar*>(g_malloc(log_length + 1));
85 glGetProgramInfoLog(program, log_length, nullptr, log);
86
87 return log;
88 }
89
90 /// Converts a pixel co-ordinate from 0..pixels to OpenGL -1..1.
91 static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels) {
92 return (2.0 * position / pixels) - 1.0;
93 }
94
95 static void fl_renderer_unblock_main_thread(FlRenderer* self) {
96 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
97 fl_renderer_get_instance_private(self));
98 if (priv->blocking_main_thread) {
99 priv->blocking_main_thread = false;
100
101 FlTaskRunner* runner =
102 fl_engine_get_task_runner(fl_view_get_engine(priv->view));
103 fl_task_runner_release_main_thread(runner);
104 }
105 }
106
107 static void fl_renderer_dispose(GObject* object) {
108 FlRenderer* self = FL_RENDERER(object);
109 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
110 fl_renderer_get_instance_private(self));
111
112 fl_renderer_unblock_main_thread(self);
113
114 g_clear_pointer(&priv->textures, g_ptr_array_unref);
115
116 G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(object);
117 }
118
119 static void fl_renderer_class_init(FlRendererClass* klass) {
120 G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose;
121 }
122
123 static void fl_renderer_init(FlRenderer* self) {
124 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
125 fl_renderer_get_instance_private(self));
126 priv->textures = g_ptr_array_new_with_free_func(g_object_unref);
127 }
128
129 gboolean fl_renderer_start(FlRenderer* self, FlView* view) {
130 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
131 fl_renderer_get_instance_private(self));
132
133 g_return_val_if_fail(FL_IS_RENDERER(self), FALSE);
134
135 priv->view = view;
136 return TRUE;
137 }
138
139 void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) {
140 g_return_val_if_fail(FL_IS_RENDERER(self), NULL);
141
142 return reinterpret_cast<void*>(eglGetProcAddress(name));
143 }
144
145 void fl_renderer_make_current(FlRenderer* self) {
146 g_return_if_fail(FL_IS_RENDERER(self));
147 FL_RENDERER_GET_CLASS(self)->make_current(self);
148 }
149
150 void fl_renderer_make_resource_current(FlRenderer* self) {
151 g_return_if_fail(FL_IS_RENDERER(self));
152 FL_RENDERER_GET_CLASS(self)->make_resource_current(self);
153 }
154
155 void fl_renderer_clear_current(FlRenderer* self) {
156 g_return_if_fail(FL_IS_RENDERER(self));
157 FL_RENDERER_GET_CLASS(self)->clear_current(self);
158 }
159
160 gdouble fl_renderer_get_refresh_rate(FlRenderer* self) {
161 g_return_val_if_fail(FL_IS_RENDERER(self), -1.0);
162 return FL_RENDERER_GET_CLASS(self)->get_refresh_rate(self);
163 }
164
165 guint32 fl_renderer_get_fbo(FlRenderer* self) {
166 g_return_val_if_fail(FL_IS_RENDERER(self), 0);
167
168 // There is only one frame buffer object - always return that.
169 return 0;
170 }
171
172 gboolean fl_renderer_create_backing_store(
173 FlRenderer* renderer,
174 const FlutterBackingStoreConfig* config,
175 FlutterBackingStore* backing_store_out) {
176 fl_renderer_make_current(renderer);
177
178 FlBackingStoreProvider* provider =
179 fl_backing_store_provider_new(config->size.width, config->size.height);
180 if (!provider) {
181 g_warning("Failed to create backing store");
182 return FALSE;
183 }
184
185 uint32_t name = fl_backing_store_provider_get_gl_framebuffer_id(provider);
186 uint32_t format = fl_backing_store_provider_get_gl_format(provider);
187
188 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
189 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
190 backing_store_out->open_gl.framebuffer.user_data = provider;
191 backing_store_out->open_gl.framebuffer.name = name;
192 backing_store_out->open_gl.framebuffer.target = format;
193 backing_store_out->open_gl.framebuffer.destruction_callback = [](void* p) {
194 // Backing store destroyed in fl_renderer_collect_backing_store(), set
195 // on FlutterCompositor.collect_backing_store_callback during engine start.
196 };
197
198 return TRUE;
199 }
200
201 gboolean fl_renderer_collect_backing_store(
202 FlRenderer* self,
203 const FlutterBackingStore* backing_store) {
204 fl_renderer_make_current(self);
205
206 // OpenGL context is required when destroying #FlBackingStoreProvider.
207 g_object_unref(backing_store->open_gl.framebuffer.user_data);
208 return TRUE;
209 }
210
211 void fl_renderer_wait_for_frame(FlRenderer* self,
212 int target_width,
213 int target_height) {
214 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
215 fl_renderer_get_instance_private(self));
216
217 g_return_if_fail(FL_IS_RENDERER(self));
218
219 priv->target_width = target_width;
220 priv->target_height = target_height;
221
222 if (priv->had_first_frame && !priv->blocking_main_thread) {
223 priv->blocking_main_thread = true;
224 FlTaskRunner* runner =
225 fl_engine_get_task_runner(fl_view_get_engine(priv->view));
226 fl_task_runner_block_main_thread(runner);
227 }
228 }
229
230 gboolean fl_renderer_present_layers(FlRenderer* self,
231 const FlutterLayer** layers,
232 size_t layers_count) {
233 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
234 fl_renderer_get_instance_private(self));
235
236 g_return_val_if_fail(FL_IS_RENDERER(self), FALSE);
237
238 // ignore incoming frame with wrong dimensions in trivial case with just one
239 // layer
240 if (priv->blocking_main_thread && layers_count == 1 &&
241 layers[0]->offset.x == 0 && layers[0]->offset.y == 0 &&
242 (layers[0]->size.width != priv->target_width ||
243 layers[0]->size.height != priv->target_height)) {
244 return true;
245 }
246
247 priv->had_first_frame = true;
248
249 fl_renderer_unblock_main_thread(self);
250
251 if (!priv->view) {
252 return FALSE;
253 }
254
255 g_ptr_array_set_size(priv->textures, 0);
256 for (size_t i = 0; i < layers_count; ++i) {
257 const FlutterLayer* layer = layers[i];
258 switch (layer->type) {
259 case kFlutterLayerContentTypeBackingStore: {
260 const FlutterBackingStore* backing_store = layer->backing_store;
261 auto framebuffer = &backing_store->open_gl.framebuffer;
262 FlBackingStoreProvider* provider =
263 FL_BACKING_STORE_PROVIDER(framebuffer->user_data);
264 g_ptr_array_add(priv->textures, g_object_ref(provider));
265 } break;
266 case kFlutterLayerContentTypePlatformView: {
267 // TODO(robert-ancell) Not implemented -
268 // https://github.com/flutter/flutter/issues/41724
269 } break;
270 }
271 }
272
273 fl_view_redraw(priv->view);
274
275 return TRUE;
276 }
277
278 void fl_renderer_setup(FlRenderer* self) {
279 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
280 fl_renderer_get_instance_private(self));
281
282 g_return_if_fail(FL_IS_RENDERER(self));
283
284 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
285 glShaderSource(vertex_shader, 1, &vertex_shader_src, nullptr);
286 glCompileShader(vertex_shader);
287 int vertex_compile_status;
288 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
289 if (vertex_compile_status == GL_FALSE) {
290 g_autofree gchar* shader_log = get_shader_log(vertex_shader);
291 g_warning("Failed to compile vertex shader: %s", shader_log);
292 }
293
294 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
295 glShaderSource(fragment_shader, 1, &fragment_shader_src, nullptr);
296 glCompileShader(fragment_shader);
297 int fragment_compile_status;
298 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
299 if (fragment_compile_status == GL_FALSE) {
300 g_autofree gchar* shader_log = get_shader_log(fragment_shader);
301 g_warning("Failed to compile fragment shader: %s", shader_log);
302 }
303
304 priv->program = glCreateProgram();
305 glAttachShader(priv->program, vertex_shader);
306 glAttachShader(priv->program, fragment_shader);
307 glLinkProgram(priv->program);
308
309 int link_status;
310 glGetProgramiv(priv->program, GL_LINK_STATUS, &link_status);
311 if (link_status == GL_FALSE) {
312 g_autofree gchar* program_log = get_program_log(priv->program);
313 g_warning("Failed to link program: %s", program_log);
314 }
315
316 glDeleteShader(vertex_shader);
317 glDeleteShader(fragment_shader);
318 }
319
320 void fl_renderer_render(FlRenderer* self, int width, int height) {
321 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
322 fl_renderer_get_instance_private(self));
323
324 g_return_if_fail(FL_IS_RENDERER(self));
325
326 // Save bindings that are set by this function. All bindings must be restored
327 // to their original values because Skia expects that its bindings have not
328 // been altered.
329 GLint saved_texture_binding;
330 glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
331 GLint saved_vao_binding;
332 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
333 GLint saved_array_buffer_binding;
334 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
335
336 glClearColor(0.0, 0.0, 0.0, 1.0);
337 glClear(GL_COLOR_BUFFER_BIT);
338
339 glUseProgram(priv->program);
340
341 for (guint i = 0; i < priv->textures->len; i++) {
342 FlBackingStoreProvider* texture =
343 FL_BACKING_STORE_PROVIDER(g_ptr_array_index(priv->textures, i));
344
345 uint32_t texture_id = fl_backing_store_provider_get_gl_texture_id(texture);
346 glBindTexture(GL_TEXTURE_2D, texture_id);
347
348 // Translate into OpenGL co-ordinates
349 GdkRectangle texture_geometry =
350 fl_backing_store_provider_get_geometry(texture);
351 GLfloat texture_x = texture_geometry.x;
352 GLfloat texture_y = texture_geometry.y;
353 GLfloat texture_width = texture_geometry.width;
354 GLfloat texture_height = texture_geometry.height;
355 GLfloat x0 = pixels_to_gl_coords(texture_x, width);
356 GLfloat y0 =
357 pixels_to_gl_coords(height - (texture_y + texture_height), height);
358 GLfloat x1 = pixels_to_gl_coords(texture_x + texture_width, width);
359 GLfloat y1 = pixels_to_gl_coords(height - texture_y, height);
360 GLfloat vertex_data[] = {x0, y0, 0, 0, x1, y1, 1, 1, x0, y1, 0, 1,
361 x0, y0, 0, 0, x1, y0, 1, 0, x1, y1, 1, 1};
362
363 GLuint vao, vertex_buffer;
364 glGenVertexArrays(1, &vao);
365 glBindVertexArray(vao);
366 glGenBuffers(1, &vertex_buffer);
367 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
368 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
369 GL_STATIC_DRAW);
370 GLint position_index = glGetAttribLocation(priv->program, "position");
371 glEnableVertexAttribArray(position_index);
372 glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE,
373 sizeof(GLfloat) * 4, 0);
374 GLint texcoord_index = glGetAttribLocation(priv->program, "in_texcoord");
375 glEnableVertexAttribArray(texcoord_index);
376 glVertexAttribPointer(texcoord_index, 2, GL_FLOAT, GL_FALSE,
377 sizeof(GLfloat) * 4, (void*)(sizeof(GLfloat) * 2));
378
379 glDrawArrays(GL_TRIANGLES, 0, 6);
380
381 glDeleteVertexArrays(1, &vao);
382 glDeleteBuffers(1, &vertex_buffer);
383 }
384
385 glFlush();
386
387 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
388 glBindVertexArray(saved_vao_binding);
389 glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
390 }
391
392 void fl_renderer_cleanup(FlRenderer* self) {
393 FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
394 fl_renderer_get_instance_private(self));
395
396 g_return_if_fail(FL_IS_RENDERER(self));
397
398 glDeleteProgram(priv->program);
399 }
fl_renderer_wait_for_frame
void fl_renderer_wait_for_frame(FlRenderer *self, int target_width, int target_height)
Definition: fl_renderer.cc:211
fl_renderer_error_quark
GQuark fl_renderer_error_quark(void) G_GNUC_CONST
G_DEFINE_TYPE_WITH_PRIVATE
G_DEFINE_TYPE_WITH_PRIVATE(FlTextInputPlugin, fl_text_input_plugin, G_TYPE_OBJECT) static gboolean finish_method(GObject *object
fl_renderer_init
static void fl_renderer_init(FlRenderer *self)
Definition: fl_renderer.cc:123
fl_backing_store_provider_get_gl_format
uint32_t fl_backing_store_provider_get_gl_format(FlBackingStoreProvider *self)
Definition: fl_backing_store_provider.cc:80
fl_renderer_get_refresh_rate
gdouble fl_renderer_get_refresh_rate(FlRenderer *self)
Definition: fl_renderer.cc:160
vertex_shader_src
static const char * vertex_shader_src
Definition: fl_renderer.cc:16
i
int i
Definition: fl_socket_accessible.cc:18
priv
FlPixelBufferTexturePrivate * priv
Definition: fl_pixel_buffer_texture.cc:30
FlRendererPrivate::target_width
int target_width
Definition: fl_renderer.cc:45
FlRendererPrivate::textures
GPtrArray * textures
Definition: fl_renderer.cc:59
fl_backing_store_provider_new
FlBackingStoreProvider * fl_backing_store_provider_new(int width, int height)
Definition: fl_backing_store_provider.cc:35
height
G_BEGIN_DECLS int height
Definition: fl_backing_store_provider.h:37
fl_renderer_clear_current
void fl_renderer_clear_current(FlRenderer *self)
Definition: fl_renderer.cc:155
fl_renderer_get_proc_address
void * fl_renderer_get_proc_address(FlRenderer *self, const char *name)
Definition: fl_renderer.cc:139
fl_view_private.h
fl_renderer_start
gboolean fl_renderer_start(FlRenderer *self, FlView *view)
Definition: fl_renderer.cc:129
FlRendererPrivate::blocking_main_thread
bool blocking_main_thread
Definition: fl_renderer.cc:49
G_DEFINE_QUARK
G_DEFINE_QUARK(fl_binary_messenger_codec_error_quark, fl_binary_messenger_codec_error) G_DECLARE_FINAL_TYPE(FlBinaryMessengerImpl
fl_renderer_class_init
static void fl_renderer_class_init(FlRendererClass *klass)
Definition: fl_renderer.cc:119
fl_backing_store_provider_get_gl_texture_id
uint32_t fl_backing_store_provider_get_gl_texture_id(FlBackingStoreProvider *self)
Definition: fl_backing_store_provider.cc:71
fragment_shader_src
static const char * fragment_shader_src
Definition: fl_renderer.cc:27
fl_renderer_collect_backing_store
gboolean fl_renderer_collect_backing_store(FlRenderer *self, const FlutterBackingStore *backing_store)
Definition: fl_renderer.cc:201
fl_renderer_dispose
static void fl_renderer_dispose(GObject *object)
Definition: fl_renderer.cc:107
fl_renderer_present_layers
gboolean fl_renderer_present_layers(FlRenderer *self, const FlutterLayer **layers, size_t layers_count)
Definition: fl_renderer.cc:230
FlRendererPrivate::view
FlView * view
Definition: fl_renderer.cc:42
fl_engine_private.h
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_view_get_engine
G_MODULE_EXPORT FlEngine * fl_view_get_engine(FlView *self)
Definition: fl_view.cc:842
fl_renderer_create_backing_store
gboolean fl_renderer_create_backing_store(FlRenderer *renderer, const FlutterBackingStoreConfig *config, FlutterBackingStore *backing_store_out)
Definition: fl_renderer.cc:172
fl_renderer.h
fl_renderer_make_resource_current
void fl_renderer_make_resource_current(FlRenderer *self)
Definition: fl_renderer.cc:150
fl_view_redraw
void fl_view_redraw(FlView *self)
Definition: fl_view.cc:847
get_shader_log
static gchar * get_shader_log(GLuint shader)
Definition: fl_renderer.cc:65
fl_renderer_unblock_main_thread
static void fl_renderer_unblock_main_thread(FlRenderer *self)
Definition: fl_renderer.cc:95
fl_task_runner_release_main_thread
void fl_task_runner_release_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:197
fl_backing_store_provider_get_geometry
GdkRectangle fl_backing_store_provider_get_geometry(FlBackingStoreProvider *self)
Definition: fl_backing_store_provider.cc:105
fl_renderer_cleanup
void fl_renderer_cleanup(FlRenderer *self)
Definition: fl_renderer.cc:392
get_program_log
static gchar * get_program_log(GLuint program)
Definition: fl_renderer.cc:78
fl_renderer_make_current
void fl_renderer_make_current(FlRenderer *self)
Definition: fl_renderer.cc:145
fl_engine_get_task_runner
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
Definition: fl_engine.cc:924
FlRendererPrivate::target_height
int target_height
Definition: fl_renderer.cc:46
fl_renderer_render
void fl_renderer_render(FlRenderer *self, int width, int height)
Definition: fl_renderer.cc:320
fl_backing_store_provider.h
pixels_to_gl_coords
static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels)
Converts a pixel co-ordinate from 0..pixels to OpenGL -1..1.
Definition: fl_renderer.cc:91
texture_id
int64_t texture_id
Definition: texture_registrar_unittests.cc:24
width
const uint8_t uint32_t * width
Definition: fl_pixel_buffer_texture_test.cc:38
FlRendererPrivate
Definition: fl_renderer.cc:41
FlRendererPrivate::had_first_frame
bool had_first_frame
Definition: fl_renderer.cc:53
format
uint32_t uint32_t * format
Definition: fl_texture_registrar_test.cc:41
fl_renderer_get_fbo
guint32 fl_renderer_get_fbo(FlRenderer *self)
Definition: fl_renderer.cc:165
fl_task_runner_block_main_thread
void fl_task_runner_block_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:176
FlRendererPrivate::program
GLuint program
Definition: fl_renderer.cc:56
fl_backing_store_provider_get_gl_framebuffer_id
uint32_t fl_backing_store_provider_get_gl_framebuffer_id(FlBackingStoreProvider *self)
Definition: fl_backing_store_provider.cc:66
fl_renderer_setup
void fl_renderer_setup(FlRenderer *self)
Definition: fl_renderer.cc:278