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