| Flutter Linux Embedder |

Classes | Functions | Variables
fl_compositor_opengl.cc File Reference
`#include "fl_compositor_opengl.h"`
`#include <epoxy/egl.h>`
`#include <epoxy/gl.h>`
`#include "flutter/common/constants.h"`
`#include "flutter/shell/platform/embedder/embedder.h"`
`#include "flutter/shell/platform/linux/fl_engine_private.h"`
`#include "flutter/shell/platform/linux/fl_framebuffer.h"`

Go to the source code of this file.

## Classes
struct | _FlCompositorOpenGL

## Functions
| G_DEFINE_TYPE (FlCompositorOpenGL, fl_compositor_opengl, fl_compositor_get_type()) static gchar *get_shader_log(GLuint shader)
static gchar * | get_program_log (GLuint program)
static void | setup_shader (FlCompositorOpenGL *self)
static void | cleanup_shader (FlCompositorOpenGL *self)
static void | composite_layer (FlCompositorOpenGL *self, FlFramebuffer *framebuffer, double x, double y, int width, int height)
static gboolean | fl_compositor_opengl_present_layers (FlCompositor *compositor, const FlutterLayer **layers, size_t layers_count)
static gboolean | fl_compositor_opengl_render (FlCompositor *compositor, cairo_t *cr, GdkWindow *window)
static void | fl_compositor_opengl_dispose (GObject *object)
static void | fl_compositor_opengl_class_init (FlCompositorOpenGLClass *klass)
static void | fl_compositor_opengl_init (FlCompositorOpenGL *self)
FlCompositorOpenGL * | fl_compositor_opengl_new (FlTaskRunner *task_runner, FlOpenGLManager *opengl_manager, gboolean shareable)

## Variables
static const char * | vertex_shader_src
static const char * | fragment_shader_src

## Function Documentation

## ◆ cleanup_shader()

static void cleanup_shader | ( | FlCompositorOpenGL * | self | ) |
| static

Definition at line 171 of file fl_compositor_opengl.cc.

171 {
172 if (!fl_opengl_manager_make_current(self->opengl_manager)) {
173 g_warning(
174 "Failed to cleanup compositor shaders, unable to make OpenGL context "
175 "current");
176 return;
177 }
178
179 if (self->program != 0) {
180 glDeleteProgram(self->program);
181 }
182 if (self->vertex_buffer != 0) {
183 glDeleteBuffers(1, &self->vertex_buffer);
184 }
185 }
fl_opengl_manager_make_current
gboolean fl_opengl_manager_make_current(FlOpenGLManager *self)
Definition: fl_opengl_manager.cc:76

References fl_opengl_manager_make_current().

Referenced by fl_compositor_opengl_dispose().

## ◆ composite_layer()

static void composite_layer | ( | FlCompositorOpenGL * | self,
|  | FlFramebuffer * | framebuffer,
|  | double | x,
|  | double | y,
|  | int | width,
|  | int | height
| ) |  |
| static

Definition at line 187 of file fl_compositor_opengl.cc.

192 {
193 size_t texture_width = fl_framebuffer_get_width(framebuffer);
194 size_t texture_height = fl_framebuffer_get_height(framebuffer);
195 glUniform2f(self->offset_location, (2 * x / width) - 1.0,
196 (2 * y / width) - 1.0);
197 glUniform2f(self->scale_location, texture_width / width,
198 texture_height / height);
199
200 GLuint texture_id = fl_framebuffer_get_texture_id(framebuffer);
201 glBindTexture(GL_TEXTURE_2D, texture_id);
202
203 glDrawArrays(GL_TRIANGLES, 0, 6);
204 }
height
self height
Definition: fl_compositor_software.cc:43
width
self width
Definition: fl_compositor_software.cc:42
fl_framebuffer_get_height
size_t fl_framebuffer_get_height(FlFramebuffer *self)
Definition: fl_framebuffer.cc:160
fl_framebuffer_get_width
size_t fl_framebuffer_get_width(FlFramebuffer *self)
Definition: fl_framebuffer.cc:156
fl_framebuffer_get_texture_id
GLuint fl_framebuffer_get_texture_id(FlFramebuffer *self)
Definition: fl_framebuffer.cc:152
texture_id
int64_t texture_id
Definition: texture_registrar_unittests.cc:24

