Make an interface for FlTextureRegistrar

This commit is contained in:
Robert Ancell
2021-10-19 12:16:18 +13:00
committed by Robert Ancell
parent e4951d8895
commit 1730ca3fee
5 changed files with 261 additions and 113 deletions

View File

@@ -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<FlEngine*>(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.

View File

@@ -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<FlTexture*>(
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<FlTexture*>(
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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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: