| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/shell/platform/linux/fl_renderer_gl.h" |
| |
| #include "flutter/shell/platform/linux/fl_backing_store_provider.h" |
| #include "flutter/shell/platform/linux/fl_view_private.h" |
| |
| struct _FlRendererGL { |
| FlRenderer parent_instance; |
| }; |
| |
| G_DEFINE_TYPE(FlRendererGL, fl_renderer_gl, fl_renderer_get_type()) |
| |
| // Implements FlRenderer::create_contexts. |
| static gboolean fl_renderer_gl_create_contexts(FlRenderer* renderer, |
| GtkWidget* widget, |
| GdkGLContext** visible, |
| GdkGLContext** resource, |
| GError** error) { |
| GdkWindow* window = gtk_widget_get_parent_window(widget); |
| |
| *visible = gdk_window_create_gl_context(window, error); |
| |
| if (*error != nullptr) { |
| return FALSE; |
| } |
| |
| *resource = gdk_window_create_gl_context(window, error); |
| |
| if (*error != nullptr) { |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| // Implements FlRenderer::create_backing_store. |
| static gboolean fl_renderer_gl_create_backing_store( |
| FlRenderer* renderer, |
| const FlutterBackingStoreConfig* config, |
| FlutterBackingStore* backing_store_out) { |
| g_autoptr(GError) error = nullptr; |
| gboolean result = fl_renderer_make_current(renderer, &error); |
| if (!result) { |
| g_warning("Failed to make renderer current when creating backing store: %s", |
| error->message); |
| return FALSE; |
| } |
| |
| FlBackingStoreProvider* provider = |
| fl_backing_store_provider_new(config->size.width, config->size.height); |
| if (!provider) { |
| g_warning("Failed to create backing store"); |
| return FALSE; |
| } |
| |
| uint32_t name = fl_backing_store_provider_get_gl_framebuffer_id(provider); |
| uint32_t format = fl_backing_store_provider_get_gl_format(provider); |
| |
| backing_store_out->type = kFlutterBackingStoreTypeOpenGL; |
| backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; |
| backing_store_out->open_gl.framebuffer.user_data = provider; |
| backing_store_out->open_gl.framebuffer.name = name; |
| backing_store_out->open_gl.framebuffer.target = format; |
| backing_store_out->open_gl.framebuffer.destruction_callback = [](void* p) { |
| // Backing store destroyed in fl_renderer_gl_collect_backing_store(), set |
| // on FlutterCompositor.collect_backing_store_callback during engine start. |
| }; |
| |
| return TRUE; |
| } |
| |
| // Implements FlRenderer::collect_backing_store. |
| static gboolean fl_renderer_gl_collect_backing_store( |
| FlRenderer* renderer, |
| const FlutterBackingStore* backing_store) { |
| g_autoptr(GError) error = nullptr; |
| gboolean result = fl_renderer_make_current(renderer, &error); |
| if (!result) { |
| g_warning( |
| "Failed to make renderer current when collecting backing store: %s", |
| error->message); |
| return FALSE; |
| } |
| |
| // OpenGL context is required when destroying #FlBackingStoreProvider. |
| g_object_unref(backing_store->open_gl.framebuffer.user_data); |
| return TRUE; |
| } |
| |
| // Implements FlRenderer::present_layers. |
| static gboolean fl_renderer_gl_present_layers(FlRenderer* renderer, |
| const FlutterLayer** layers, |
| size_t layers_count) { |
| FlView* view = fl_renderer_get_view(renderer); |
| GdkGLContext* context = fl_renderer_get_context(renderer); |
| if (!view || !context) { |
| return FALSE; |
| } |
| |
| g_autoptr(GPtrArray) textures = g_ptr_array_new(); |
| for (size_t i = 0; i < layers_count; ++i) { |
| const FlutterLayer* layer = layers[i]; |
| switch (layer->type) { |
| case kFlutterLayerContentTypeBackingStore: { |
| const FlutterBackingStore* backing_store = layer->backing_store; |
| auto framebuffer = &backing_store->open_gl.framebuffer; |
| g_ptr_array_add(textures, reinterpret_cast<FlBackingStoreProvider*>( |
| framebuffer->user_data)); |
| } break; |
| case kFlutterLayerContentTypePlatformView: { |
| // Currently unsupported. |
| } break; |
| } |
| } |
| |
| fl_view_set_textures(view, context, textures); |
| |
| return TRUE; |
| } |
| |
| static void fl_renderer_gl_class_init(FlRendererGLClass* klass) { |
| FL_RENDERER_CLASS(klass)->create_contexts = fl_renderer_gl_create_contexts; |
| FL_RENDERER_CLASS(klass)->create_backing_store = |
| fl_renderer_gl_create_backing_store; |
| FL_RENDERER_CLASS(klass)->collect_backing_store = |
| fl_renderer_gl_collect_backing_store; |
| FL_RENDERER_CLASS(klass)->present_layers = fl_renderer_gl_present_layers; |
| } |
| |
| static void fl_renderer_gl_init(FlRendererGL* self) {} |
| |
| FlRendererGL* fl_renderer_gl_new() { |
| return FL_RENDERER_GL(g_object_new(fl_renderer_gl_get_type(), nullptr)); |
| } |