References fl_framebuffer_get_height(), fl_framebuffer_get_texture_id(), fl_framebuffer_get_width(), height, texture_id, and width.

Referenced by fl_compositor_opengl_present_layers().

## ◆ fl_compositor_opengl_class_init()

static void fl_compositor_opengl_class_init | ( | FlCompositorOpenGLClass * | klass | ) |
| static

Definition at line 403 of file fl_compositor_opengl.cc.

403 {
404 FL_COMPOSITOR_CLASS(klass)->present_layers =
405 fl_compositor_opengl_present_layers;
406 FL_COMPOSITOR_CLASS(klass)->render = fl_compositor_opengl_render;
407
408 G_OBJECT_CLASS(klass)->dispose = fl_compositor_opengl_dispose;
409 }
fl_compositor_opengl_dispose
static void fl_compositor_opengl_dispose(GObject *object)
Definition: fl_compositor_opengl.cc:389
fl_compositor_opengl_present_layers
static gboolean fl_compositor_opengl_present_layers(FlCompositor *compositor, const FlutterLayer **layers, size_t layers_count)
Definition: fl_compositor_opengl.cc:206
fl_compositor_opengl_render
static gboolean fl_compositor_opengl_render(FlCompositor *compositor, cairo_t *cr, GdkWindow *window)
Definition: fl_compositor_opengl.cc:337

References fl_compositor_opengl_dispose(), fl_compositor_opengl_present_layers(), and fl_compositor_opengl_render().

## ◆ fl_compositor_opengl_dispose()

static void fl_compositor_opengl_dispose | ( | GObject * | object | ) |
| static

Definition at line 389 of file fl_compositor_opengl.cc.

389 {
390 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(object);
391
392 cleanup_shader(self);
393
394 g_clear_object(&self->task_runner);
395 g_clear_object(&self->opengl_manager);
396 g_clear_object(&self->framebuffer);
397 g_clear_pointer(&self->pixels, g_free);
398 g_mutex_clear(&self->frame_mutex);
399
400 G_OBJECT_CLASS(fl_compositor_opengl_parent_class)->dispose(object);
401 }
cleanup_shader
static void cleanup_shader(FlCompositorOpenGL *self)
Definition: fl_compositor_opengl.cc:171

References cleanup_shader().

Referenced by fl_compositor_opengl_class_init().

## ◆ fl_compositor_opengl_init()

static void fl_compositor_opengl_init | ( | FlCompositorOpenGL * | self | ) |
| static

Definition at line 411 of file fl_compositor_opengl.cc.

411 {
412 g_mutex_init(&self->frame_mutex);
413 }

## ◆ fl_compositor_opengl_new()

FlCompositorOpenGL* fl_compositor_opengl_new | ( | FlTaskRunner * | task_runner,
|  | FlOpenGLManager * | opengl_manager,
|  | gboolean | shareable
| ) |  |

Definition at line 415 of file fl_compositor_opengl.cc.

417 {
418 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(
419 g_object_new(fl_compositor_opengl_get_type(), nullptr));
420
421 self->task_runner = FL_TASK_RUNNER(g_object_ref(task_runner));
422 self->shareable = shareable;
423 self->opengl_manager = FL_OPENGL_MANAGER(g_object_ref(opengl_manager));
424
425 setup_shader(self);
426
427 return self;
428 }
setup_shader
static void setup_shader(FlCompositorOpenGL *self)
Definition: fl_compositor_opengl.cc:112
shareable
G_BEGIN_DECLS FlOpenGLManager gboolean shareable
Definition: fl_compositor_opengl.h:43
opengl_manager
G_BEGIN_DECLS FlOpenGLManager * opengl_manager
Definition: fl_compositor_opengl.h:42

References opengl_manager, setup_shader(), and shareable.

Referenced by setup_opengl(), and TEST().

## ◆ fl_compositor_opengl_present_layers()

static gboolean fl_compositor_opengl_present_layers | ( | FlCompositor * | compositor,
|  | const FlutterLayer ** | layers,
|  | size_t | layers_count
| ) |  |
| static

Definition at line 206 of file fl_compositor_opengl.cc.

