10 #include "flutter/common/constants.h"
11 #include "flutter/shell/platform/embedder/embedder.h"
17 "attribute vec2 position;\n"
18 "attribute vec2 in_texcoord;\n"
19 "varying vec2 texcoord;\n"
22 " gl_Position = vec4(position, 0, 1);\n"
23 " texcoord = in_texcoord;\n"
29 "precision mediump float;\n"
32 "uniform sampler2D texture;\n"
33 "varying vec2 texcoord;\n"
36 " gl_FragColor = texture2D(texture, texcoord);\n"
88 fl_compositor_get_type())
91 static gboolean is_nvidia() {
92 const gchar* vendor =
reinterpret_cast<const gchar*
>(glGetString(GL_VENDOR));
93 return strstr(vendor,
"NVIDIA") !=
nullptr;
98 const gchar* vendor =
reinterpret_cast<const gchar*
>(glGetString(GL_VENDOR));
99 return strstr(vendor,
"Vivante Corporation") !=
nullptr;
107 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
109 log =
static_cast<gchar*
>(g_malloc(log_length + 1));
110 glGetShaderInfoLog(shader, log_length,
nullptr, log);
120 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
122 log =
static_cast<gchar*
>(g_malloc(log_length + 1));
123 glGetProgramInfoLog(program, log_length,
nullptr, log);
130 return (2.0 * position / pixels) - 1.0;
135 if (self->initialized) {
138 self->initialized =
TRUE;
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;
144 self->sized_format = GL_RGBA8;
145 self->general_format = GL_RGBA;
150 if (self->blocking_main_thread) {
151 self->blocking_main_thread =
false;
153 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
154 if (engine !=
nullptr) {
161 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
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) {
168 g_warning(
"Failed to compile vertex shader: %s", shader_log);
171 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
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) {
178 g_warning(
"Failed to compile fragment shader: %s", shader_log);
181 self->program = glCreateProgram();
182 glAttachShader(self->program, vertex_shader);
183 glAttachShader(self->program, fragment_shader);
184 glLinkProgram(self->program);
187 glGetProgramiv(self->program, GL_LINK_STATUS, &link_status);
188 if (link_status == GL_FALSE) {
190 g_warning(
"Failed to link program: %s", program_log);
193 glDeleteShader(vertex_shader);
194 glDeleteShader(fragment_shader);
198 GPtrArray* framebuffers) {
202 glDisable(GL_SCISSOR_TEST);
204 for (guint
i = 0;
i < framebuffers->len;
i++) {
205 FlFramebuffer* framebuffer =
206 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
209 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_id);
213 GL_COLOR_BUFFER_BIT, GL_NEAREST);
215 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
219 GPtrArray* framebuffers,
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);
233 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
235 glUseProgram(self->program);
237 for (guint
i = 0;
i < framebuffers->len;
i++) {
238 FlFramebuffer* framebuffer =
239 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
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};
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,
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,
269 reinterpret_cast<void*
>(
sizeof(GLfloat) * 2));
271 glDrawArrays(GL_TRIANGLES, 0, 6);
273 glDeleteVertexArrays(1, &vao);
274 glDeleteBuffers(1, &vertex_buffer);
279 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
280 glBindVertexArray(saved_vao_binding);
281 glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
284 static void render(FlCompositorOpenGL*
self,
285 GPtrArray* framebuffers,
288 if (self->has_gl_framebuffer_blit) {
297 const FlutterLayer** layers,
298 size_t layers_count) {
299 g_return_val_if_fail(FL_IS_COMPOSITOR_OPENGL(
self), FALSE);
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)) {
310 self->had_first_frame =
true;
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));
325 case kFlutterLayerContentTypePlatformView: {
332 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
333 if (engine ==
nullptr) {
336 g_autoptr(FlRenderable) renderable =
338 if (renderable ==
nullptr) {
342 if (
view_id == flutter::kFlutterImplicitViewId) {
344 g_hash_table_insert(self->framebuffers_by_view_id, GINT_TO_POINTER(
view_id),
345 g_ptr_array_ref(framebuffers));
348 if (framebuffers->len > 1) {
351 for (guint
i = 0;
i < framebuffers->len;
i++) {
352 FlFramebuffer* framebuffer =
353 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
365 FlFramebuffer* view_framebuffer =
367 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
370 g_ptr_array_set_size(framebuffers, 0);
371 g_ptr_array_add(framebuffers, view_framebuffer);
375 FlFramebuffer* framebuffer =
376 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, 0));
380 g_autofree uint8_t* data =
static_cast<uint8_t*
>(malloc(data_length));
382 glReadPixels(0, 0,
width,
height, self->general_format, GL_UNSIGNED_BYTE,
387 FlFramebuffer* view_framebuffer =
389 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
391 glBindTexture(GL_TEXTURE_2D,
393 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width,
height, 0, GL_RGBA,
394 GL_UNSIGNED_BYTE, data);
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));
409 FlCompositorOpenGL*
self;
424 FlCompositorOpenGL*
self = data->
self;
433 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
435 g_cond_signal(&self->present_condition);
439 FlCompositor* compositor,
440 const FlutterBackingStoreConfig* config,
441 FlutterBackingStore* backing_store_out) {
442 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
449 self->general_format, config->size.width, config->size.height);
451 g_warning(
"Failed to create backing store");
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 =
460 backing_store_out->open_gl.framebuffer.target =
self->sized_format;
461 backing_store_out->open_gl.framebuffer.destruction_callback = [](
void* p) {
471 FlCompositor* compositor,
472 const FlutterBackingStore* backing_store) {
473 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
478 g_object_unref(backing_store->open_gl.framebuffer.user_data);
485 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
487 self->target_width = target_width;
488 self->target_height = target_height;
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) {
501 const FlutterLayer** layers,
502 size_t layers_count) {
503 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
509 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
517 .layers_count = layers_count,
524 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
526 g_cond_wait(&self->present_condition, &self->present_mutex);
537 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(
object);
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);
547 G_OBJECT_CLASS(fl_compositor_opengl_parent_class)->dispose(
object);
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 =
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);
572 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(
573 g_object_new(fl_compositor_opengl_get_type(),
nullptr));
575 g_weak_ref_init(&self->engine, engine);
576 self->opengl_manager =
583 g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(
self));
587 self->has_gl_framebuffer_blit =
589 (epoxy_gl_version() >= 30 ||
590 epoxy_has_gl_extension(
"GL_EXT_framebuffer_blit"));
592 if (!self->has_gl_framebuffer_blit) {
601 const GdkRGBA* background_color) {
602 g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(
self));
604 glClearColor(background_color->red, background_color->green,
605 background_color->blue, background_color->alpha);
606 glClear(GL_COLOR_BUFFER_BIT);
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) {
618 g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(
self));
620 if (self->program != 0) {
621 glDeleteProgram(self->program);
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)
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
FlRenderable * fl_engine_get_renderable(FlEngine *self, FlutterViewId view_id)
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
bool has_gl_framebuffer_blit
FlCompositor parent_instance
bool blocking_main_thread
FlOpenGLManager * opengl_manager
GHashTable * framebuffers_by_view_id
FlCompositorOpenGL * self
const FlutterLayer ** layers