From 2f71dece69915a3aa1786abcced37fda4d5da25d Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 16 Feb 2024 15:13:52 +1300 Subject: [PATCH 1/9] Add checks for FlRenderer methods --- shell/platform/linux/fl_renderer.cc | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index f32215dd38ecc..61b16230bf103 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -57,9 +57,11 @@ static void fl_renderer_class_init(FlRendererClass* klass) { static void fl_renderer_init(FlRenderer* self) {} gboolean fl_renderer_start(FlRenderer* self, FlView* view, GError** error) { - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + priv->view = view; gboolean result = FL_RENDERER_GET_CLASS(self)->create_contexts( self, GTK_WIDGET(view), &priv->main_context, &priv->resource_context, @@ -77,6 +79,7 @@ gboolean fl_renderer_start(FlRenderer* self, FlView* view, GError** error) { } FlView* fl_renderer_get_view(FlRenderer* self) { + g_return_val_if_fail(FL_IS_RENDERER(self), NULL); FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); return priv->view; @@ -85,16 +88,24 @@ FlView* fl_renderer_get_view(FlRenderer* self) { GdkGLContext* fl_renderer_get_context(FlRenderer* self) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + + g_return_val_if_fail(FL_IS_RENDERER(self), NULL); + return priv->main_context; } void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) { + g_return_val_if_fail(FL_IS_RENDERER(self), NULL); + return reinterpret_cast(eglGetProcAddress(name)); } gboolean fl_renderer_make_current(FlRenderer* self, GError** error) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + if (priv->main_context) { gdk_gl_context_make_current(priv->main_context); } @@ -105,6 +116,9 @@ gboolean fl_renderer_make_current(FlRenderer* self, GError** error) { gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + if (priv->resource_context) { gdk_gl_context_make_current(priv->resource_context); } @@ -113,11 +127,16 @@ gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) { } gboolean fl_renderer_clear_current(FlRenderer* self, GError** error) { + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + gdk_gl_context_clear_current(); + return TRUE; } guint32 fl_renderer_get_fbo(FlRenderer* self) { + g_return_val_if_fail(FL_IS_RENDERER(self), 0); + // There is only one frame buffer object - always return that. return 0; } @@ -126,6 +145,7 @@ gboolean fl_renderer_create_backing_store( FlRenderer* self, const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out) { + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); return FL_RENDERER_GET_CLASS(self)->create_backing_store(self, config, backing_store_out); } @@ -133,6 +153,7 @@ gboolean fl_renderer_create_backing_store( gboolean fl_renderer_collect_backing_store( FlRenderer* self, const FlutterBackingStore* backing_store) { + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); return FL_RENDERER_GET_CLASS(self)->collect_backing_store(self, backing_store); } @@ -143,6 +164,8 @@ void fl_renderer_wait_for_frame(FlRenderer* self, FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + g_return_if_fail(FL_IS_RENDERER(self)); + priv->target_width = target_width; priv->target_height = target_height; @@ -160,6 +183,8 @@ gboolean fl_renderer_present_layers(FlRenderer* self, FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + // ignore incoming frame with wrong dimensions in trivial case with just one // layer if (priv->blocking_main_thread && layers_count == 1 && From 4ad5bb064f18640b67808d6245df6a324bde7242 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 13 Feb 2024 16:32:17 +1300 Subject: [PATCH 2/9] Refactor GL rendering to prepare for GTK4 - Remove FlGLArea - we can just use GtkGLArea directly - Stop using gdk_cairo_draw_from_gl, it's not available in GTK4. - Rename FlRendererGL to FlRendererGdk, this was implying that FlRenderer could be something other than OpenGL which is not the case currently. - Remove unnecessary virtual methods in FlRenderer, just implement them as standard methods. --- ci/licenses_golden/licenses_flutter | 8 +- shell/platform/linux/BUILD.gn | 8 +- shell/platform/linux/fl_engine.cc | 24 +- shell/platform/linux/fl_gl_area.cc | 136 -------- shell/platform/linux/fl_gl_area.h | 44 --- shell/platform/linux/fl_renderer.cc | 312 ++++++++++++++---- shell/platform/linux/fl_renderer.h | 109 +++--- shell/platform/linux/fl_renderer_gdk.cc | 91 +++++ shell/platform/linux/fl_renderer_gdk.h | 57 ++++ shell/platform/linux/fl_renderer_gl.cc | 136 -------- shell/platform/linux/fl_renderer_gl.h | 31 -- shell/platform/linux/fl_renderer_headless.cc | 46 +-- shell/platform/linux/fl_view.cc | 132 +++++--- shell/platform/linux/fl_view_private.h | 13 +- shell/platform/linux/testing/mock_renderer.cc | 43 +-- 15 files changed, 564 insertions(+), 626 deletions(-) delete mode 100644 shell/platform/linux/fl_gl_area.cc delete mode 100644 shell/platform/linux/fl_gl_area.h create mode 100644 shell/platform/linux/fl_renderer_gdk.cc create mode 100644 shell/platform/linux/fl_renderer_gdk.h delete mode 100644 shell/platform/linux/fl_renderer_gl.cc delete mode 100644 shell/platform/linux/fl_renderer_gl.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 8e2c1a0f81175..2f57729497a20 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -10926,8 +10926,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_plugin_registrar_test.cc + ../. ORIGIN: ../../../flutter/shell/platform/linux/fl_plugin_registry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_gl.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_gl.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_gdk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_gdk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_headless.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_headless.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_manager.cc + ../../../flutter/LICENSE @@ -13787,8 +13787,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_plugin_registrar_test.cc FILE: ../../../flutter/shell/platform/linux/fl_plugin_registry.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer.h -FILE: ../../../flutter/shell/platform/linux/fl_renderer_gl.cc -FILE: ../../../flutter/shell/platform/linux/fl_renderer_gl.h +FILE: ../../../flutter/shell/platform/linux/fl_renderer_gdk.cc +FILE: ../../../flutter/shell/platform/linux/fl_renderer_gdk.h FILE: ../../../flutter/shell/platform/linux/fl_renderer_headless.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer_headless.h FILE: ../../../flutter/shell/platform/linux/fl_scrolling_manager.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index e0d29566ae2cb..d4d4c11341564 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -106,7 +106,6 @@ source_set("flutter_linux_sources") { "fl_dart_project.cc", "fl_engine.cc", "fl_event_channel.cc", - "fl_gl_area.cc", "fl_gnome_settings.cc", "fl_json_message_codec.cc", "fl_json_method_codec.cc", @@ -127,7 +126,7 @@ source_set("flutter_linux_sources") { "fl_plugin_registrar.cc", "fl_plugin_registry.cc", "fl_renderer.cc", - "fl_renderer_gl.cc", + "fl_renderer_gdk.cc", "fl_renderer_headless.cc", "fl_scrolling_manager.cc", "fl_scrolling_view_delegate.cc", @@ -247,7 +246,10 @@ executable("flutter_linux_unittests") { public_configs = [ "//flutter:config" ] - configs += [ "//flutter/shell/platform/linux/config:gtk" ] + configs += [ + "//flutter/shell/platform/linux/config:gtk", + "//flutter/shell/platform/linux/config:epoxy", + ] defines = [ "FLUTTER_ENGINE_NO_PROTOTYPES", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index ee4cd06004636..51a3cd998c820 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -217,22 +217,14 @@ static void* fl_engine_gl_proc_resolver(void* user_data, const char* name) { static bool fl_engine_gl_make_current(void* user_data) { FlEngine* self = static_cast(user_data); - g_autoptr(GError) error = nullptr; - gboolean result = fl_renderer_make_current(self->renderer, &error); - if (!result) { - g_warning("%s", error->message); - } - return result; + fl_renderer_make_current(self->renderer); + return true; } static bool fl_engine_gl_clear_current(void* user_data) { FlEngine* self = static_cast(user_data); - g_autoptr(GError) error = nullptr; - gboolean result = fl_renderer_clear_current(self->renderer, &error); - if (!result) { - g_warning("%s", error->message); - } - return result; + fl_renderer_clear_current(self->renderer); + return true; } static uint32_t fl_engine_gl_get_fbo(void* user_data) { @@ -248,12 +240,8 @@ static bool fl_engine_gl_present(void* user_data) { static bool fl_engine_gl_make_resource_current(void* user_data) { FlEngine* self = static_cast(user_data); - g_autoptr(GError) error = nullptr; - gboolean result = fl_renderer_make_resource_current(self->renderer, &error); - if (!result) { - g_warning("%s", error->message); - } - return result; + fl_renderer_make_resource_current(self->renderer); + return true; } // Called by the engine to retrieve an external texture. diff --git a/shell/platform/linux/fl_gl_area.cc b/shell/platform/linux/fl_gl_area.cc deleted file mode 100644 index b6c11bdd42fae..0000000000000 --- a/shell/platform/linux/fl_gl_area.cc +++ /dev/null @@ -1,136 +0,0 @@ -// 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_gl_area.h" - -#include - -struct _FlGLArea { - GtkWidget parent_instance; - - GdkGLContext* context; - - GPtrArray* textures; -}; - -G_DEFINE_TYPE(FlGLArea, fl_gl_area, GTK_TYPE_WIDGET) - -static void fl_gl_area_dispose(GObject* gobject) { - FlGLArea* self = FL_GL_AREA(gobject); - - g_clear_object(&self->context); - g_clear_pointer(&self->textures, g_ptr_array_unref); - - G_OBJECT_CLASS(fl_gl_area_parent_class)->dispose(gobject); -} - -// Implements GtkWidget::realize. -static void fl_gl_area_realize(GtkWidget* widget) { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - - gtk_widget_set_realized(widget, TRUE); - - GdkWindowAttr attributes; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual(widget); - attributes.event_mask = gtk_widget_get_events(widget); - gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), - &attributes, attributes_mask); - gtk_widget_set_window(widget, window); - gtk_widget_register_window(widget, window); -} - -// Implements GtkWidget::unrealize. -static void fl_gl_area_unrealize(GtkWidget* widget) { - FlGLArea* self = FL_GL_AREA(widget); - gdk_gl_context_make_current(self->context); - g_clear_pointer(&self->textures, g_ptr_array_unref); - - /* Make sure to unset the context if current */ - if (self->context == gdk_gl_context_get_current()) { - gdk_gl_context_clear_current(); - } - - GTK_WIDGET_CLASS(fl_gl_area_parent_class)->unrealize(widget); -} - -// Implements GtkWidget::size_allocate. -static void fl_gl_area_size_allocate(GtkWidget* widget, - GtkAllocation* allocation) { - gtk_widget_set_allocation(widget, allocation); - - if (gtk_widget_get_has_window(widget)) { - if (gtk_widget_get_realized(widget)) { - gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x, - allocation->y, allocation->width, - allocation->height); - } - } -} - -// Implements GtkWidget::draw. -static gboolean fl_gl_area_draw(GtkWidget* widget, cairo_t* cr) { - FlGLArea* self = FL_GL_AREA(widget); - - gdk_gl_context_make_current(self->context); - - gint scale = gtk_widget_get_scale_factor(widget); - - if (self->textures == nullptr) { - return TRUE; - } - - for (guint i = 0; i < self->textures->len; i++) { - FlBackingStoreProvider* texture = - FL_BACKING_STORE_PROVIDER(g_ptr_array_index(self->textures, i)); - uint32_t texture_id = fl_backing_store_provider_get_gl_texture_id(texture); - GdkRectangle geometry = fl_backing_store_provider_get_geometry(texture); - gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget), texture_id, - GL_TEXTURE, scale, geometry.x, geometry.y, - geometry.width, geometry.height); - } - - return TRUE; -} - -static void fl_gl_area_class_init(FlGLAreaClass* klass) { - GObjectClass* gobject_class = G_OBJECT_CLASS(klass); - gobject_class->dispose = fl_gl_area_dispose; - - GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); - widget_class->realize = fl_gl_area_realize; - widget_class->unrealize = fl_gl_area_unrealize; - widget_class->size_allocate = fl_gl_area_size_allocate; - widget_class->draw = fl_gl_area_draw; - - gtk_widget_class_set_accessible_role(widget_class, ATK_ROLE_DRAWING_AREA); -} - -static void fl_gl_area_init(FlGLArea* self) { - gtk_widget_set_app_paintable(GTK_WIDGET(self), TRUE); -} - -GtkWidget* fl_gl_area_new(GdkGLContext* context) { - g_return_val_if_fail(GDK_IS_GL_CONTEXT(context), nullptr); - FlGLArea* area = - reinterpret_cast(g_object_new(fl_gl_area_get_type(), nullptr)); - area->context = GDK_GL_CONTEXT(g_object_ref(context)); - return GTK_WIDGET(area); -} - -void fl_gl_area_queue_render(FlGLArea* self, GPtrArray* textures) { - g_return_if_fail(FL_IS_GL_AREA(self)); - - g_clear_pointer(&self->textures, g_ptr_array_unref); - self->textures = g_ptr_array_ref(textures); - - gtk_widget_queue_draw(GTK_WIDGET(self)); -} diff --git a/shell/platform/linux/fl_gl_area.h b/shell/platform/linux/fl_gl_area.h deleted file mode 100644 index 72bb32d2c06e9..0000000000000 --- a/shell/platform/linux/fl_gl_area.h +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_GL_AREA_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_GL_AREA_H_ - -#include - -#include "flutter/shell/platform/linux/fl_backing_store_provider.h" - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlGLArea, fl_gl_area, FL, GL_AREA, GtkWidget) - -/** - * FlGLArea: - * - * #FlGLArea is a OpenGL drawing area that shows Flutter backing store Layer. - */ - -/** - * fl_gl_area_new: - * @context: an #GdkGLContext. - * - * Creates a new #FlGLArea widget. - * - * Returns: the newly created #FlGLArea widget. - */ -GtkWidget* fl_gl_area_new(GdkGLContext* context); - -/** - * fl_gl_area_queue_render: - * @area: an #FlGLArea. - * @textures: (transfer none) (element-type FlBackingStoreProvider): a list of - * #FlBackingStoreProvider. - * - * Queues textures to be drawn later. - */ -void fl_gl_area_queue_render(FlGLArea* area, GPtrArray* textures); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_GL_AREA_H_ diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index 61b16230bf103..98ce1a3e56ecb 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -10,6 +10,27 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_backing_store_provider.h" #include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_view_private.h" + +// Vertex shader to draw Flutter window contents. +static const char* vertex_shader_src = + "attribute vec2 position;\n" + "attribute vec2 in_texcoord;\n" + "varying vec2 texcoord;\n" + "\n" + "void main() {\n" + " gl_Position = vec4(position, 0, 1);\n" + " texcoord = in_texcoord;\n" + "}\n"; + +// Fragment shader to draw Flutter window contents. +static const char* fragment_shader_src = + "uniform sampler2D texture;\n" + "varying vec2 texcoord;\n" + "\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, texcoord);\n" + "}\n"; G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error) @@ -27,12 +48,46 @@ typedef struct { // was rendered bool had_first_frame; - GdkGLContext* main_context; - GdkGLContext* resource_context; + // Shader program. + GLuint program; + + // Textures to render. + GPtrArray* textures; } FlRendererPrivate; G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT) +// Returns the log for the given OpenGL shader. +static gchar* get_shader_log(GLuint shader) { + int log_length; + gchar* log; + + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); + + log = static_cast(g_malloc(log_length + 1)); + glGetShaderInfoLog(shader, log_length, nullptr, log); + + return log; +} + +// Returns the log for the given OpenGL program. +static gchar* get_program_log(GLuint program) { + int log_length; + gchar* log; + + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); + + log = static_cast(g_malloc(log_length + 1)); + glGetProgramInfoLog(program, log_length, nullptr, log); + + return log; +} + +/// Converts a pixel co-ordinate from 0..pixels to OpenGL -1..1. +static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels) { + return (2.0 * position / pixels) - 1.0; +} + static void fl_renderer_unblock_main_thread(FlRenderer* self) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); @@ -45,53 +100,36 @@ static void fl_renderer_unblock_main_thread(FlRenderer* self) { } } -static void fl_renderer_dispose(GObject* self) { - fl_renderer_unblock_main_thread(FL_RENDERER(self)); - G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(self); -} - -static void fl_renderer_class_init(FlRendererClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose; -} - -static void fl_renderer_init(FlRenderer* self) {} - -gboolean fl_renderer_start(FlRenderer* self, FlView* view, GError** error) { +static void fl_renderer_dispose(GObject* object) { + FlRenderer* self = FL_RENDERER(object); FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); + fl_renderer_unblock_main_thread(self); - priv->view = view; - gboolean result = FL_RENDERER_GET_CLASS(self)->create_contexts( - self, GTK_WIDGET(view), &priv->main_context, &priv->resource_context, - error); + g_clear_pointer(&priv->textures, g_ptr_array_unref); - if (result) { - gdk_gl_context_realize(priv->main_context, error); - gdk_gl_context_realize(priv->resource_context, error); - } + G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(object); +} - if (*error != nullptr) { - return FALSE; - } - return TRUE; +static void fl_renderer_class_init(FlRendererClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose; } -FlView* fl_renderer_get_view(FlRenderer* self) { - g_return_val_if_fail(FL_IS_RENDERER(self), NULL); +static void fl_renderer_init(FlRenderer* self) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); - return priv->view; + priv->textures = g_ptr_array_new_with_free_func(g_object_unref); } -GdkGLContext* fl_renderer_get_context(FlRenderer* self) { +gboolean fl_renderer_start(FlRenderer* self, FlView* view) { FlRendererPrivate* priv = reinterpret_cast( fl_renderer_get_instance_private(self)); - g_return_val_if_fail(FL_IS_RENDERER(self), NULL); + g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - return priv->main_context; + priv->view = view; + return TRUE; } void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) { @@ -100,38 +138,19 @@ void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) { return reinterpret_cast(eglGetProcAddress(name)); } -gboolean fl_renderer_make_current(FlRenderer* self, GError** error) { - FlRendererPrivate* priv = reinterpret_cast( - fl_renderer_get_instance_private(self)); - - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - - if (priv->main_context) { - gdk_gl_context_make_current(priv->main_context); - } - - return TRUE; +void fl_renderer_make_current(FlRenderer* self) { + g_return_if_fail(FL_IS_RENDERER(self)); + FL_RENDERER_GET_CLASS(self)->make_current(self); } -gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) { - FlRendererPrivate* priv = reinterpret_cast( - fl_renderer_get_instance_private(self)); - - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - - if (priv->resource_context) { - gdk_gl_context_make_current(priv->resource_context); - } - - return TRUE; +void fl_renderer_make_resource_current(FlRenderer* self) { + g_return_if_fail(FL_IS_RENDERER(self)); + FL_RENDERER_GET_CLASS(self)->make_resource_current(self); } -gboolean fl_renderer_clear_current(FlRenderer* self, GError** error) { - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - - gdk_gl_context_clear_current(); - - return TRUE; +void fl_renderer_clear_current(FlRenderer* self) { + g_return_if_fail(FL_IS_RENDERER(self)); + FL_RENDERER_GET_CLASS(self)->clear_current(self); } guint32 fl_renderer_get_fbo(FlRenderer* self) { @@ -142,20 +161,42 @@ guint32 fl_renderer_get_fbo(FlRenderer* self) { } gboolean fl_renderer_create_backing_store( - FlRenderer* self, + FlRenderer* renderer, const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out) { - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - return FL_RENDERER_GET_CLASS(self)->create_backing_store(self, config, - backing_store_out); + fl_renderer_make_current(renderer); + + 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_collect_backing_store(), set + // on FlutterCompositor.collect_backing_store_callback during engine start. + }; + + return TRUE; } gboolean fl_renderer_collect_backing_store( FlRenderer* self, const FlutterBackingStore* backing_store) { - g_return_val_if_fail(FL_IS_RENDERER(self), FALSE); - return FL_RENDERER_GET_CLASS(self)->collect_backing_store(self, - backing_store); + fl_renderer_make_current(self); + + // OpenGL context is required when destroying #FlBackingStoreProvider. + g_object_unref(backing_store->open_gl.framebuffer.user_data); + return TRUE; } void fl_renderer_wait_for_frame(FlRenderer* self, @@ -198,6 +239,137 @@ gboolean fl_renderer_present_layers(FlRenderer* self, fl_renderer_unblock_main_thread(self); - return FL_RENDERER_GET_CLASS(self)->present_layers(self, layers, - layers_count); + if (!priv->view) { + return FALSE; + } + + g_ptr_array_set_size(priv->textures, 0); + 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; + FlBackingStoreProvider* provider = + FL_BACKING_STORE_PROVIDER(framebuffer->user_data); + g_ptr_array_add(priv->textures, g_object_ref(provider)); + } break; + case kFlutterLayerContentTypePlatformView: { + // Currently unsupported. + } break; + } + } + + fl_view_redraw(priv->view); + + return TRUE; +} + +void fl_renderer_setup(FlRenderer* self) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + + g_return_if_fail(FL_IS_RENDERER(self)); + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_shader_src, nullptr); + glCompileShader(vertex_shader); + int vertex_compile_status; + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status); + if (vertex_compile_status == GL_FALSE) { + g_autofree gchar* shader_log = get_shader_log(vertex_shader); + g_warning("Failed to compile vertex shader: %s", shader_log); + } + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_shader_src, nullptr); + glCompileShader(fragment_shader); + int fragment_compile_status; + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status); + if (fragment_compile_status == GL_FALSE) { + g_autofree gchar* shader_log = get_shader_log(fragment_shader); + g_warning("Failed to compile fragment shader: %s", shader_log); + } + + priv->program = glCreateProgram(); + glAttachShader(priv->program, vertex_shader); + glAttachShader(priv->program, fragment_shader); + glLinkProgram(priv->program); + + int link_status; + glGetProgramiv(priv->program, GL_LINK_STATUS, &link_status); + if (link_status == GL_FALSE) { + g_autofree gchar* program_log = get_program_log(priv->program); + g_warning("Failed to link program: %s", program_log); + } + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); +} + +void fl_renderer_render(FlRenderer* self, int width, int height) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + + g_return_if_fail(FL_IS_RENDERER(self)); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(priv->program); + + for (guint i = 0; i < priv->textures->len; i++) { + FlBackingStoreProvider* texture = + FL_BACKING_STORE_PROVIDER(g_ptr_array_index(priv->textures, i)); + + uint32_t texture_id = fl_backing_store_provider_get_gl_texture_id(texture); + glBindTexture(GL_TEXTURE_2D, texture_id); + + // Translate into OpenGL co-ordinates + GdkRectangle texture_geometry = + fl_backing_store_provider_get_geometry(texture); + GLfloat texture_x = texture_geometry.x; + GLfloat texture_y = texture_geometry.y; + GLfloat texture_width = texture_geometry.width; + GLfloat texture_height = texture_geometry.height; + GLfloat x0 = pixels_to_gl_coords(texture_x, width); + GLfloat y0 = + pixels_to_gl_coords(height - (texture_y + texture_height), height); + GLfloat x1 = pixels_to_gl_coords(texture_x + texture_width, width); + GLfloat y1 = pixels_to_gl_coords(height - texture_y, height); + GLfloat vertex_data[] = {x0, y0, 0, 0, x1, y1, 1, 1, x0, y1, 0, 1, + x0, y0, 0, 0, x1, y0, 1, 0, x1, y1, 1, 1}; + + GLuint vao, vertex_buffer; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, + GL_STATIC_DRAW); + GLint position_index = glGetAttribLocation(priv->program, "position"); + glEnableVertexAttribArray(position_index); + glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, + sizeof(GLfloat) * 4, 0); + GLint texcoord_index = glGetAttribLocation(priv->program, "in_texcoord"); + glEnableVertexAttribArray(texcoord_index); + glVertexAttribPointer(texcoord_index, 2, GL_FLOAT, GL_FALSE, + sizeof(GLfloat) * 4, (void*)(sizeof(GLfloat) * 2)); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vertex_buffer); + } + + glFlush(); +} + +void fl_renderer_cleanup(FlRenderer* self) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + + g_return_if_fail(FL_IS_RENDERER(self)); + + glDeleteProgram(priv->program); } diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h index 16f2cbf540ac7..e2145fdbaed7b 100644 --- a/shell/platform/linux/fl_renderer.h +++ b/shell/platform/linux/fl_renderer.h @@ -39,30 +39,24 @@ struct _FlRendererClass { GObjectClass parent_class; /** - * Virtual method called when Flutter needs #GdkGLContext to render. + * Virtual method called when Flutter needs to make the OpenGL context + * current. * @renderer: an #FlRenderer. - * @widget: the widget being rendered on. - * @visible: (out): the GL context for visible surface. - * @resource: (out): the GL context for resource loading. - * @error: (allow-none): #GError location to store the error occurring, or - * %NULL to ignore. - * - * Returns: %TRUE if both contexts were created, %FALSE if there was an error. */ - gboolean (*create_contexts)(FlRenderer* renderer, - GtkWidget* widget, - GdkGLContext** visible, - GdkGLContext** resource, - GError** error); + void (*make_current)(FlRenderer* renderer); /** - * Virtual method called when Flutter needs OpenGL proc address. + * Virtual method called when Flutter needs to make the OpenGL resource + * context current. + * @renderer: an #FlRenderer. + */ + void (*make_resource_current)(FlRenderer* renderer); + + /** + * Virtual method called when Flutter needs to clear the OpenGL context. * @renderer: an #FlRenderer. - * @name: proc name. - * - * Returns: OpenGL proc address. */ - void* (*get_proc_address)(); + void (*clear_current)(FlRenderer* renderer); /** * Virtual method called when Flutter needs a backing store for a specific @@ -86,49 +80,18 @@ struct _FlRendererClass { */ gboolean (*collect_backing_store)(FlRenderer* renderer, const FlutterBackingStore* backing_store); - - /** - * Virtual method called when Flutter wants to composite layers onto the - * screen. - * @renderer: an #FlRenderer. - * @layers: layers to be composited. - * @layers_count: number of layers. - * - * Returns %TRUE if successful. - */ - gboolean (*present_layers)(FlRenderer* renderer, - const FlutterLayer** layers, - size_t layers_count); }; /** * fl_renderer_start: * @renderer: an #FlRenderer. * @view: the view Flutter is renderering to. - * @error: (allow-none): #GError location to store the error occurring, or %NULL - * to ignore. * * Start the renderer. * * Returns: %TRUE if successfully started. */ -gboolean fl_renderer_start(FlRenderer* renderer, FlView* view, GError** error); - -/** - * fl_renderer_get_view: - * @renderer: an #FlRenderer. - * - * Returns: targeted #FlView or %NULL if headless. - */ -FlView* fl_renderer_get_view(FlRenderer* renderer); - -/** - * fl_renderer_get_context: - * @renderer: an #FlRenderer. - * - * Returns: GL context for GLAreas or %NULL if headless. - */ -GdkGLContext* fl_renderer_get_context(FlRenderer* renderer); +gboolean fl_renderer_start(FlRenderer* renderer, FlView* view); /** * fl_renderer_get_proc_address: @@ -144,39 +107,26 @@ void* fl_renderer_get_proc_address(FlRenderer* renderer, const char* name); /** * fl_renderer_make_current: * @renderer: an #FlRenderer. - * @error: (allow-none): #GError location to store the error occurring, or %NULL - * to ignore. * * Makes the rendering context current. - * - * Returns %TRUE if successful. */ -gboolean fl_renderer_make_current(FlRenderer* renderer, GError** error); +void fl_renderer_make_current(FlRenderer* renderer); /** * fl_renderer_make_resource_current: * @renderer: an #FlRenderer. - * @error: (allow-none): #GError location to store the error occurring, or %NULL - * to ignore. * * Makes the resource rendering context current. - * - * Returns %TRUE if successful. */ -gboolean fl_renderer_make_resource_current(FlRenderer* renderer, - GError** error); +void fl_renderer_make_resource_current(FlRenderer* renderer); /** * fl_renderer_clear_current: * @renderer: an #FlRenderer. - * @error: (allow-none): #GError location to store the error occurring, or %NULL - * to ignore. * * Clears the current rendering context. - * - * Returns %TRUE if successful. */ -gboolean fl_renderer_clear_current(FlRenderer* renderer, GError** error); +void fl_renderer_clear_current(FlRenderer* renderer); /** * fl_renderer_get_fbo: @@ -246,6 +196,33 @@ void fl_renderer_wait_for_frame(FlRenderer* renderer, int target_width, int target_height); +/** + * fl_renderer_setup: + * @renderer: an #FlRenderer. + * + * Creates OpenGL resources required before rendering. Requires an active OpenGL + * context. + */ +void fl_renderer_setup(FlRenderer* renderer); + +/** + * fl_renderer_render: + * @renderer: an #FlRenderer. + * @width: width of the window in pixels. + * @height: height of the window in pixels. + * + * Performs OpenGL commands to render current Flutter view. + */ +void fl_renderer_render(FlRenderer* renderer, int width, int height); + +/** + * fl_renderer_cleanup: + * + * Removes OpenGL resources used for rendering. Requires an active OpenGL + * context. + */ +void fl_renderer_cleanup(FlRenderer* renderer); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_H_ diff --git a/shell/platform/linux/fl_renderer_gdk.cc b/shell/platform/linux/fl_renderer_gdk.cc new file mode 100644 index 0000000000000..90623b4f209cb --- /dev/null +++ b/shell/platform/linux/fl_renderer_gdk.cc @@ -0,0 +1,91 @@ +// 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_gdk.h" + +struct _FlRendererGdk { + FlRenderer parent_instance; + + // Window being rendered on. + GdkWindow* window; + + // Main OpenGL rendering context. + GdkGLContext* main_context; + + // Secondary OpenGL rendering context. + GdkGLContext* resource_context; +}; + +G_DEFINE_TYPE(FlRendererGdk, fl_renderer_gdk, fl_renderer_get_type()) + +// Implements FlRenderer::make_current. +static void fl_renderer_gdk_make_current(FlRenderer* renderer) { + FlRendererGdk* self = FL_RENDERER_GDK(renderer); + gdk_gl_context_make_current(self->main_context); +} + +// Implements FlRenderer::make_resource_current. +static void fl_renderer_gdk_make_resource_current(FlRenderer* renderer) { + FlRendererGdk* self = FL_RENDERER_GDK(renderer); + gdk_gl_context_make_current(self->resource_context); +} + +// Implements FlRenderer::clear_current. +static void fl_renderer_gdk_clear_current(FlRenderer* renderer) { + gdk_gl_context_clear_current(); +} + +static void fl_renderer_gdk_dispose(GObject* object) { + FlRendererGdk* self = FL_RENDERER_GDK(object); + + g_clear_object(&self->main_context); + g_clear_object(&self->resource_context); + + G_OBJECT_CLASS(fl_renderer_gdk_parent_class)->dispose(object); +} + +static void fl_renderer_gdk_class_init(FlRendererGdkClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_renderer_gdk_dispose; + + FL_RENDERER_CLASS(klass)->make_current = fl_renderer_gdk_make_current; + FL_RENDERER_CLASS(klass)->make_resource_current = + fl_renderer_gdk_make_resource_current; + FL_RENDERER_CLASS(klass)->clear_current = fl_renderer_gdk_clear_current; +} + +static void fl_renderer_gdk_init(FlRendererGdk* self) {} + +FlRendererGdk* fl_renderer_gdk_new(GdkWindow* window) { + FlRendererGdk* self = + FL_RENDERER_GDK(g_object_new(fl_renderer_gdk_get_type(), nullptr)); + self->window = window; + return self; +} + +gboolean fl_renderer_gdk_create_contexts(FlRendererGdk* self, GError** error) { + self->main_context = gdk_window_create_gl_context(self->window, error); + if (self->main_context == nullptr) { + return FALSE; + } + gdk_gl_context_set_use_es(self->main_context, TRUE); + if (!gdk_gl_context_realize(self->main_context, error)) { + return FALSE; + } + + self->resource_context = gdk_window_create_gl_context(self->window, error); + if (self->resource_context == nullptr) { + return FALSE; + } + gdk_gl_context_set_use_es(self->resource_context, TRUE); + if (!gdk_gl_context_realize(self->resource_context, error)) { + return FALSE; + } + + return TRUE; +} + +GdkGLContext* fl_renderer_gdk_get_context(FlRendererGdk* self) { + g_return_val_if_fail(FL_IS_RENDERER_GDK(self), nullptr); + return self->main_context; +} diff --git a/shell/platform/linux/fl_renderer_gdk.h b/shell/platform/linux/fl_renderer_gdk.h new file mode 100644 index 0000000000000..e2b3f7bb1f961 --- /dev/null +++ b/shell/platform/linux/fl_renderer_gdk.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GDK_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GDK_H_ + +#include "flutter/shell/platform/linux/fl_renderer.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlRendererGdk, + fl_renderer_gdk, + FL, + RENDERER_GDK, + FlRenderer) + +/** + * FlRendererGdk: + * + * #FlRendererGdk is an implementation of #FlRenderer that renders by OpenGL ES. + */ + +/** + * fl_renderer_gdk_new: + * @window: the window that is being rendered on. + * + * Creates an object that allows Flutter to render by OpenGL ES. + * + * Returns: a new #FlRendererGdk. + */ +FlRendererGdk* fl_renderer_gdk_new(GdkWindow* window); + +/** + * fl_renderer_gdk_create_contexts: + * @renderer: an #FlRendererGdk. + * @error: (allow-none): #GError location to store the error occurring, or + * %NULL to ignore. + * + * Create rendering contexts. + * + * Returns: %TRUE if contexts were created, %FALSE if there was an error. + */ +gboolean fl_renderer_gdk_create_contexts(FlRendererGdk* renderer, + GError** error); + +/** + * fl_renderer_gdk_get_context: + * @renderer: an #FlRendererGdk. + * + * Returns: the main context used for rendering. + */ +GdkGLContext* fl_renderer_gdk_get_context(FlRendererGdk* renderer); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GDK_H_ diff --git a/shell/platform/linux/fl_renderer_gl.cc b/shell/platform/linux/fl_renderer_gl.cc deleted file mode 100644 index 7210e95954950..0000000000000 --- a/shell/platform/linux/fl_renderer_gl.cc +++ /dev/null @@ -1,136 +0,0 @@ -// 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( - 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)); -} diff --git a/shell/platform/linux/fl_renderer_gl.h b/shell/platform/linux/fl_renderer_gl.h deleted file mode 100644 index 25216b49cab10..0000000000000 --- a/shell/platform/linux/fl_renderer_gl.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GL_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GL_H_ - -#include "flutter/shell/platform/linux/fl_renderer.h" - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlRendererGL, fl_renderer_gl, FL, RENDERER_GL, FlRenderer) - -/** - * FlRendererGL: - * - * #FlRendererGL is an implementation of #FlRenderer that renders by OpenGL ES. - */ - -/** - * fl_renderer_gl_new: - * - * Creates an object that allows Flutter to render by OpenGL ES. - * - * Returns: a new #FlRendererGL. - */ -FlRendererGL* fl_renderer_gl_new(); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_GL_H_ diff --git a/shell/platform/linux/fl_renderer_headless.cc b/shell/platform/linux/fl_renderer_headless.cc index 19d2da931e8e2..1736e1437396f 100644 --- a/shell/platform/linux/fl_renderer_headless.cc +++ b/shell/platform/linux/fl_renderer_headless.cc @@ -10,46 +10,20 @@ struct _FlRendererHeadless { G_DEFINE_TYPE(FlRendererHeadless, fl_renderer_headless, fl_renderer_get_type()) -// Implements FlRenderer::create_contexts. -static gboolean fl_renderer_headless_create_contexts(FlRenderer* renderer, - GtkWidget* widget, - GdkGLContext** visible, - GdkGLContext** resource, - GError** error) { - return FALSE; -} +// Implements FlRenderer::make_current. +static void fl_renderer_headless_make_current(FlRenderer* renderer) {} -// Implements FlRenderer::create_backing_store. -static gboolean fl_renderer_headless_create_backing_store( - FlRenderer* renderer, - const FlutterBackingStoreConfig* config, - FlutterBackingStore* backing_store_out) { - return FALSE; -} +// Implements FlRenderer::make_resource_current. +static void fl_renderer_headless_make_resource_current(FlRenderer* renderer) {} -// Implements FlRenderer::collect_backing_store. -static gboolean fl_renderer_headless_collect_backing_store( - FlRenderer* self, - const FlutterBackingStore* backing_store) { - return FALSE; -} - -// Implements FlRenderer::present_layers. -static gboolean fl_renderer_headless_present_layers(FlRenderer* self, - const FlutterLayer** layers, - size_t layers_count) { - return FALSE; -} +// Implements FlRenderer::clear_current. +static void fl_renderer_headless_clear_current(FlRenderer* renderer) {} static void fl_renderer_headless_class_init(FlRendererHeadlessClass* klass) { - FL_RENDERER_CLASS(klass)->create_contexts = - fl_renderer_headless_create_contexts; - FL_RENDERER_CLASS(klass)->create_backing_store = - fl_renderer_headless_create_backing_store; - FL_RENDERER_CLASS(klass)->collect_backing_store = - fl_renderer_headless_collect_backing_store; - FL_RENDERER_CLASS(klass)->present_layers = - fl_renderer_headless_present_layers; + FL_RENDERER_CLASS(klass)->make_current = fl_renderer_headless_make_current; + FL_RENDERER_CLASS(klass)->make_resource_current = + fl_renderer_headless_make_resource_current; + FL_RENDERER_CLASS(klass)->clear_current = fl_renderer_headless_clear_current; } static void fl_renderer_headless_init(FlRendererHeadless* self) {} diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index b6b29b1890efa..f3f661518fc5b 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -9,6 +9,7 @@ #include #include "flutter/shell/platform/linux/fl_accessibility_plugin.h" +#include "flutter/shell/platform/linux/fl_backing_store_provider.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/fl_keyboard_manager.h" @@ -16,7 +17,7 @@ #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" -#include "flutter/shell/platform/linux/fl_renderer_gl.h" +#include "flutter/shell/platform/linux/fl_renderer_gdk.h" #include "flutter/shell/platform/linux/fl_scrolling_manager.h" #include "flutter/shell/platform/linux/fl_scrolling_view_delegate.h" #include "flutter/shell/platform/linux/fl_text_input_plugin.h" @@ -34,7 +35,7 @@ struct _FlView { FlDartProject* project; // Rendering output. - FlRenderer* renderer; + FlRendererGdk* renderer; // Engine running @project. FlEngine* engine; @@ -54,7 +55,7 @@ struct _FlView { FlPlatformPlugin* platform_plugin; GtkWidget* event_box; - FlGLArea* gl_area; + GtkGLArea* gl_area; // Tracks whether mouse pointer is inside the view. gboolean pointer_inside; @@ -220,7 +221,8 @@ static void handle_geometry_changed(FlView* self) { // Note: `gtk_widget_init()` initializes the size allocation to 1x1. if (allocation.width > 1 && allocation.height > 1 && gtk_widget_get_realized(GTK_WIDGET(self))) { - fl_renderer_wait_for_frame(self->renderer, allocation.width * scale_factor, + fl_renderer_wait_for_frame(FL_RENDERER(self->renderer), + allocation.width * scale_factor, allocation.height * scale_factor); } } @@ -519,9 +521,50 @@ static gboolean window_state_event_cb(FlView* self, GdkEvent* event) { return FALSE; } +static GdkGLContext* create_context_cb(FlView* self) { + self->renderer = + fl_renderer_gdk_new(gtk_widget_get_parent_window(GTK_WIDGET(self))); + self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer)); + fl_engine_set_update_semantics_node_handler( + self->engine, update_semantics_node_cb, self, nullptr); + fl_engine_set_on_pre_engine_restart_handler( + self->engine, on_pre_engine_restart_cb, self, nullptr); + + // Must initialize the keymap before the keyboard. + self->keymap = gdk_keymap_get_for_display(gdk_display_get_default()); + self->keymap_keys_changed_cb_id = g_signal_connect_swapped( + self->keymap, "keys-changed", G_CALLBACK(keymap_keys_changed_cb), self); + + // Create system channel handlers. + FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); + self->accessibility_plugin = fl_accessibility_plugin_new(self); + init_scrolling(self); + self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); + self->platform_plugin = fl_platform_plugin_new(messenger); + + g_autoptr(GError) error = nullptr; + if (!fl_renderer_gdk_create_contexts(self->renderer, &error)) { + gtk_gl_area_set_error(self->gl_area, error); + return nullptr; + } + + return GDK_GL_CONTEXT( + g_object_ref(fl_renderer_gdk_get_context(self->renderer))); +} + static void realize_cb(FlView* self) { g_autoptr(GError) error = nullptr; + fl_renderer_make_current(FL_RENDERER(self->renderer)); + + GError* gl_error = gtk_gl_area_get_error(self->gl_area); + if (gl_error != NULL) { + g_warning("Failed to initialize GLArea: %s", gl_error->message); + return; + } + + fl_renderer_setup(FL_RENDERER(self->renderer)); + // Handle requests by the user to close the application. GtkWidget* toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(self)); @@ -537,10 +580,7 @@ static void realize_cb(FlView* self) { init_keyboard(self); - if (!fl_renderer_start(self->renderer, self, &error)) { - g_warning("Failed to start Flutter renderer: %s", error->message); - return; - } + fl_renderer_start(FL_RENDERER(FL_RENDERER(self->renderer)), self); if (!fl_engine_start(self->engine, &error)) { g_warning("Failed to start Flutter engine: %s", error->message); @@ -550,6 +590,34 @@ static void realize_cb(FlView* self) { handle_geometry_changed(self); } +static gboolean render_cb(FlView* self, GdkGLContext* context) { + if (gtk_gl_area_get_error(self->gl_area) != NULL) { + return FALSE; + } + + int width = gtk_widget_get_allocated_width(GTK_WIDGET(self->gl_area)); + int height = gtk_widget_get_allocated_height(GTK_WIDGET(self->gl_area)); + gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self->gl_area)); + fl_renderer_render(FL_RENDERER(self->renderer), width * scale_factor, + height * scale_factor); + + return TRUE; +} + +static void unrealize_cb(FlView* self) { + g_autoptr(GError) error = nullptr; + + fl_renderer_make_current(FL_RENDERER(self->renderer)); + + GError* gl_error = gtk_gl_area_get_error(self->gl_area); + if (gl_error != NULL) { + g_warning("Failed to uninitialize GLArea: %s", gl_error->message); + return; + } + + fl_renderer_cleanup(FL_RENDERER(self->renderer)); +} + static void size_allocate_cb(FlView* self) { handle_geometry_changed(self); } @@ -557,23 +625,6 @@ static void size_allocate_cb(FlView* self) { static void fl_view_constructed(GObject* object) { FlView* self = FL_VIEW(object); - self->renderer = FL_RENDERER(fl_renderer_gl_new()); - self->engine = fl_engine_new(self->project, self->renderer); - fl_engine_set_update_semantics_node_handler( - self->engine, update_semantics_node_cb, self, nullptr); - fl_engine_set_on_pre_engine_restart_handler( - self->engine, on_pre_engine_restart_cb, self, nullptr); - - // Must initialize the keymap before the keyboard. - self->keymap = gdk_keymap_get_for_display(gdk_display_get_default()); - - // Create system channel handlers. - FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); - self->accessibility_plugin = fl_accessibility_plugin_new(self); - init_scrolling(self); - self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); - self->platform_plugin = fl_platform_plugin_new(messenger); - self->event_box = gtk_event_box_new(); gtk_widget_set_hexpand(self->event_box, TRUE); gtk_widget_set_vexpand(self->event_box, TRUE); @@ -596,8 +647,6 @@ static void fl_view_constructed(GObject* object) { G_CALLBACK(enter_notify_event_cb), self); g_signal_connect_swapped(self->event_box, "leave-notify-event", G_CALLBACK(leave_notify_event_cb), self); - self->keymap_keys_changed_cb_id = g_signal_connect_swapped( - self->keymap, "keys-changed", G_CALLBACK(keymap_keys_changed_cb), self); GtkGesture* zoom = gtk_gesture_zoom_new(self->event_box); g_signal_connect_swapped(zoom, "begin", G_CALLBACK(gesture_zoom_begin_cb), self); @@ -612,7 +661,19 @@ static void fl_view_constructed(GObject* object) { g_signal_connect_swapped(rotate, "end", G_CALLBACK(gesture_rotation_end_cb), self); - g_signal_connect_swapped(self, "realize", G_CALLBACK(realize_cb), self); + self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); + gtk_widget_show(GTK_WIDGET(self->gl_area)); + gtk_container_add(GTK_CONTAINER(self->event_box), GTK_WIDGET(self->gl_area)); + + g_signal_connect_swapped(self->gl_area, "create-context", + G_CALLBACK(create_context_cb), self); + g_signal_connect_swapped(self->gl_area, "realize", G_CALLBACK(realize_cb), + self); + g_signal_connect_swapped(self->gl_area, "render", G_CALLBACK(render_cb), + self); + g_signal_connect_swapped(self->gl_area, "unrealize", G_CALLBACK(unrealize_cb), + self); + g_signal_connect_swapped(self, "size-allocate", G_CALLBACK(size_allocate_cb), self); } @@ -749,23 +810,12 @@ G_MODULE_EXPORT FlEngine* fl_view_get_engine(FlView* self) { return self->engine; } -void fl_view_set_textures(FlView* self, - GdkGLContext* context, - GPtrArray* textures) { +void fl_view_redraw(FlView* self) { g_return_if_fail(FL_IS_VIEW(self)); - - if (self->gl_area == nullptr) { - self->gl_area = FL_GL_AREA(fl_gl_area_new(context)); - gtk_widget_show(GTK_WIDGET(self->gl_area)); - gtk_container_add(GTK_CONTAINER(self->event_box), - GTK_WIDGET(self->gl_area)); - } - - fl_gl_area_queue_render(self->gl_area, textures); + gtk_widget_queue_draw(GTK_WIDGET(self->gl_area)); } GHashTable* fl_view_get_keyboard_state(FlView* self) { g_return_val_if_fail(FL_IS_VIEW(self), nullptr); - return fl_keyboard_manager_get_pressed_state(self->keyboard_manager); } diff --git a/shell/platform/linux/fl_view_private.h b/shell/platform/linux/fl_view_private.h index dffc5114e5387..de3fc9c911876 100644 --- a/shell/platform/linux/fl_view_private.h +++ b/shell/platform/linux/fl_view_private.h @@ -7,20 +7,13 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" -#include "flutter/shell/platform/linux/fl_gl_area.h" - /** - * fl_view_set_textures: + * fl_view_redraw: * @view: an #FlView. - * @context: a #GdkGLContext, for #FlGLArea to render. - * @textures: (transfer none) (element-type FlBackingStoreProvider): a list of - * #FlBackingStoreProvider. * - * Set the textures for this view to render. + * Indicate the view needs to redraw. */ -void fl_view_set_textures(FlView* view, - GdkGLContext* context, - GPtrArray* textures); +void fl_view_redraw(FlView* view); /** * fl_view_get_keyboard_state: diff --git a/shell/platform/linux/testing/mock_renderer.cc b/shell/platform/linux/testing/mock_renderer.cc index ce801724ec3c8..b204bf1016259 100644 --- a/shell/platform/linux/testing/mock_renderer.cc +++ b/shell/platform/linux/testing/mock_renderer.cc @@ -10,44 +10,25 @@ struct _FlMockRenderer { G_DEFINE_TYPE(FlMockRenderer, fl_mock_renderer, fl_renderer_get_type()) -// Implements FlRenderer::create_contexts. -static gboolean fl_mock_renderer_create_contexts(FlRenderer* renderer, - GtkWidget* widget, - GdkGLContext** visible, - GdkGLContext** resource, - GError** error) { - return TRUE; +// Implements FlRenderer::make_current. +static void fl_mock_renderer_make_current(FlRenderer *renderer) +{ } -// Implements FlRenderer::create_backing_store. -static gboolean fl_mock_renderer_create_backing_store( - FlRenderer* renderer, - const FlutterBackingStoreConfig* config, - FlutterBackingStore* backing_store_out) { - return TRUE; +// Implements FlRenderer::make_resource_current. +static void fl_mock_renderer_make_resource_current(FlRenderer *renderer) +{ } -// Implements FlRenderer::collect_backing_store. -static gboolean fl_mock_renderer_collect_backing_store( - FlRenderer* self, - const FlutterBackingStore* backing_store) { - return TRUE; -} - -// Implements FlRenderer::present_layers. -static gboolean fl_mock_renderer_present_layers(FlRenderer* self, - const FlutterLayer** layers, - size_t layers_count) { - return TRUE; +// Implements FlRenderer::clear_current. +static void fl_mock_renderer_clear_current(FlRenderer *renderer) +{ } static void fl_mock_renderer_class_init(FlMockRendererClass* klass) { - FL_RENDERER_CLASS(klass)->create_contexts = fl_mock_renderer_create_contexts; - FL_RENDERER_CLASS(klass)->create_backing_store = - fl_mock_renderer_create_backing_store; - FL_RENDERER_CLASS(klass)->collect_backing_store = - fl_mock_renderer_collect_backing_store; - FL_RENDERER_CLASS(klass)->present_layers = fl_mock_renderer_present_layers; + FL_RENDERER_CLASS(klass)->make_current= fl_mock_renderer_make_current; + FL_RENDERER_CLASS(klass)->make_resource_current= fl_mock_renderer_make_resource_current; + FL_RENDERER_CLASS(klass)->clear_current= fl_mock_renderer_clear_current; } static void fl_mock_renderer_init(FlMockRenderer* self) {} From 74232b6566e939ffb9a98366a7b60d6d2e7f556a Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 21 Feb 2024 17:05:16 +1300 Subject: [PATCH 3/9] Stop using constructed, we can use init now code requiring this was moved to realize --- shell/platform/linux/fl_view.cc | 109 +++++++++++++++----------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index f3f661518fc5b..615a0f7a034a3 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -622,62 +622,6 @@ static void size_allocate_cb(FlView* self) { handle_geometry_changed(self); } -static void fl_view_constructed(GObject* object) { - FlView* self = FL_VIEW(object); - - self->event_box = gtk_event_box_new(); - gtk_widget_set_hexpand(self->event_box, TRUE); - gtk_widget_set_vexpand(self->event_box, TRUE); - gtk_container_add(GTK_CONTAINER(self), self->event_box); - gtk_widget_show(self->event_box); - gtk_widget_add_events(self->event_box, - GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | - GDK_SMOOTH_SCROLL_MASK); - - g_signal_connect_swapped(self->event_box, "button-press-event", - G_CALLBACK(button_press_event_cb), self); - g_signal_connect_swapped(self->event_box, "button-release-event", - G_CALLBACK(button_release_event_cb), self); - g_signal_connect_swapped(self->event_box, "scroll-event", - G_CALLBACK(scroll_event_cb), self); - g_signal_connect_swapped(self->event_box, "motion-notify-event", - G_CALLBACK(motion_notify_event_cb), self); - g_signal_connect_swapped(self->event_box, "enter-notify-event", - G_CALLBACK(enter_notify_event_cb), self); - g_signal_connect_swapped(self->event_box, "leave-notify-event", - G_CALLBACK(leave_notify_event_cb), self); - GtkGesture* zoom = gtk_gesture_zoom_new(self->event_box); - g_signal_connect_swapped(zoom, "begin", G_CALLBACK(gesture_zoom_begin_cb), - self); - g_signal_connect_swapped(zoom, "scale-changed", - G_CALLBACK(gesture_zoom_update_cb), self); - g_signal_connect_swapped(zoom, "end", G_CALLBACK(gesture_zoom_end_cb), self); - GtkGesture* rotate = gtk_gesture_rotate_new(self->event_box); - g_signal_connect_swapped(rotate, "begin", - G_CALLBACK(gesture_rotation_begin_cb), self); - g_signal_connect_swapped(rotate, "angle-changed", - G_CALLBACK(gesture_rotation_update_cb), self); - g_signal_connect_swapped(rotate, "end", G_CALLBACK(gesture_rotation_end_cb), - self); - - self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); - gtk_widget_show(GTK_WIDGET(self->gl_area)); - gtk_container_add(GTK_CONTAINER(self->event_box), GTK_WIDGET(self->gl_area)); - - g_signal_connect_swapped(self->gl_area, "create-context", - G_CALLBACK(create_context_cb), self); - g_signal_connect_swapped(self->gl_area, "realize", G_CALLBACK(realize_cb), - self); - g_signal_connect_swapped(self->gl_area, "render", G_CALLBACK(render_cb), - self); - g_signal_connect_swapped(self->gl_area, "unrealize", G_CALLBACK(unrealize_cb), - self); - - g_signal_connect_swapped(self, "size-allocate", G_CALLBACK(size_allocate_cb), - self); -} - static void fl_view_set_property(GObject* object, guint prop_id, const GValue* value, @@ -774,7 +718,6 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, static void fl_view_class_init(FlViewClass* klass) { GObjectClass* object_class = G_OBJECT_CLASS(klass); - object_class->constructed = fl_view_constructed; object_class->set_property = fl_view_set_property; object_class->get_property = fl_view_get_property; object_class->notify = fl_view_notify; @@ -798,6 +741,58 @@ static void fl_view_class_init(FlViewClass* klass) { static void fl_view_init(FlView* self) { gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE); + + self->event_box = gtk_event_box_new(); + gtk_widget_set_hexpand(self->event_box, TRUE); + gtk_widget_set_vexpand(self->event_box, TRUE); + gtk_container_add(GTK_CONTAINER(self), self->event_box); + gtk_widget_show(self->event_box); + gtk_widget_add_events(self->event_box, + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | + GDK_SMOOTH_SCROLL_MASK); + + g_signal_connect_swapped(self->event_box, "button-press-event", + G_CALLBACK(button_press_event_cb), self); + g_signal_connect_swapped(self->event_box, "button-release-event", + G_CALLBACK(button_release_event_cb), self); + g_signal_connect_swapped(self->event_box, "scroll-event", + G_CALLBACK(scroll_event_cb), self); + g_signal_connect_swapped(self->event_box, "motion-notify-event", + G_CALLBACK(motion_notify_event_cb), self); + g_signal_connect_swapped(self->event_box, "enter-notify-event", + G_CALLBACK(enter_notify_event_cb), self); + g_signal_connect_swapped(self->event_box, "leave-notify-event", + G_CALLBACK(leave_notify_event_cb), self); + GtkGesture* zoom = gtk_gesture_zoom_new(self->event_box); + g_signal_connect_swapped(zoom, "begin", G_CALLBACK(gesture_zoom_begin_cb), + self); + g_signal_connect_swapped(zoom, "scale-changed", + G_CALLBACK(gesture_zoom_update_cb), self); + g_signal_connect_swapped(zoom, "end", G_CALLBACK(gesture_zoom_end_cb), self); + GtkGesture* rotate = gtk_gesture_rotate_new(self->event_box); + g_signal_connect_swapped(rotate, "begin", + G_CALLBACK(gesture_rotation_begin_cb), self); + g_signal_connect_swapped(rotate, "angle-changed", + G_CALLBACK(gesture_rotation_update_cb), self); + g_signal_connect_swapped(rotate, "end", G_CALLBACK(gesture_rotation_end_cb), + self); + + self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); + gtk_widget_show(GTK_WIDGET(self->gl_area)); + gtk_container_add(GTK_CONTAINER(self->event_box), GTK_WIDGET(self->gl_area)); + + g_signal_connect_swapped(self->gl_area, "create-context", + G_CALLBACK(create_context_cb), self); + g_signal_connect_swapped(self->gl_area, "realize", G_CALLBACK(realize_cb), + self); + g_signal_connect_swapped(self->gl_area, "render", G_CALLBACK(render_cb), + self); + g_signal_connect_swapped(self->gl_area, "unrealize", G_CALLBACK(unrealize_cb), + self); + + g_signal_connect_swapped(self, "size-allocate", G_CALLBACK(size_allocate_cb), + self); } G_MODULE_EXPORT FlView* fl_view_new(FlDartProject* project) { From 1625590bf1e07d39364d05ebf3aae71631b18df7 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 21 Feb 2024 17:05:29 +1300 Subject: [PATCH 4/9] Add link to platform view support issue --- shell/platform/linux/fl_renderer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index 98ce1a3e56ecb..ec35b14d2e670 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -255,7 +255,8 @@ gboolean fl_renderer_present_layers(FlRenderer* self, g_ptr_array_add(priv->textures, g_object_ref(provider)); } break; case kFlutterLayerContentTypePlatformView: { - // Currently unsupported. + // TODO(robert-ancell) Not implemented - + // https://github.com/flutter/flutter/issues/41724 } break; } } From 5d7ca6edf1cac4d65f6e8eedfaa8972cbb71ad21 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 21 Feb 2024 17:13:09 +1300 Subject: [PATCH 5/9] Drop explicitly setting use_es - this doesn't seem to be necessary and was having issues in the GTK4 branch --- shell/platform/linux/fl_renderer_gdk.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell/platform/linux/fl_renderer_gdk.cc b/shell/platform/linux/fl_renderer_gdk.cc index 90623b4f209cb..f5d4990efcd82 100644 --- a/shell/platform/linux/fl_renderer_gdk.cc +++ b/shell/platform/linux/fl_renderer_gdk.cc @@ -68,7 +68,6 @@ gboolean fl_renderer_gdk_create_contexts(FlRendererGdk* self, GError** error) { if (self->main_context == nullptr) { return FALSE; } - gdk_gl_context_set_use_es(self->main_context, TRUE); if (!gdk_gl_context_realize(self->main_context, error)) { return FALSE; } @@ -77,7 +76,6 @@ gboolean fl_renderer_gdk_create_contexts(FlRendererGdk* self, GError** error) { if (self->resource_context == nullptr) { return FALSE; } - gdk_gl_context_set_use_es(self->resource_context, TRUE); if (!gdk_gl_context_realize(self->resource_context, error)) { return FALSE; } From 829ae5e6dc1d25a1eba2b5b6424451d96839b53c Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 21 Feb 2024 17:14:02 +1300 Subject: [PATCH 6/9] Add note about allocated strings --- shell/platform/linux/fl_renderer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index ec35b14d2e670..c6d20f5a1f308 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -57,7 +57,7 @@ typedef struct { G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT) -// Returns the log for the given OpenGL shader. +// Returns the log for the given OpenGL shader. Must be freed by the caller. static gchar* get_shader_log(GLuint shader) { int log_length; gchar* log; @@ -70,7 +70,7 @@ static gchar* get_shader_log(GLuint shader) { return log; } -// Returns the log for the given OpenGL program. +// Returns the log for the given OpenGL program. Must be freed by the caller. static gchar* get_program_log(GLuint program) { int log_length; gchar* log; From c48a8e004b4e598f50357e4e0d010053d9afb25a Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 22 Feb 2024 09:32:45 +1300 Subject: [PATCH 7/9] Remove fl_gl_area.cc from licenses --- ci/licenses_golden/licenses_flutter | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 2f57729497a20..30754eb29ca03 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -10875,8 +10875,6 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_engine_private.h + ../../../flu ORIGIN: ../../../flutter/shell/platform/linux/fl_engine_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_event_channel.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_event_channel_test.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_gl_area.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_gl_area.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_gnome_settings.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_gnome_settings.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_gnome_settings_test.cc + ../../../flutter/LICENSE @@ -13736,8 +13734,6 @@ FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h FILE: ../../../flutter/shell/platform/linux/fl_engine_test.cc FILE: ../../../flutter/shell/platform/linux/fl_event_channel.cc FILE: ../../../flutter/shell/platform/linux/fl_event_channel_test.cc -FILE: ../../../flutter/shell/platform/linux/fl_gl_area.cc -FILE: ../../../flutter/shell/platform/linux/fl_gl_area.h FILE: ../../../flutter/shell/platform/linux/fl_gnome_settings.cc FILE: ../../../flutter/shell/platform/linux/fl_gnome_settings.h FILE: ../../../flutter/shell/platform/linux/fl_gnome_settings_test.cc From 8e201497409c630dbf596481601cb305b01878cb Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 22 Feb 2024 09:33:35 +1300 Subject: [PATCH 8/9] Fix formatting --- shell/platform/linux/testing/mock_renderer.cc | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/shell/platform/linux/testing/mock_renderer.cc b/shell/platform/linux/testing/mock_renderer.cc index b204bf1016259..91d87b460cf3d 100644 --- a/shell/platform/linux/testing/mock_renderer.cc +++ b/shell/platform/linux/testing/mock_renderer.cc @@ -11,24 +11,19 @@ struct _FlMockRenderer { G_DEFINE_TYPE(FlMockRenderer, fl_mock_renderer, fl_renderer_get_type()) // Implements FlRenderer::make_current. -static void fl_mock_renderer_make_current(FlRenderer *renderer) -{ -} +static void fl_mock_renderer_make_current(FlRenderer* renderer) {} // Implements FlRenderer::make_resource_current. -static void fl_mock_renderer_make_resource_current(FlRenderer *renderer) -{ -} +static void fl_mock_renderer_make_resource_current(FlRenderer* renderer) {} // Implements FlRenderer::clear_current. -static void fl_mock_renderer_clear_current(FlRenderer *renderer) -{ -} +static void fl_mock_renderer_clear_current(FlRenderer* renderer) {} static void fl_mock_renderer_class_init(FlMockRendererClass* klass) { - FL_RENDERER_CLASS(klass)->make_current= fl_mock_renderer_make_current; - FL_RENDERER_CLASS(klass)->make_resource_current= fl_mock_renderer_make_resource_current; - FL_RENDERER_CLASS(klass)->clear_current= fl_mock_renderer_clear_current; + FL_RENDERER_CLASS(klass)->make_current = fl_mock_renderer_make_current; + FL_RENDERER_CLASS(klass)->make_resource_current = + fl_mock_renderer_make_resource_current; + FL_RENDERER_CLASS(klass)->clear_current = fl_mock_renderer_clear_current; } static void fl_mock_renderer_init(FlMockRenderer* self) {} From 446a30b76fe15b7553af393560f09f975f8dff0d Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 29 Feb 2024 17:29:15 +1300 Subject: [PATCH 9/9] Fix formatting --- shell/platform/linux/fl_view.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index c14b23ff426a9..0d1fb4709f703 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -524,8 +524,8 @@ static GdkGLContext* create_context_cb(FlView* self) { self->renderer = fl_renderer_gdk_new(gtk_widget_get_parent_window(GTK_WIDGET(self))); self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer)); - fl_engine_set_update_semantics_handler( - self->engine, update_semantics_cb, self, nullptr); + fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb, + self, nullptr); fl_engine_set_on_pre_engine_restart_handler( self->engine, on_pre_engine_restart_cb, self, nullptr);