208 {
209 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
210
211 g_mutex_lock(&self->frame_mutex);
212 if (layers_count == 0) {
213 g_mutex_unlock(&self->frame_mutex);
214 return TRUE;
215 }
216
217 GLint general_format = GL_RGBA;
218 if (epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
219 general_format = GL_BGRA_EXT;
220 }
221
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 GLint saved_framebuffer_binding;
232 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &saved_framebuffer_binding);
233
234 // Update framebuffer to write into.
235 size_t width = layers[0]->size.width;
236 size_t height = layers[0]->size.height;
237 if (self->framebuffer == nullptr ||
238 fl_framebuffer_get_width(self->framebuffer) != width ||
239 fl_framebuffer_get_height(self->framebuffer) != height) {
240 g_clear_object(&self->framebuffer);
241 self->framebuffer =
242 fl_framebuffer_new(general_format, width, height, self->shareable);
243
244 // If not shareable make buffer to copy frame pixels into.
245 if (!self->shareable) {
246 size_t data_length = width * height * 4;
247 self->pixels = static_cast<uint8_t*>(realloc(self->pixels, data_length));
248 }
249 }
250
251 self->had_first_frame = true;
252
253 // FIXME(robert-ancell): The vertex array is the same for all views, but
254 // cannot be shared in OpenGL. Find a way to not generate this every time.
255 GLuint vao;
256 glGenVertexArrays(1, &vao);
257 glBindVertexArray(vao);
258 glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
259 GLint position_location = glGetAttribLocation(self->program, "position");
260 glEnableVertexAttribArray(position_location);
261 glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE,
262 sizeof(GLfloat) * 4, 0);
263 GLint texcoord_location = glGetAttribLocation(self->program, "in_texcoord");
264 glEnableVertexAttribArray(texcoord_location);
265 glVertexAttribPointer(texcoord_location, 2, GL_FLOAT, GL_FALSE,
266 sizeof(GLfloat) * 4,
267 reinterpret_cast<void*>(sizeof(GLfloat) * 2));
268
269 glEnable(GL_BLEND);
270 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
271
272 glUseProgram(self->program);
273
274 // Disable the scissor test as it can affect blit operations.
275 // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
276 // See OpenGL specification version 4.6, section 18.3.1.
277 glDisable(GL_SCISSOR_TEST);
278
279 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
280 fl_framebuffer_get_id(self->framebuffer));
281 gboolean first_layer = TRUE;
282 for (size_t i = 0; i < layers_count; ++i) {
283 const FlutterLayer* layer = layers[i];
284 switch (layer->type) {
285 case kFlutterLayerContentTypeBackingStore: {
286 const FlutterBackingStore* backing_store = layer->backing_store;
287 FlFramebuffer* framebuffer =
288 FL_FRAMEBUFFER(backing_store->open_gl.framebuffer.user_data);
289 glBindFramebuffer(GL_READ_FRAMEBUFFER,
290 fl_framebuffer_get_id(framebuffer));
291 // The first layer can be blitted, and following layers composited with
292 // this.
293 if (first_layer) {
294 glBlitFramebuffer(layer->offset.x, layer->offset.y, layer->size.width,
295 layer->size.height, layer->offset.x,
296 layer->offset.y, layer->size.width,
297 layer->size.height, GL_COLOR_BUFFER_BIT,
298 GL_NEAREST);
299 first_layer = FALSE;
300 } else {
301 composite_layer(self, framebuffer, layer->offset.x, layer->offset.y,
302 width, height);
303 }
304 } break;
305 case kFlutterLayerContentTypePlatformView: {
306 // TODO(robert-ancell) Not implemented -
307 // https://github.com/flutter/flutter/issues/41724
308 } break;
309 }
310 }
311 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
312 glFlush();
313
314 glDeleteVertexArrays(1, &vao);
315
316 glDisable(GL_BLEND);
317
318 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
319 glBindVertexArray(saved_vao_binding);
320 glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
321 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_framebuffer_binding);
322
323 if (!self->shareable) {
324 glBindFramebuffer(GL_READ_FRAMEBUFFER,
325 fl_framebuffer_get_id(self->framebuffer));
326 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, self->pixels);
327 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
328 }
329
330 g_mutex_unlock(&self->frame_mutex);
331
332 fl_task_runner_stop_wait(self->task_runner);
333
334 return TRUE;
335 }
composite_layer
static void composite_layer(FlCompositorOpenGL *self, FlFramebuffer *framebuffer, double x, double y, int width, int height)
Definition: fl_compositor_opengl.cc:187
layers_count
const FlutterLayer size_t layers_count
Definition: fl_compositor_software.cc:33
layers
const FlutterLayer ** layers
Definition: fl_compositor_software.cc:32
TRUE
return TRUE
Definition: fl_compositor_software.cc:68
fl_task_runner_stop_wait
fl_task_runner_stop_wait(self->task_runner)
fl_framebuffer_get_id
GLuint fl_framebuffer_get_id(FlFramebuffer *self)
Definition: fl_framebuffer.cc:148
fl_framebuffer_new
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height, gboolean shareable)
Definition: fl_framebuffer.cc:69
i
int i
Definition: fl_socket_accessible.cc:18

