Flutter Linux Embedder
fl_compositor_opengl.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_compositor_opengl.h"
6 
7 #include <epoxy/egl.h>
8 #include <epoxy/gl.h>
9 
10 #include "flutter/common/constants.h"
11 #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  "#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 
40  FlCompositor parent_instance;
41 
42  // Engine we are rendering.
43  GWeakRef engine;
44 
45  // OpenGL contexts.
46  FlOpenGLManager* opengl_manager;
47 
48  // Flag to track lazy initialization.
49  gboolean initialized;
50 
51  // The pixel format passed to the engine.
52  GLint sized_format;
53 
54  // The format used to create textures.
56 
57  // target dimension for resizing
60 
61  // whether the renderer waits for frame render
63 
64  // true if frame was completed; resizing is not synchronized until first frame
65  // was rendered
67 
68  // True if we can use glBlitFramebuffer.
70 
71  // Shader program.
72  GLuint program;
73 
74  // Framebuffers to render keyed by view ID.
76 
77  // Mutex used when blocking the raster thread until a task is completed on
78  // platform thread.
79  GMutex present_mutex;
80 
81  // Condition to unblock the raster thread after task is completed on platform
82  // thread.
84 };
85 
86 G_DEFINE_TYPE(FlCompositorOpenGL,
87  fl_compositor_opengl,
88  fl_compositor_get_type())
89 
90 // Check if running on an NVIDIA driver.
91 static gboolean is_nvidia() {
92  const gchar* vendor = reinterpret_cast<const gchar*>(glGetString(GL_VENDOR));
93  return strstr(vendor, "NVIDIA") != nullptr;
94 }
95 
96 // Check if running on an Vivante Corporation driver.
97 static gboolean is_vivante() {
98  const gchar* vendor = reinterpret_cast<const gchar*>(glGetString(GL_VENDOR));
99  return strstr(vendor, "Vivante Corporation") != nullptr;
100 }
101 
102 // Returns the log for the given OpenGL shader. Must be freed by the caller.
103 static gchar* get_shader_log(GLuint shader) {
104  GLint log_length;
105  gchar* log;
106 
107  glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
108 
109  log = static_cast<gchar*>(g_malloc(log_length + 1));
110  glGetShaderInfoLog(shader, log_length, nullptr, log);
111 
112  return log;
113 }
114 
115 // Returns the log for the given OpenGL program. Must be freed by the caller.
116 static gchar* get_program_log(GLuint program) {
117  GLint log_length;
118  gchar* log;
119 
120  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
121 
122  log = static_cast<gchar*>(g_malloc(log_length + 1));
123  glGetProgramInfoLog(program, log_length, nullptr, log);
124 
125  return log;
126 }
127 
128 /// Converts a pixel co-ordinate from 0..pixels to OpenGL -1..1.
129 static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels) {
130  return (2.0 * position / pixels) - 1.0;
131 }
132 
133 // Perform single run OpenGL initialization.
134 static void initialize(FlCompositorOpenGL* self) {
135  if (self->initialized) {
136  return;
137  }
138  self->initialized = TRUE;
139 
140  if (epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
141  self->sized_format = GL_BGRA8_EXT;
142  self->general_format = GL_BGRA_EXT;
143  } else {
144  self->sized_format = GL_RGBA8;
145  self->general_format = GL_RGBA;
146  }
147 }
148 
149 static void fl_compositor_opengl_unblock_main_thread(FlCompositorOpenGL* self) {
150  if (self->blocking_main_thread) {
151  self->blocking_main_thread = false;
152 
153  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
154  if (engine != nullptr) {
156  }
157  }
158 }
159 
160 static void setup_shader(FlCompositorOpenGL* self) {
161  GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
162  glShaderSource(vertex_shader, 1, &vertex_shader_src, nullptr);
163  glCompileShader(vertex_shader);
164  GLint vertex_compile_status;
165  glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
166  if (vertex_compile_status == GL_FALSE) {
167  g_autofree gchar* shader_log = get_shader_log(vertex_shader);
168  g_warning("Failed to compile vertex shader: %s", shader_log);
169  }
170 
171  GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
172  glShaderSource(fragment_shader, 1, &fragment_shader_src, nullptr);
173  glCompileShader(fragment_shader);
174  GLint fragment_compile_status;
175  glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
176  if (fragment_compile_status == GL_FALSE) {
177  g_autofree gchar* shader_log = get_shader_log(fragment_shader);
178  g_warning("Failed to compile fragment shader: %s", shader_log);
179  }
180 
181  self->program = glCreateProgram();
182  glAttachShader(self->program, vertex_shader);
183  glAttachShader(self->program, fragment_shader);
184  glLinkProgram(self->program);
185 
186  GLint link_status;
187  glGetProgramiv(self->program, GL_LINK_STATUS, &link_status);
188  if (link_status == GL_FALSE) {
189  g_autofree gchar* program_log = get_program_log(self->program);
190  g_warning("Failed to link program: %s", program_log);
191  }
192 
193  glDeleteShader(vertex_shader);
194  glDeleteShader(fragment_shader);
195 }
196 
197 static void render_with_blit(FlCompositorOpenGL* self,
198  GPtrArray* framebuffers) {
199  // Disable the scissor test as it can affect blit operations.
200  // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
201  // See OpenGL specification version 4.6, section 18.3.1.
202  glDisable(GL_SCISSOR_TEST);
203 
204  for (guint i = 0; i < framebuffers->len; i++) {
205  FlFramebuffer* framebuffer =
206  FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, i));
207 
208  GLuint framebuffer_id = fl_framebuffer_get_id(framebuffer);
209  glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_id);
210  size_t width = fl_framebuffer_get_width(framebuffer);
211  size_t height = fl_framebuffer_get_height(framebuffer);
212  glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
213  GL_COLOR_BUFFER_BIT, GL_NEAREST);
214  }
215  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
216 }
217 
218 static void render_with_textures(FlCompositorOpenGL* self,
219  GPtrArray* framebuffers,
220  int width,
221  int height) {
222  // Save bindings that are set by this function. All bindings must be restored
223  // to their original values because Skia expects that its bindings have not
224  // been altered.
225  GLint saved_texture_binding;
226  glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
227  GLint saved_vao_binding;
228  glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
229  GLint saved_array_buffer_binding;
230  glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
231 
232  glEnable(GL_BLEND);
233  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
234 
235  glUseProgram(self->program);
236 
237  for (guint i = 0; i < framebuffers->len; i++) {
238  FlFramebuffer* framebuffer =
239  FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, i));
240 
241  GLuint texture_id = fl_framebuffer_get_texture_id(framebuffer);
242  glBindTexture(GL_TEXTURE_2D, texture_id);
243 
244  // Translate into OpenGL co-ordinates
245  size_t texture_width = fl_framebuffer_get_width(framebuffer);
246  size_t texture_height = fl_framebuffer_get_height(framebuffer);
247  GLfloat x0 = pixels_to_gl_coords(0, width);
248  GLfloat y0 = pixels_to_gl_coords(height - texture_height, height);
249  GLfloat x1 = pixels_to_gl_coords(texture_width, width);
250  GLfloat y1 = pixels_to_gl_coords(height, height);
251  GLfloat vertex_data[] = {x0, y0, 0, 0, x1, y1, 1, 1, x0, y1, 0, 1,
252  x0, y0, 0, 0, x1, y0, 1, 0, x1, y1, 1, 1};
253 
254  GLuint vao, vertex_buffer;
255  glGenVertexArrays(1, &vao);
256  glBindVertexArray(vao);
257  glGenBuffers(1, &vertex_buffer);
258  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
259  glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
260  GL_STATIC_DRAW);
261  GLint position_index = glGetAttribLocation(self->program, "position");
262  glEnableVertexAttribArray(position_index);
263  glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE,
264  sizeof(GLfloat) * 4, 0);
265  GLint texcoord_index = glGetAttribLocation(self->program, "in_texcoord");
266  glEnableVertexAttribArray(texcoord_index);
267  glVertexAttribPointer(texcoord_index, 2, GL_FLOAT, GL_FALSE,
268  sizeof(GLfloat) * 4,
269  reinterpret_cast<void*>(sizeof(GLfloat) * 2));
270 
271  glDrawArrays(GL_TRIANGLES, 0, 6);
272 
273  glDeleteVertexArrays(1, &vao);
274  glDeleteBuffers(1, &vertex_buffer);
275  }
276 
277  glDisable(GL_BLEND);
278 
279  glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
280  glBindVertexArray(saved_vao_binding);
281  glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
282 }
283 
284 static void render(FlCompositorOpenGL* self,
285  GPtrArray* framebuffers,
286  int width,
287  int height) {
288  if (self->has_gl_framebuffer_blit) {
289  render_with_blit(self, framebuffers);
290  } else {
291  render_with_textures(self, framebuffers, width, height);
292  }
293 }
294 
295 static gboolean present_layers(FlCompositorOpenGL* self,
296  FlutterViewId view_id,
297  const FlutterLayer** layers,
298  size_t layers_count) {
299  g_return_val_if_fail(FL_IS_COMPOSITOR_OPENGL(self), FALSE);
300 
301  // ignore incoming frame with wrong dimensions in trivial case with just one
302  // layer
303  if (self->blocking_main_thread && layers_count == 1 &&
304  layers[0]->offset.x == 0 && layers[0]->offset.y == 0 &&
305  (layers[0]->size.width != self->target_width ||
306  layers[0]->size.height != self->target_height)) {
307  return TRUE;
308  }
309 
310  self->had_first_frame = true;
311 
313 
314  g_autoptr(GPtrArray) framebuffers =
315  g_ptr_array_new_with_free_func(g_object_unref);
316  for (size_t i = 0; i < layers_count; ++i) {
317  const FlutterLayer* layer = layers[i];
318  switch (layer->type) {
319  case kFlutterLayerContentTypeBackingStore: {
320  const FlutterBackingStore* backing_store = layer->backing_store;
321  FlFramebuffer* framebuffer =
322  FL_FRAMEBUFFER(backing_store->open_gl.framebuffer.user_data);
323  g_ptr_array_add(framebuffers, g_object_ref(framebuffer));
324  } break;
325  case kFlutterLayerContentTypePlatformView: {
326  // TODO(robert-ancell) Not implemented -
327  // https://github.com/flutter/flutter/issues/41724
328  } break;
329  }
330  }
331 
332  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
333  if (engine == nullptr) {
334  return TRUE;
335  }
336  g_autoptr(FlRenderable) renderable =
338  if (renderable == nullptr) {
339  return TRUE;
340  }
341 
342  if (view_id == flutter::kFlutterImplicitViewId) {
343  // Store for rendering later
344  g_hash_table_insert(self->framebuffers_by_view_id, GINT_TO_POINTER(view_id),
345  g_ptr_array_ref(framebuffers));
346  } else {
347  // Composite into a single framebuffer.
348  if (framebuffers->len > 1) {
349  size_t width = 0, height = 0;
350 
351  for (guint i = 0; i < framebuffers->len; i++) {
352  FlFramebuffer* framebuffer =
353  FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, i));
354 
355  size_t w = fl_framebuffer_get_width(framebuffer);
356  size_t h = fl_framebuffer_get_height(framebuffer);
357  if (w > width) {
358  width = w;
359  }
360  if (h > height) {
361  height = h;
362  }
363  }
364 
365  FlFramebuffer* view_framebuffer =
366  fl_framebuffer_new(self->general_format, width, height);
367  glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
368  fl_framebuffer_get_id(view_framebuffer));
369  render(self, framebuffers, width, height);
370  g_ptr_array_set_size(framebuffers, 0);
371  g_ptr_array_add(framebuffers, view_framebuffer);
372  }
373 
374  // Read back pixel values.
375  FlFramebuffer* framebuffer =
376  FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, 0));
377  size_t width = fl_framebuffer_get_width(framebuffer);
378  size_t height = fl_framebuffer_get_height(framebuffer);
379  size_t data_length = width * height * 4;
380  g_autofree uint8_t* data = static_cast<uint8_t*>(malloc(data_length));
381  glBindFramebuffer(GL_READ_FRAMEBUFFER, fl_framebuffer_get_id(framebuffer));
382  glReadPixels(0, 0, width, height, self->general_format, GL_UNSIGNED_BYTE,
383  data);
384 
385  // Write into a texture in the views context.
386  fl_renderable_make_current(renderable);
387  FlFramebuffer* view_framebuffer =
388  fl_framebuffer_new(self->general_format, width, height);
389  glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
390  fl_framebuffer_get_id(view_framebuffer));
391  glBindTexture(GL_TEXTURE_2D,
392  fl_framebuffer_get_texture_id(view_framebuffer));
393  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
394  GL_UNSIGNED_BYTE, data);
395 
396  g_autoptr(GPtrArray) secondary_framebuffers =
397  g_ptr_array_new_with_free_func(g_object_unref);
398  g_ptr_array_add(secondary_framebuffers, g_object_ref(view_framebuffer));
399  g_hash_table_insert(self->framebuffers_by_view_id, GINT_TO_POINTER(view_id),
400  g_ptr_array_ref(secondary_framebuffers));
401  }
402 
403  fl_renderable_redraw(renderable);
404 
405  return TRUE;
406 }
407 
408 typedef struct {
409  FlCompositorOpenGL* self;
410 
411  FlutterViewId view_id;
412 
413  const FlutterLayer** layers;
414  size_t layers_count;
415 
416  gboolean result;
417 
418  gboolean finished;
420 
421 // Perform the present on the main thread.
422 static void present_layers_task_cb(gpointer user_data) {
423  PresentLayersData* data = static_cast<PresentLayersData*>(user_data);
424  FlCompositorOpenGL* self = data->self;
425 
426  // Perform the present.
427  fl_opengl_manager_make_current(self->opengl_manager);
428  data->result =
429  present_layers(self, data->view_id, data->layers, data->layers_count);
430  fl_opengl_manager_clear_current(self->opengl_manager);
431 
432  // Complete fl_compositor_opengl_present_layers().
433  g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
434  data->finished = TRUE;
435  g_cond_signal(&self->present_condition);
436 }
437 
439  FlCompositor* compositor,
440  const FlutterBackingStoreConfig* config,
441  FlutterBackingStore* backing_store_out) {
442  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
443 
444  fl_opengl_manager_make_current(self->opengl_manager);
445 
446  initialize(self);
447 
448  FlFramebuffer* framebuffer = fl_framebuffer_new(
449  self->general_format, config->size.width, config->size.height);
450  if (!framebuffer) {
451  g_warning("Failed to create backing store");
452  return FALSE;
453  }
454 
455  backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
456  backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
457  backing_store_out->open_gl.framebuffer.user_data = framebuffer;
458  backing_store_out->open_gl.framebuffer.name =
459  fl_framebuffer_get_id(framebuffer);
460  backing_store_out->open_gl.framebuffer.target = self->sized_format;
461  backing_store_out->open_gl.framebuffer.destruction_callback = [](void* p) {
462  // Backing store destroyed in fl_compositor_opengl_collect_backing_store(),
463  // set on FlutterCompositor.collect_backing_store_callback during engine
464  // start.
465  };
466 
467  return TRUE;
468 }
469 
471  FlCompositor* compositor,
472  const FlutterBackingStore* backing_store) {
473  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
474 
475  fl_opengl_manager_make_current(self->opengl_manager);
476 
477  // OpenGL context is required when destroying #FlFramebuffer.
478  g_object_unref(backing_store->open_gl.framebuffer.user_data);
479  return TRUE;
480 }
481 
482 static void fl_compositor_opengl_wait_for_frame(FlCompositor* compositor,
483  int target_width,
484  int target_height) {
485  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
486 
487  self->target_width = target_width;
488  self->target_height = target_height;
489 
490  if (self->had_first_frame && !self->blocking_main_thread) {
491  self->blocking_main_thread = true;
492  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
493  if (engine != nullptr) {
495  }
496  }
497 }
498 
499 static gboolean fl_compositor_opengl_present_layers(FlCompositor* compositor,
500  FlutterViewId view_id,
501  const FlutterLayer** layers,
502  size_t layers_count) {
503  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
504 
505  // Detach the context from raster thread. Needed because blitting
506  // will be done on the main thread, which will make the context current.
507  fl_opengl_manager_clear_current(self->opengl_manager);
508 
509  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
510 
511  // Schedule the present to run on the main thread.
512  FlTaskRunner* task_runner = fl_engine_get_task_runner(engine);
513  PresentLayersData data = {
514  .self = self,
515  .view_id = view_id,
516  .layers = layers,
517  .layers_count = layers_count,
518  .result = FALSE,
519  .finished = FALSE,
520  };
522 
523  // Block until present completes.
524  g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
525  while (!data.finished) {
526  g_cond_wait(&self->present_condition, &self->present_mutex);
527  }
528 
529  // Restore the context to the raster thread in case the engine needs it
530  // to do some cleanup.
531  fl_opengl_manager_make_current(self->opengl_manager);
532 
533  return data.result;
534 }
535 
536 static void fl_compositor_opengl_dispose(GObject* object) {
537  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(object);
538 
540 
541  g_weak_ref_clear(&self->engine);
542  g_clear_object(&self->opengl_manager);
543  g_clear_pointer(&self->framebuffers_by_view_id, g_hash_table_unref);
544  g_mutex_clear(&self->present_mutex);
545  g_cond_clear(&self->present_condition);
546 
547  G_OBJECT_CLASS(fl_compositor_opengl_parent_class)->dispose(object);
548 }
549 
550 static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass* klass) {
551  FL_COMPOSITOR_CLASS(klass)->create_backing_store =
553  FL_COMPOSITOR_CLASS(klass)->collect_backing_store =
555  FL_COMPOSITOR_CLASS(klass)->wait_for_frame =
557  FL_COMPOSITOR_CLASS(klass)->present_layers =
559 
560  G_OBJECT_CLASS(klass)->dispose = fl_compositor_opengl_dispose;
561 }
562 
563 static void fl_compositor_opengl_init(FlCompositorOpenGL* self) {
564  self->framebuffers_by_view_id = g_hash_table_new_full(
565  g_direct_hash, g_direct_equal, nullptr,
566  reinterpret_cast<GDestroyNotify>(g_ptr_array_unref));
567  g_mutex_init(&self->present_mutex);
568  g_cond_init(&self->present_condition);
569 }
570 
571 FlCompositorOpenGL* fl_compositor_opengl_new(FlEngine* engine) {
572  FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(
573  g_object_new(fl_compositor_opengl_get_type(), nullptr));
574 
575  g_weak_ref_init(&self->engine, engine);
576  self->opengl_manager =
577  FL_OPENGL_MANAGER(g_object_ref(fl_engine_get_opengl_manager(engine)));
578 
579  return self;
580 }
581 
582 void fl_compositor_opengl_setup(FlCompositorOpenGL* self) {
583  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(self));
584 
585  // Note: NVIDIA and Vivante are temporarily disabled due to
586  // https://github.com/flutter/flutter/issues/152099
587  self->has_gl_framebuffer_blit =
588  !is_nvidia() && !is_vivante() &&
589  (epoxy_gl_version() >= 30 ||
590  epoxy_has_gl_extension("GL_EXT_framebuffer_blit"));
591 
592  if (!self->has_gl_framebuffer_blit) {
593  setup_shader(self);
594  }
595 }
596 
597 void fl_compositor_opengl_render(FlCompositorOpenGL* self,
598  FlutterViewId view_id,
599  int width,
600  int height,
601  const GdkRGBA* background_color) {
602  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(self));
603 
604  glClearColor(background_color->red, background_color->green,
605  background_color->blue, background_color->alpha);
606  glClear(GL_COLOR_BUFFER_BIT);
607 
608  GPtrArray* framebuffers = reinterpret_cast<GPtrArray*>((g_hash_table_lookup(
609  self->framebuffers_by_view_id, GINT_TO_POINTER(view_id))));
610  if (framebuffers != nullptr) {
611  render(self, framebuffers, width, height);
612  }
613 
614  glFlush();
615 }
616 
617 void fl_compositor_opengl_cleanup(FlCompositorOpenGL* self) {
618  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(self));
619 
620  if (self->program != 0) {
621  glDeleteProgram(self->program);
622  }
623 }
static void fl_compositor_opengl_dispose(GObject *object)
static void fl_compositor_opengl_wait_for_frame(FlCompositor *compositor, int target_width, int target_height)
static void render_with_textures(FlCompositorOpenGL *self, GPtrArray *framebuffers, int width, int height)
void fl_compositor_opengl_setup(FlCompositorOpenGL *self)
static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels)
Converts a pixel co-ordinate from 0..pixels to OpenGL -1..1.
static gchar * get_shader_log(GLuint shader)
static gboolean fl_compositor_opengl_create_backing_store(FlCompositor *compositor, const FlutterBackingStoreConfig *config, FlutterBackingStore *backing_store_out)
static void fl_compositor_opengl_unblock_main_thread(FlCompositorOpenGL *self)
G_DEFINE_TYPE(FlCompositorOpenGL, fl_compositor_opengl, fl_compositor_get_type()) static gboolean is_nvidia()
static const char * fragment_shader_src
static gboolean present_layers(FlCompositorOpenGL *self, FlutterViewId view_id, const FlutterLayer **layers, size_t layers_count)
static void fl_compositor_opengl_init(FlCompositorOpenGL *self)
static gchar * get_program_log(GLuint program)
static void setup_shader(FlCompositorOpenGL *self)
static void render(FlCompositorOpenGL *self, GPtrArray *framebuffers, int width, int height)
static gboolean is_vivante()
static void present_layers_task_cb(gpointer user_data)
static void render_with_blit(FlCompositorOpenGL *self, GPtrArray *framebuffers)
FlCompositorOpenGL * fl_compositor_opengl_new(FlEngine *engine)
static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass *klass)
void fl_compositor_opengl_render(FlCompositorOpenGL *self, FlutterViewId view_id, int width, int height, const GdkRGBA *background_color)
void fl_compositor_opengl_cleanup(FlCompositorOpenGL *self)
static gboolean fl_compositor_opengl_present_layers(FlCompositor *compositor, FlutterViewId view_id, const FlutterLayer **layers, size_t layers_count)
static const char * vertex_shader_src
static gboolean fl_compositor_opengl_collect_backing_store(FlCompositor *compositor, const FlutterBackingStore *backing_store)
static void initialize(FlCompositorOpenGL *self)
FlOpenGLManager * fl_engine_get_opengl_manager(FlEngine *self)
Definition: fl_engine.cc:603
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
Definition: fl_engine.cc:1287
FlRenderable * fl_engine_get_renderable(FlEngine *self, FlutterViewId view_id)
Definition: fl_engine.cc:806
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
size_t fl_framebuffer_get_height(FlFramebuffer *self)
GLuint fl_framebuffer_get_id(FlFramebuffer *self)
size_t fl_framebuffer_get_width(FlFramebuffer *self)
GLuint fl_framebuffer_get_texture_id(FlFramebuffer *self)
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height)
void fl_opengl_manager_clear_current(FlOpenGLManager *self)
void fl_opengl_manager_make_current(FlOpenGLManager *self)
const uint8_t uint32_t uint32_t * height
const uint8_t uint32_t * width
void fl_renderable_make_current(FlRenderable *self)
void fl_renderable_redraw(FlRenderable *self)
void fl_task_runner_post_callback(FlTaskRunner *self, void(*callback)(gpointer data), gpointer data)
void fl_task_runner_release_main_thread(FlTaskRunner *self)
void fl_task_runner_block_main_thread(FlTaskRunner *self)
G_BEGIN_DECLS FlutterViewId view_id
FlOpenGLManager * opengl_manager
GHashTable * framebuffers_by_view_id
FlCompositorOpenGL * self
const FlutterLayer ** layers
int64_t texture_id