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 "uniform vec2 offset;\n"
20 "uniform vec2 scale;\n"
21 "varying vec2 texcoord;\n"
24 " gl_Position = vec4(offset + position * scale, 0, 1);\n"
25 " texcoord = in_texcoord;\n"
31 "precision mediump float;\n"
34 "uniform sampler2D texture;\n"
35 "varying vec2 texcoord;\n"
38 " gl_FragColor = texture2D(texture, texcoord);\n"
93 fl_compositor_get_type())
96 static gboolean driver_supports_blit() {
97 const gchar* vendor =
reinterpret_cast<const gchar*
>(glGetString(GL_VENDOR));
101 const char* unsupported_vendors_exact[] = {
"Vivante Corporation",
"ARM"};
102 const char* unsupported_vendors_fuzzy[] = {
"NVIDIA"};
104 for (
const char* unsupported : unsupported_vendors_fuzzy) {
105 if (strstr(vendor, unsupported) !=
nullptr) {
109 for (
const char* unsupported : unsupported_vendors_exact) {
110 if (strcmp(vendor, unsupported) == 0) {
122 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
124 log =
static_cast<gchar*
>(g_malloc(log_length + 1));
125 glGetShaderInfoLog(shader, log_length,
nullptr, log);
135 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
137 log =
static_cast<gchar*
>(g_malloc(log_length + 1));
138 glGetProgramInfoLog(program, log_length,
nullptr, log);
144 if (self->blocking_main_thread) {
145 self->blocking_main_thread =
false;
147 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
148 if (engine !=
nullptr) {
155 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
157 glCompileShader(vertex_shader);
158 GLint vertex_compile_status;
159 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
160 if (vertex_compile_status == GL_FALSE) {
162 g_warning(
"Failed to compile vertex shader: %s", shader_log);
165 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
167 glCompileShader(fragment_shader);
168 GLint fragment_compile_status;
169 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
170 if (fragment_compile_status == GL_FALSE) {
172 g_warning(
"Failed to compile fragment shader: %s", shader_log);
175 self->program = glCreateProgram();
176 glAttachShader(self->program, vertex_shader);
177 glAttachShader(self->program, fragment_shader);
178 glLinkProgram(self->program);
181 glGetProgramiv(self->program, GL_LINK_STATUS, &link_status);
182 if (link_status == GL_FALSE) {
184 g_warning(
"Failed to link program: %s", program_log);
187 self->offset_location = glGetUniformLocation(self->program,
"offset");
188 self->scale_location = glGetUniformLocation(self->program,
"scale");
190 glDeleteShader(vertex_shader);
191 glDeleteShader(fragment_shader);
197 GLfloat vertex_data[] = {-1, -1, 0, 0, 1, 1, 1, 1, -1, 1, 0, 1,
198 -1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1};
200 glGenBuffers(1, &self->vertex_buffer);
201 glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
202 glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_data), vertex_data,
207 GPtrArray* framebuffers) {
211 glDisable(GL_SCISSOR_TEST);
213 for (guint
i = 0;
i < framebuffers->len;
i++) {
214 FlFramebuffer* framebuffer =
215 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
218 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_id);
222 GL_COLOR_BUFFER_BIT, GL_NEAREST);
224 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
228 GPtrArray* framebuffers,
234 GLint saved_texture_binding;
235 glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
236 GLint saved_vao_binding;
237 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
238 GLint saved_array_buffer_binding;
239 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
244 glGenVertexArrays(1, &vao);
245 glBindVertexArray(vao);
246 glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
247 GLint position_location = glGetAttribLocation(self->program,
"position");
248 glEnableVertexAttribArray(position_location);
249 glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE,
250 sizeof(GLfloat) * 4, 0);
251 GLint texcoord_location = glGetAttribLocation(self->program,
"in_texcoord");
252 glEnableVertexAttribArray(texcoord_location);
253 glVertexAttribPointer(texcoord_location, 2, GL_FLOAT, GL_FALSE,
255 reinterpret_cast<void*
>(
sizeof(GLfloat) * 2));
258 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
260 glUseProgram(self->program);
262 for (guint
i = 0;
i < framebuffers->len;
i++) {
263 FlFramebuffer* framebuffer =
264 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
270 glUniform2f(self->offset_location, 0, 0);
271 glUniform2f(self->scale_location, texture_width /
width,
277 glDrawArrays(GL_TRIANGLES, 0, 6);
280 glDeleteVertexArrays(1, &vao);
284 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
285 glBindVertexArray(saved_vao_binding);
286 glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
289 static void render(FlCompositorOpenGL*
self,
290 GPtrArray* framebuffers,
293 if (self->has_gl_framebuffer_blit) {
301 const FlutterLayer** layers,
302 size_t layers_count) {
303 g_return_val_if_fail(FL_IS_COMPOSITOR_OPENGL(
self), FALSE);
307 if (self->blocking_main_thread && layers_count == 1 &&
308 layers[0]->offset.x == 0 && layers[0]->offset.y == 0 &&
309 (layers[0]->size.width != self->target_width ||
310 layers[0]->size.height != self->target_height)) {
314 self->had_first_frame =
true;
318 GLint general_format = GL_RGBA;
319 if (epoxy_has_gl_extension(
"GL_EXT_texture_format_BGRA8888")) {
320 general_format = GL_BGRA_EXT;
323 g_autoptr(GPtrArray) framebuffers =
324 g_ptr_array_new_with_free_func(g_object_unref);
325 for (
size_t i = 0;
i < layers_count; ++
i) {
326 const FlutterLayer* layer = layers[
i];
327 switch (layer->type) {
328 case kFlutterLayerContentTypeBackingStore: {
329 const FlutterBackingStore* backing_store = layer->backing_store;
330 FlFramebuffer* framebuffer =
331 FL_FRAMEBUFFER(backing_store->open_gl.framebuffer.user_data);
332 g_ptr_array_add(framebuffers, g_object_ref(framebuffer));
334 case kFlutterLayerContentTypePlatformView: {
341 if (self->context ==
nullptr) {
343 g_ptr_array_unref(self->framebuffers);
344 self->framebuffers = g_ptr_array_ref(framebuffers);
347 if (framebuffers->len > 1) {
350 for (guint
i = 0;
i < framebuffers->len;
i++) {
351 FlFramebuffer* framebuffer =
352 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers,
i));
364 FlFramebuffer* view_framebuffer =
366 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
369 g_ptr_array_set_size(framebuffers, 0);
370 g_ptr_array_add(framebuffers, view_framebuffer);
374 FlFramebuffer* framebuffer =
375 FL_FRAMEBUFFER(g_ptr_array_index(framebuffers, 0));
379 g_autofree uint8_t* data =
static_cast<uint8_t*
>(malloc(data_length));
381 glReadPixels(0, 0,
width,
height, general_format, GL_UNSIGNED_BYTE, data);
384 gdk_gl_context_make_current(self->context);
385 g_autoptr(FlFramebuffer) view_framebuffer =
387 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
389 glBindTexture(GL_TEXTURE_2D,
391 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width,
height, 0, GL_RGBA,
392 GL_UNSIGNED_BYTE, data);
394 g_autoptr(GPtrArray) secondary_framebuffers =
395 g_ptr_array_new_with_free_func(g_object_unref);
396 g_ptr_array_add(secondary_framebuffers, g_object_ref(view_framebuffer));
397 g_ptr_array_unref(self->framebuffers);
398 self->framebuffers = g_ptr_array_ref(secondary_framebuffers);
405 FlCompositorOpenGL*
self;
418 FlCompositorOpenGL*
self = data->
self;
426 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
428 g_cond_signal(&self->present_condition);
432 FlCompositor* compositor) {
439 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
441 self->target_width = target_width;
442 self->target_height = target_height;
444 if (self->had_first_frame && !self->blocking_main_thread) {
445 self->blocking_main_thread =
true;
446 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
447 if (engine !=
nullptr) {
454 const FlutterLayer** layers,
455 size_t layers_count) {
456 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(compositor);
462 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
469 .layers_count = layers_count,
476 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->present_mutex);
478 g_cond_wait(&self->present_condition, &self->present_mutex);
489 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(
object);
493 g_weak_ref_clear(&self->engine);
494 g_clear_object(&self->context);
495 g_clear_object(&self->opengl_manager);
496 g_clear_pointer(&self->framebuffers, g_ptr_array_unref);
497 g_mutex_clear(&self->present_mutex);
498 g_cond_clear(&self->present_condition);
500 G_OBJECT_CLASS(fl_compositor_opengl_parent_class)->dispose(
object);
504 FL_COMPOSITOR_CLASS(klass)->get_renderer_type =
506 FL_COMPOSITOR_CLASS(klass)->wait_for_frame =
508 FL_COMPOSITOR_CLASS(klass)->present_layers =
515 self->framebuffers = g_ptr_array_new();
516 g_mutex_init(&self->present_mutex);
517 g_cond_init(&self->present_condition);
522 FlCompositorOpenGL*
self = FL_COMPOSITOR_OPENGL(
523 g_object_new(fl_compositor_opengl_get_type(),
nullptr));
525 g_weak_ref_init(&self->engine, engine);
527 context !=
nullptr ? GDK_GL_CONTEXT(g_object_ref(
context)) :
nullptr;
528 self->opengl_manager =
533 self->has_gl_framebuffer_blit =
534 driver_supports_blit() &&
535 (epoxy_gl_version() >= 30 ||
536 epoxy_has_gl_extension(
"GL_EXT_framebuffer_blit"));
538 if (!self->has_gl_framebuffer_blit) {
548 g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(
self));
550 glClearColor(0.0, 0.0, 0.0, 0.0);
551 glClear(GL_COLOR_BUFFER_BIT);
559 g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(
self));
561 if (self->program != 0) {
562 glDeleteProgram(self->program);
564 if (self->vertex_buffer != 0) {
565 glDeleteBuffers(1, &self->vertex_buffer);
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)
static gchar * get_shader_log(GLuint shader)
static gboolean present_layers(FlCompositorOpenGL *self, const FlutterLayer **layers, size_t layers_count)
static void fl_compositor_opengl_unblock_main_thread(FlCompositorOpenGL *self)
static gboolean fl_compositor_opengl_present_layers(FlCompositor *compositor, const FlutterLayer **layers, size_t layers_count)
static const char * fragment_shader_src
static void fl_compositor_opengl_init(FlCompositorOpenGL *self)
static gchar * get_program_log(GLuint program)
static void setup_shader(FlCompositorOpenGL *self)
static FlutterRendererType fl_compositor_opengl_get_renderer_type(FlCompositor *compositor)
static void render(FlCompositorOpenGL *self, GPtrArray *framebuffers, int width, int height)
static void present_layers_task_cb(gpointer user_data)
FlCompositorOpenGL * fl_compositor_opengl_new(FlEngine *engine, GdkGLContext *context)
static void render_with_blit(FlCompositorOpenGL *self, GPtrArray *framebuffers)
void fl_compositor_opengl_render(FlCompositorOpenGL *self, int width, int height)
static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass *klass)
G_DEFINE_TYPE(FlCompositorOpenGL, fl_compositor_opengl, fl_compositor_get_type()) static gboolean driver_supports_blit()
void fl_compositor_opengl_cleanup(FlCompositorOpenGL *self)
static const char * vertex_shader_src
G_BEGIN_DECLS GdkGLContext * context
FlOpenGLManager * fl_engine_get_opengl_manager(FlEngine *self)
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
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_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)
bool has_gl_framebuffer_blit
FlCompositor parent_instance
bool blocking_main_thread
FlOpenGLManager * opengl_manager
FlCompositorOpenGL * self
const FlutterLayer ** layers