References composite_layer(), fl_framebuffer_get_height(), fl_framebuffer_get_id(), fl_framebuffer_get_width(), fl_framebuffer_new(), fl_task_runner_stop_wait(), height, i, layers, layers_count, TRUE, and width.

Referenced by fl_compositor_opengl_class_init().

## ◆ fl_compositor_opengl_render()

static gboolean fl_compositor_opengl_render | ( | FlCompositor * | compositor,
|  | cairo_t * | cr,
|  | GdkWindow * | window
| ) |  |
| static

Definition at line 337 of file fl_compositor_opengl.cc.

339 {
340 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor);
341
342 g_mutex_lock(&self->frame_mutex);
343 if (self->framebuffer == nullptr) {
344 g_mutex_unlock(&self->frame_mutex);
345 return FALSE;
346 }
347
348 // If frame not ready, then wait for it.
349 gint scale_factor = gdk_window_get_scale_factor(window);
350 size_t width = gdk_window_get_width(window) * scale_factor;
351 size_t height = gdk_window_get_height(window) * scale_factor;
352 while (fl_framebuffer_get_width(self->framebuffer) != width ||
353 fl_framebuffer_get_height(self->framebuffer) != height) {
354 g_mutex_unlock(&self->frame_mutex);
355 fl_task_runner_wait(self->task_runner);
356 g_mutex_lock(&self->frame_mutex);
357 }
358
359 if (fl_framebuffer_get_shareable(self->framebuffer)) {
360 g_autoptr(FlFramebuffer) sibling =
361 fl_framebuffer_create_sibling(self->framebuffer);
362 gdk_cairo_draw_from_gl(cr, window, fl_framebuffer_get_texture_id(sibling),
363 GL_TEXTURE, scale_factor, 0, 0, width, height);
364 } else {
365 GLint saved_texture_binding;
366 glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
367
368 GLuint texture_id;
369 glGenTextures(1, &texture_id);
370 glBindTexture(GL_TEXTURE_2D, texture_id);
371 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
372 GL_UNSIGNED_BYTE, self->pixels);
373
374 gdk_cairo_draw_from_gl(cr, window, texture_id, GL_TEXTURE, scale_factor, 0,
375 0, width, height);
376
377 glDeleteTextures(1, &texture_id);
378
379 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
380 }
381
382 glFlush();
383
384 g_mutex_unlock(&self->frame_mutex);
385
386 return TRUE;
387 }
window
return window
Definition: fl_application.cc:41
g_autoptr
g_autoptr(GMutexLocker) locker
fl_framebuffer_get_shareable
gboolean fl_framebuffer_get_shareable(FlFramebuffer *self)
Definition: fl_framebuffer.cc:115
fl_framebuffer_create_sibling
FlFramebuffer * fl_framebuffer_create_sibling(FlFramebuffer *self)
Definition: fl_framebuffer.cc:120
fl_task_runner_wait
void fl_task_runner_wait(FlTaskRunner *self)
Definition: fl_task_runner.cc:172

References fl_framebuffer_create_sibling(), fl_framebuffer_get_height(), fl_framebuffer_get_shareable(), fl_framebuffer_get_texture_id(), fl_framebuffer_get_width(), fl_task_runner_wait(), g_autoptr(), height, texture_id, TRUE, width, and window.

Referenced by fl_compositor_opengl_class_init().

## ◆ G_DEFINE_TYPE()

G_DEFINE_TYPE | ( | FlCompositorOpenGL | ,
|  | fl_compositor_opengl | ,
|  | fl_compositor_get_type() |
| ) |  |

Definition at line 82 of file fl_compositor_opengl.cc.

87 {
88 GLint log_length;
89 gchar* log;
90
91 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
92
93 log = static_cast<gchar*>(g_malloc(log_length + 1));
94 glGetShaderInfoLog(shader, log_length, nullptr, log);
95
96 return log;
97 }

