diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 9f42b6bd07..187fb9e68a 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc @@ -12,10 +12,12 @@ #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_dart_project_private.h" #include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer.h" #include "flutter/shell/platform/linux/fl_renderer_headless.h" #include "flutter/shell/platform/linux/fl_settings_plugin.h" +#include "flutter/shell/platform/linux/fl_texture_gl_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" @@ -224,18 +226,39 @@ static bool fl_engine_gl_external_texture_frame_callback( int64_t texture_id, size_t width, size_t height, - FlutterOpenGLTexture* texture) { + FlutterOpenGLTexture* opengl_texture) { FlEngine* self = static_cast(user_data); if (!self->texture_registrar) { return false; } + + FlTexture* texture = + fl_texture_registrar_lookup_texture(self->texture_registrar, texture_id); + if (texture == nullptr) { + g_warning("Unable to find texture %" G_GINT64_FORMAT, texture_id); + return false; + } + + gboolean result; g_autoptr(GError) error = nullptr; - gboolean result = fl_texture_registrar_populate_gl_external_texture( - self->texture_registrar, texture_id, width, height, texture, &error); + if (FL_IS_TEXTURE_GL(texture)) { + result = fl_texture_gl_populate(FL_TEXTURE_GL(texture), width, height, + opengl_texture, &error); + } else if (FL_IS_PIXEL_BUFFER_TEXTURE(texture)) { + result = + fl_pixel_buffer_texture_populate(FL_PIXEL_BUFFER_TEXTURE(texture), + width, height, opengl_texture, &error); + } else { + g_warning("Unsupported texture type %" G_GINT64_FORMAT, texture_id); + return false; + } + if (!result) { g_warning("%s", error->message); + return false; } - return result; + + return true; } // Called by the engine to determine if it is on the GTK thread. diff --git a/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc b/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc index 70c6e59cbd..a2a6669a5e 100644 --- a/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc +++ b/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc @@ -13,7 +13,13 @@ #include "flutter/shell/platform/linux/fl_texture_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" -struct _FlTextureRegistrar { +G_DECLARE_FINAL_TYPE(FlTextureRegistrarImpl, + fl_texture_registrar_impl, + FL, + TEXTURE_REGISTRAR_IMPL, + GObject) + +struct _FlTextureRegistrarImpl { GObject parent_instance; // Weak reference to the engine this texture registrar is created for. @@ -27,11 +33,24 @@ struct _FlTextureRegistrar { GHashTable* textures; }; -G_DEFINE_TYPE(FlTextureRegistrar, fl_texture_registrar, G_TYPE_OBJECT) +static void fl_texture_registrar_impl_iface_init( + FlTextureRegistrarInterface* iface); + +G_DEFINE_INTERFACE(FlTextureRegistrar, fl_texture_registrar, G_TYPE_OBJECT) + +G_DEFINE_TYPE_WITH_CODE( + FlTextureRegistrarImpl, + fl_texture_registrar_impl, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_texture_registrar_get_type(), + fl_texture_registrar_impl_iface_init)) + +static void fl_texture_registrar_default_init( + FlTextureRegistrarInterface* iface) {} static void engine_weak_notify_cb(gpointer user_data, GObject* where_the_object_was) { - FlTextureRegistrar* self = FL_TEXTURE_REGISTRAR(user_data); + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(user_data); self->engine = nullptr; // Unregister any textures. @@ -41,8 +60,8 @@ static void engine_weak_notify_cb(gpointer user_data, g_hash_table_remove_all(textures); } -static void fl_texture_registrar_dispose(GObject* object) { - FlTextureRegistrar* self = FL_TEXTURE_REGISTRAR(object); +static void fl_texture_registrar_impl_dispose(GObject* object) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(object); g_clear_pointer(&self->textures, g_hash_table_unref); @@ -51,23 +70,17 @@ static void fl_texture_registrar_dispose(GObject* object) { self->engine = nullptr; } - G_OBJECT_CLASS(fl_texture_registrar_parent_class)->dispose(object); + G_OBJECT_CLASS(fl_texture_registrar_impl_parent_class)->dispose(object); } -static void fl_texture_registrar_class_init(FlTextureRegistrarClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_texture_registrar_dispose; +static void fl_texture_registrar_impl_class_init( + FlTextureRegistrarImplClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_texture_registrar_impl_dispose; } -static void fl_texture_registrar_init(FlTextureRegistrar* self) { - self->textures = g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, - g_object_unref); -} - -G_MODULE_EXPORT gboolean -fl_texture_registrar_register_texture(FlTextureRegistrar* self, - FlTexture* texture) { - g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); - g_return_val_if_fail(FL_IS_TEXTURE(texture), FALSE); +static gboolean register_texture(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); if (FL_IS_TEXTURE_GL(texture) || FL_IS_PIXEL_BUFFER_TEXTURE(texture)) { g_hash_table_insert(self->textures, @@ -86,17 +99,23 @@ fl_texture_registrar_register_texture(FlTextureRegistrar* self, } } -G_MODULE_EXPORT gboolean -fl_texture_registrar_mark_texture_frame_available(FlTextureRegistrar* self, - FlTexture* texture) { - g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); +static FlTexture* lookup_texture(FlTextureRegistrar* registrar, + int64_t texture_id) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); + return reinterpret_cast( + g_hash_table_lookup(self->textures, GINT_TO_POINTER(texture_id))); +} + +static gboolean mark_texture_frame_available(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); if (self->engine == nullptr) { return FALSE; } - if (fl_texture_registrar_get_texture( - self, fl_texture_get_texture_id(texture)) == nullptr) { + if (lookup_texture(registrar, fl_texture_get_texture_id(texture)) == + nullptr) { g_warning("Unregistered texture %p", texture); return FALSE; } @@ -105,36 +124,9 @@ fl_texture_registrar_mark_texture_frame_available(FlTextureRegistrar* self, self->engine, fl_texture_get_texture_id(texture)); } -gboolean fl_texture_registrar_populate_gl_external_texture( - FlTextureRegistrar* self, - int64_t texture_id, - uint32_t width, - uint32_t height, - FlutterOpenGLTexture* opengl_texture, - GError** error) { - FlTexture* texture = fl_texture_registrar_get_texture(self, texture_id); - if (texture == nullptr) { - g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, - "Unable to find texture %" G_GINT64_FORMAT, texture_id); - return FALSE; - } - if (FL_IS_TEXTURE_GL(texture)) { - return fl_texture_gl_populate(FL_TEXTURE_GL(texture), width, height, - opengl_texture, error); - } else if (FL_IS_PIXEL_BUFFER_TEXTURE(texture)) { - return fl_pixel_buffer_texture_populate( - FL_PIXEL_BUFFER_TEXTURE(texture), width, height, opengl_texture, error); - } else { - g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, - "Unsupported texture type %" G_GINT64_FORMAT, texture_id); - return FALSE; - } -} - -G_MODULE_EXPORT gboolean -fl_texture_registrar_unregister_texture(FlTextureRegistrar* self, - FlTexture* texture) { - g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); +static gboolean unregister_texture(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); if (!g_hash_table_remove( self->textures, @@ -151,18 +143,62 @@ fl_texture_registrar_unregister_texture(FlTextureRegistrar* self, self->engine, fl_texture_get_texture_id(texture)); } -FlTexture* fl_texture_registrar_get_texture(FlTextureRegistrar* registrar, - int64_t texture_id) { - return reinterpret_cast( - g_hash_table_lookup(registrar->textures, GINT_TO_POINTER(texture_id))); +static void fl_texture_registrar_impl_iface_init( + FlTextureRegistrarInterface* iface) { + iface->register_texture = register_texture; + iface->lookup_texture = lookup_texture; + iface->mark_texture_frame_available = mark_texture_frame_available; + iface->unregister_texture = unregister_texture; +} + +static void fl_texture_registrar_impl_init(FlTextureRegistrarImpl* self) { + self->textures = g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, + g_object_unref); +} + +G_MODULE_EXPORT gboolean +fl_texture_registrar_register_texture(FlTextureRegistrar* self, + FlTexture* texture) { + g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); + g_return_val_if_fail(FL_IS_TEXTURE(texture), FALSE); + + return FL_TEXTURE_REGISTRAR_GET_IFACE(self)->register_texture(self, texture); +} + +FlTexture* fl_texture_registrar_lookup_texture(FlTextureRegistrar* self, + int64_t texture_id) { + g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), NULL); + + return FL_TEXTURE_REGISTRAR_GET_IFACE(self)->lookup_texture(self, texture_id); +} + +G_MODULE_EXPORT gboolean +fl_texture_registrar_mark_texture_frame_available(FlTextureRegistrar* self, + FlTexture* texture) { + g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); + + return FL_TEXTURE_REGISTRAR_GET_IFACE(self)->mark_texture_frame_available( + self, texture); +} + +G_MODULE_EXPORT gboolean +fl_texture_registrar_unregister_texture(FlTextureRegistrar* self, + FlTexture* texture) { + g_return_val_if_fail(FL_IS_TEXTURE_REGISTRAR(self), FALSE); + + return FL_TEXTURE_REGISTRAR_GET_IFACE(self)->unregister_texture(self, + texture); } FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine) { - FlTextureRegistrar* self = FL_TEXTURE_REGISTRAR( - g_object_new(fl_texture_registrar_get_type(), nullptr)); + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL( + g_object_new(fl_texture_registrar_impl_get_type(), nullptr)); + + // Added to stop compiler complaining about an unused function. + FL_IS_TEXTURE_REGISTRAR_IMPL(self); self->engine = engine; g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, self); - return self; + return FL_TEXTURE_REGISTRAR(self); } diff --git a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h index b4ea9b2119..3f1e69b7fe 100644 --- a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h @@ -22,38 +22,16 @@ G_BEGIN_DECLS FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine); /** - * fl_texture_registrar_populate_gl_external_texture: - * @registrar: an #FlTextureRegistrar. - * @texture_id: ID of texture. - * @width: width of the texture. - * @height: height of the texture. - * @opengl_texture: (out): return an #FlutterOpenGLTexture. - * @error: (allow-none): #GError location to store the error occurring, or - * %NULL to ignore. - * - * Attempts to populate the given @texture_id. - * - * Returns: %TRUE on success. - */ -gboolean fl_texture_registrar_populate_gl_external_texture( - FlTextureRegistrar* registrar, - int64_t texture_id, - uint32_t width, - uint32_t height, - FlutterOpenGLTexture* opengl_texture, - GError** error); - -/** - * fl_texture_registrar_get_texture: + * fl_texture_registrar_lookup_texture: * @registrar: an #FlTextureRegistrar. * @texture_id: ID of texture. * - * Gets a registered texture by @texture_id. + * Looks for the texture with the given ID. * - * Returns: an #FlTexture, or %NULL if not found. + * Returns: an #FlTexture or %NULL if no texture with this ID. */ -FlTexture* fl_texture_registrar_get_texture(FlTextureRegistrar* registrar, - int64_t texture_id); +FlTexture* fl_texture_registrar_lookup_texture(FlTextureRegistrar* registrar, + int64_t texture_id); G_END_DECLS diff --git a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_test.cc b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_test.cc index 6d9845ee59..0a81236965 100644 --- a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_test.cc @@ -19,6 +19,97 @@ static constexpr uint32_t BUFFER_HEIGHT = 4u; static constexpr uint32_t REAL_BUFFER_WIDTH = 2u; static constexpr uint32_t REAL_BUFFER_HEIGHT = 2u; +G_DECLARE_FINAL_TYPE(FlMockTextureRegistrar, + fl_mock_texture_registrar, + FL, + MOCK_TEXTURE_REGISTRAR, + GObject) + +struct _FlMockTextureRegistrar { + GObject parent_instance; + FlTexture* texture; + gboolean frame_available; +}; + +static void fl_mock_texture_registrar_iface_init( + FlTextureRegistrarInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockTextureRegistrar, + fl_mock_texture_registrar, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_texture_registrar_get_type(), + fl_mock_texture_registrar_iface_init)) + +static void fl_mock_texture_registrar_dispose(GObject* object) { + FlMockTextureRegistrar* self = FL_MOCK_TEXTURE_REGISTRAR(object); + g_clear_object(&self->texture); + G_OBJECT_CLASS(fl_mock_texture_registrar_parent_class)->dispose(object); +} + +static void fl_mock_texture_registrar_class_init( + FlMockTextureRegistrarClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_mock_texture_registrar_dispose; +} + +static gboolean register_texture(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlMockTextureRegistrar* self = FL_MOCK_TEXTURE_REGISTRAR(registrar); + if (self->texture != nullptr) { + return FALSE; + } + self->texture = FL_TEXTURE(g_object_ref(texture)); + return TRUE; +} + +static FlTexture* lookup_texture(FlTextureRegistrar* registrar, + int64_t texture_id) { + FlMockTextureRegistrar* self = FL_MOCK_TEXTURE_REGISTRAR(registrar); + if (self->texture != nullptr && + fl_texture_get_texture_id(self->texture) == texture_id) { + return self->texture; + } + return nullptr; +} + +static gboolean mark_texture_frame_available(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlMockTextureRegistrar* self = FL_MOCK_TEXTURE_REGISTRAR(registrar); + if (lookup_texture(registrar, fl_texture_get_texture_id(texture)) == + nullptr) { + return FALSE; + } + self->frame_available = TRUE; + return TRUE; +} + +static gboolean unregister_texture(FlTextureRegistrar* registrar, + FlTexture* texture) { + FlMockTextureRegistrar* self = FL_MOCK_TEXTURE_REGISTRAR(registrar); + if (self->texture != texture) { + return FALSE; + } + + g_clear_object(&self->texture); + + return TRUE; +} + +static void fl_mock_texture_registrar_iface_init( + FlTextureRegistrarInterface* iface) { + iface->register_texture = register_texture; + iface->lookup_texture = lookup_texture; + iface->mark_texture_frame_available = mark_texture_frame_available; + iface->unregister_texture = unregister_texture; +} + +static void fl_mock_texture_registrar_init(FlMockTextureRegistrar* self) {} + +static FlMockTextureRegistrar* fl_mock_texture_registrar_new() { + return FL_MOCK_TEXTURE_REGISTRAR( + g_object_new(fl_mock_texture_registrar_get_type(), nullptr)); +} + G_DECLARE_FINAL_TYPE(FlTestRegistrarTexture, fl_test_registrar_texture, FL, @@ -64,6 +155,27 @@ static FlTestRegistrarTexture* fl_test_registrar_texture_new() { g_object_new(fl_test_registrar_texture_get_type(), nullptr)); } +// Checks can make a mock registrar. +TEST(FlTextureRegistrarTest, MockRegistrar) { + g_autoptr(FlTexture) texture = FL_TEXTURE(fl_test_registrar_texture_new()); + g_autoptr(FlMockTextureRegistrar) registrar = fl_mock_texture_registrar_new(); + EXPECT_TRUE(FL_IS_MOCK_TEXTURE_REGISTRAR(registrar)); + + EXPECT_TRUE(fl_texture_registrar_register_texture( + FL_TEXTURE_REGISTRAR(registrar), texture)); + EXPECT_EQ(registrar->texture, texture); + EXPECT_EQ( + fl_texture_registrar_lookup_texture(FL_TEXTURE_REGISTRAR(registrar), + fl_texture_get_texture_id(texture)), + texture); + EXPECT_TRUE(fl_texture_registrar_mark_texture_frame_available( + FL_TEXTURE_REGISTRAR(registrar), texture)); + EXPECT_TRUE(registrar->frame_available); + EXPECT_TRUE(fl_texture_registrar_unregister_texture( + FL_TEXTURE_REGISTRAR(registrar), texture)); + EXPECT_EQ(registrar->texture, nullptr); +} + // Test that registering a texture works. TEST(FlTextureRegistrarTest, RegisterTexture) { g_autoptr(FlEngine) engine = make_mock_engine(); @@ -87,19 +199,3 @@ TEST(FlTextureRegistrarTest, MarkTextureFrameAvailable) { EXPECT_TRUE( fl_texture_registrar_mark_texture_frame_available(registrar, texture)); } - -// Test that populating an OpenGL texture works. -TEST(FlTextureRegistrarTest, PopulateTexture) { - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlTextureRegistrar) registrar = fl_texture_registrar_new(engine); - g_autoptr(FlTexture) texture = FL_TEXTURE(fl_test_registrar_texture_new()); - EXPECT_TRUE(fl_texture_registrar_register_texture(registrar, texture)); - FlutterOpenGLTexture opengl_texture; - g_autoptr(GError) error = nullptr; - EXPECT_TRUE(fl_texture_registrar_populate_gl_external_texture( - registrar, fl_texture_get_texture_id(texture), BUFFER_WIDTH, - BUFFER_HEIGHT, &opengl_texture, &error)); - EXPECT_EQ(error, nullptr); - EXPECT_EQ(opengl_texture.width, REAL_BUFFER_WIDTH); - EXPECT_EQ(opengl_texture.height, REAL_BUFFER_HEIGHT); -} diff --git a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h index b978559a80..1c03cdc3ec 100644 --- a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h +++ b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h @@ -16,11 +16,26 @@ G_BEGIN_DECLS -G_DECLARE_FINAL_TYPE(FlTextureRegistrar, - fl_texture_registrar, - FL, - TEXTURE_REGISTRAR, - GObject) +G_DECLARE_INTERFACE(FlTextureRegistrar, + fl_texture_registrar, + FL, + TEXTURE_REGISTRAR, + GObject) + +struct _FlTextureRegistrarInterface { + GTypeInterface parent_iface; + + gboolean (*register_texture)(FlTextureRegistrar* registrar, + FlTexture* texture); + + FlTexture* (*lookup_texture)(FlTextureRegistrar* registrar, int64_t id); + + gboolean (*mark_texture_frame_available)(FlTextureRegistrar* registrar, + FlTexture* texture); + + gboolean (*unregister_texture)(FlTextureRegistrar* registrar, + FlTexture* texture); +}; /** * FlTextureRegistrar: