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"
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  "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 
35 G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error)
36 
37 typedef 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 
58 G_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.
61 static 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.
74 static 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.
87 static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels) {
88  return (2.0 * position / pixels) - 1.0;
89 }
90 
91 static 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 
103 static 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 
115 static void fl_renderer_class_init(FlRendererClass* klass) {
116  G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose;
117 }
118 
119 static 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 
125 gboolean 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 
135 void* 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 
141 void fl_renderer_make_current(FlRenderer* self) {
142  g_return_if_fail(FL_IS_RENDERER(self));
143  FL_RENDERER_GET_CLASS(self)->make_current(self);
144 }
145 
146 void fl_renderer_make_resource_current(FlRenderer* self) {
147  g_return_if_fail(FL_IS_RENDERER(self));
148  FL_RENDERER_GET_CLASS(self)->make_resource_current(self);
149 }
150 
151 void fl_renderer_clear_current(FlRenderer* self) {
152  g_return_if_fail(FL_IS_RENDERER(self));
153  FL_RENDERER_GET_CLASS(self)->clear_current(self);
154 }
155 
156 gdouble 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 
161 guint32 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) {
172  fl_renderer_make_current(renderer);
173 
174  FlBackingStoreProvider* provider =
175  fl_backing_store_provider_new(config->size.width, config->size.height);
176  if (!provider) {
177  g_warning("Failed to create backing store");
178  return FALSE;
179  }
180 
181  uint32_t name = fl_backing_store_provider_get_gl_framebuffer_id(provider);
182  uint32_t format = fl_backing_store_provider_get_gl_format(provider);
183 
184  backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
185  backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
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 
207 void fl_renderer_wait_for_frame(FlRenderer* self,
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 
226 gboolean 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) {
255  case kFlutterLayerContentTypeBackingStore: {
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;
262  case kFlutterLayerContentTypePlatformView: {
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 
274 void 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 
316 void 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 
388 void 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 }
fl_renderer_wait_for_frame
void fl_renderer_wait_for_frame(FlRenderer *self, int target_width, int target_height)
Definition: fl_renderer.cc:207
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:119
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:156
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:41
FlRendererPrivate::textures
GPtrArray * textures
Definition: fl_renderer.cc:55
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:151
fl_renderer_get_proc_address
void * fl_renderer_get_proc_address(FlRenderer *self, const char *name)
Definition: fl_renderer.cc:135
fl_view_private.h
fl_renderer_start
gboolean fl_renderer_start(FlRenderer *self, FlView *view)
Definition: fl_renderer.cc:125
FlRendererPrivate::blocking_main_thread
bool blocking_main_thread
Definition: fl_renderer.cc:45
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:115
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:197
fl_renderer_dispose
static void fl_renderer_dispose(GObject *object)
Definition: fl_renderer.cc:103
fl_renderer_present_layers
gboolean fl_renderer_present_layers(FlRenderer *self, const FlutterLayer **layers, size_t layers_count)
Definition: fl_renderer.cc:226
FlRendererPrivate::view
FlView * view
Definition: fl_renderer.cc:38
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:835
fl_renderer_create_backing_store
gboolean fl_renderer_create_backing_store(FlRenderer *renderer, const FlutterBackingStoreConfig *config, FlutterBackingStore *backing_store_out)
Definition: fl_renderer.cc:168
fl_renderer.h
fl_renderer_make_resource_current
void fl_renderer_make_resource_current(FlRenderer *self)
Definition: fl_renderer.cc:146
fl_view_redraw
void fl_view_redraw(FlView *self)
Definition: fl_view.cc:840
get_shader_log
static gchar * get_shader_log(GLuint shader)
Definition: fl_renderer.cc:61
fl_renderer_unblock_main_thread
static void fl_renderer_unblock_main_thread(FlRenderer *self)
Definition: fl_renderer.cc:91
fl_task_runner_release_main_thread
void fl_task_runner_release_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:205
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:388
get_program_log
static gchar * get_program_log(GLuint program)
Definition: fl_renderer.cc:74
fl_renderer_make_current
void fl_renderer_make_current(FlRenderer *self)
Definition: fl_renderer.cc:141
fl_engine_get_task_runner
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
Definition: fl_engine.cc:921
FlRendererPrivate::target_height
int target_height
Definition: fl_renderer.cc:42
fl_renderer_render
void fl_renderer_render(FlRenderer *self, int width, int height)
Definition: fl_renderer.cc:316
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:87
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:37
FlRendererPrivate::had_first_frame
bool had_first_frame
Definition: fl_renderer.cc:49
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:161
fl_task_runner_block_main_thread
void fl_task_runner_block_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:184
FlRendererPrivate::program
GLuint program
Definition: fl_renderer.cc:52
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:274