## ◆ get_program_log()

static gchar* get_program_log | ( | GLuint | program | ) |
| static

Definition at line 100 of file fl_compositor_opengl.cc.

100 {
101 GLint log_length;
102 gchar* log;
103
104 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
105
106 log = static_cast<gchar*>(g_malloc(log_length + 1));
107 glGetProgramInfoLog(program, log_length, nullptr, log);
108
109 return log;
110 }

Referenced by setup_shader().

## ◆ setup_shader()

static void setup_shader | ( | FlCompositorOpenGL * | self | ) |
| static

Definition at line 112 of file fl_compositor_opengl.cc.

112 {
113 if (!fl_opengl_manager_make_current(self->opengl_manager)) {
114 g_warning(
115 "Failed to setup compositor shaders, unable to make OpenGL context "
116 "current");
117 return;
118 }
119
120 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
121 glShaderSource(vertex_shader, 1, &vertex_shader_src, nullptr);
122 glCompileShader(vertex_shader);
123 GLint vertex_compile_status;
124 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
125 if (vertex_compile_status == GL_FALSE) {
126 g_autofree gchar* shader_log = get_shader_log(vertex_shader);
127 g_warning("Failed to compile vertex shader: %s", shader_log);
128 }
129
130 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
131 glShaderSource(fragment_shader, 1, &fragment_shader_src, nullptr);
132 glCompileShader(fragment_shader);
133 GLint fragment_compile_status;
134 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
135 if (fragment_compile_status == GL_FALSE) {
136 g_autofree gchar* shader_log = get_shader_log(fragment_shader);
137 g_warning("Failed to compile fragment shader: %s", shader_log);
138 }
139
140 self->program = glCreateProgram();
141 glAttachShader(self->program, vertex_shader);
142 glAttachShader(self->program, fragment_shader);
143 glLinkProgram(self->program);
144
145 GLint link_status;
146 glGetProgramiv(self->program, GL_LINK_STATUS, &link_status);
147 if (link_status == GL_FALSE) {
148 g_autofree gchar* program_log = get_program_log(self->program);
149 g_warning("Failed to link program: %s", program_log);
150 }
151
152 self->offset_location = glGetUniformLocation(self->program, "offset");
153 self->scale_location = glGetUniformLocation(self->program, "scale");
154
155 glDeleteShader(vertex_shader);
156 glDeleteShader(fragment_shader);
157
158 // The uniform square abcd in two triangles cba + cdb
159 // a--b
160 // | |
161 // c--d
162 GLfloat vertex_data[] = {-1, -1, 0, 0, 1, 1, 1, 1, -1, 1, 0, 1,
163 -1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1};
164
165 glGenBuffers(1, &self->vertex_buffer);
166 glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
167 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
168 GL_STATIC_DRAW);
169 }
fragment_shader_src
static const char * fragment_shader_src
Definition: fl_compositor_opengl.cc:29
get_program_log
static gchar * get_program_log(GLuint program)
Definition: fl_compositor_opengl.cc:100
vertex_shader_src
static const char * vertex_shader_src
Definition: fl_compositor_opengl.cc:16

References fl_opengl_manager_make_current(), fragment_shader_src, get_program_log(), and vertex_shader_src.

Referenced by fl_compositor_opengl_new().

## Variable Documentation

## ◆ fragment_shader_src

const char* fragment_shader_src
| static

Initial value:
=
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"\n"
"uniform sampler2D texture;\n"
"varying vec2 texcoord;\n"
"\n"
"void main() {\n"
" gl_FragColor = texture2D(texture, texcoord);\n"
"}\n"

Definition at line 29 of file fl_compositor_opengl.cc.

Referenced by setup_shader().

## ◆ vertex_shader_src

const char* vertex_shader_src
| static

Initial value:
=
"attribute vec2 position;\n"
"attribute vec2 in_texcoord;\n"
"uniform vec2 offset;\n"
"uniform vec2 scale;\n"
"varying vec2 texcoord;\n"
"\n"
"void main() {\n"
" gl_Position = vec4(offset + position * scale, 0, 1);\n"
" texcoord = in_texcoord;\n"
"}\n"

Definition at line 16 of file fl_compositor_opengl.cc.

Referenced by setup_shader().