From 05b183dfe333a92e3bb025fad82c6294b62e4bf7 Mon Sep 17 00:00:00 2001 From: anirudhb Date: Sat, 22 Aug 2020 15:09:33 -0700 Subject: [PATCH 1/8] Linux texture support --- shell/platform/linux/BUILD.gn | 3 + shell/platform/linux/fl_engine.cc | 47 ++++++- shell/platform/linux/fl_engine_private.h | 35 +++++ .../platform/linux/fl_external_texture_gl.cc | 131 ++++++++++++++++++ shell/platform/linux/fl_external_texture_gl.h | 85 ++++++++++++ shell/platform/linux/fl_plugin_registrar.cc | 18 ++- .../linux/fl_plugin_registrar_private.h | 7 +- shell/platform/linux/fl_texture_registrar.cc | 93 +++++++++++++ .../linux/fl_texture_registrar_private.h | 46 ++++++ shell/platform/linux/fl_view.cc | 3 +- .../linux/public/flutter_linux/fl_engine.h | 11 ++ .../flutter_linux/fl_plugin_registrar.h | 11 ++ .../flutter_linux/fl_texture_registrar.h | 84 +++++++++++ .../public/flutter_linux/flutter_linux.h | 1 + shell/platform/linux/testing/mock_engine.cc | 18 +++ 15 files changed, 587 insertions(+), 6 deletions(-) create mode 100644 shell/platform/linux/fl_external_texture_gl.cc create mode 100644 shell/platform/linux/fl_external_texture_gl.h create mode 100644 shell/platform/linux/fl_texture_registrar.cc create mode 100644 shell/platform/linux/fl_texture_registrar_private.h create mode 100644 shell/platform/linux/public/flutter_linux/fl_texture_registrar.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index efad5e89d868e..f6e49a65633ee 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -59,6 +59,7 @@ _public_headers = [ "public/flutter_linux/fl_standard_message_codec.h", "public/flutter_linux/fl_standard_method_codec.h", "public/flutter_linux/fl_string_codec.h", + "public/flutter_linux/fl_texture_registrar.h", "public/flutter_linux/fl_value.h", "public/flutter_linux/fl_view.h", "public/flutter_linux/flutter_linux.h", @@ -80,6 +81,7 @@ source_set("flutter_linux_sources") { "fl_binary_messenger.cc", "fl_dart_project.cc", "fl_engine.cc", + "fl_external_texture_gl.cc", "fl_json_message_codec.cc", "fl_json_method_codec.cc", "fl_key_event_plugin.cc", @@ -99,6 +101,7 @@ source_set("flutter_linux_sources") { "fl_standard_method_codec.cc", "fl_string_codec.cc", "fl_text_input_plugin.cc", + "fl_texture_registrar.cc", "fl_value.cc", "fl_view.cc", ] diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index eb952a30a52a3..4f687a78ae6cd 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -3,12 +3,14 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_binary_messenger_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_texture_registrar_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" #include @@ -27,6 +29,7 @@ struct _FlEngine { FlDartProject* project; FlRenderer* renderer; FlBinaryMessenger* binary_messenger; + FlTextureRegistrar* texture_registrar; FlutterEngineAOTData aot_data; FLUTTER_API_SYMBOL(FlutterEngine) engine; @@ -210,6 +213,20 @@ static bool fl_engine_gl_make_resource_current(void* user_data) { return result; } +static bool fl_engine_gl_external_texture_frame_callback( + void* user_data, + int64_t texture_id, + size_t width, + size_t height, + FlutterOpenGLTexture* texture) { + FlEngine* self = static_cast(user_data); + if (!self->texture_registrar) { + return false; + } + return fl_texture_registrar_populate_texture( + self->texture_registrar, texture_id, width, height, texture); +} + // Called by the engine to determine if it is on the GTK thread. static bool fl_engine_runs_task_on_current_thread(void* user_data) { FlEngine* self = static_cast(user_data); @@ -268,7 +285,8 @@ static FlPluginRegistrar* fl_engine_get_registrar_for_plugin( const gchar* name) { FlEngine* self = FL_ENGINE(registry); - return fl_plugin_registrar_new(nullptr, self->binary_messenger); + return fl_plugin_registrar_new(nullptr, self->binary_messenger, + self->texture_registrar); } static void fl_engine_plugin_registry_iface_init( @@ -291,6 +309,7 @@ static void fl_engine_dispose(GObject* object) { g_clear_object(&self->project); g_clear_object(&self->renderer); + g_clear_object(&self->texture_registrar); g_clear_object(&self->binary_messenger); if (self->platform_message_handler_destroy_notify) { @@ -310,6 +329,7 @@ static void fl_engine_class_init(FlEngineClass* klass) { static void fl_engine_init(FlEngine* self) { self->thread = g_thread_self(); + self->texture_registrar = fl_texture_registrar_new(self); self->binary_messenger = fl_binary_messenger_new(self); } @@ -340,6 +360,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { config.open_gl.fbo_callback = fl_engine_gl_get_fbo; config.open_gl.present = fl_engine_gl_present; config.open_gl.make_resource_current = fl_engine_gl_make_resource_current; + config.open_gl.gl_external_texture_frame_callback = + fl_engine_gl_external_texture_frame_callback; FlutterTaskRunnerDescription platform_task_runner = {}; platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); @@ -571,8 +593,31 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, FlutterEngineSendPointerEvent(self->engine, &fl_event, 1); } +bool fl_engine_mark_texture_frame_available(FlEngine* self, + int64_t texture_id) { + g_return_val_if_fail(FL_IS_ENGINE(self), false); + return !FlutterEngineMarkExternalTextureFrameAvailable(self->engine, + texture_id); +} + +bool fl_engine_register_external_texture(FlEngine* self, int64_t texture_id) { + g_return_val_if_fail(FL_IS_ENGINE(self), false); + return !FlutterEngineRegisterExternalTexture(self->engine, texture_id); +} + +void fl_engine_unregister_external_texture(FlEngine* self, int64_t texture_id) { + g_return_if_fail(FL_IS_ENGINE(self)); + FlutterEngineUnregisterExternalTexture(self->engine, texture_id); +} + G_MODULE_EXPORT FlBinaryMessenger* fl_engine_get_binary_messenger( FlEngine* self) { g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); return self->binary_messenger; } + +G_MODULE_EXPORT FlTextureRegistrar* fl_engine_get_texture_registrar( + FlEngine* self) { + g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); + return self->texture_registrar; +} diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 6c912979ba16c..e399f1ef33479 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -175,6 +175,41 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, GAsyncResult* result, GError** error); +/** + * fl_engine_mark_texture_frame_available: + * @engine: an #FlEngine. + * @texture_id: an int64_t. + * + * Tells the Flutter engine that a new texture frame is available for the given + * texture. + * + * Returns: true on success. + */ +bool fl_engine_mark_texture_frame_available(FlEngine* engine, + int64_t texture_id); + +/** + * fl_engine_register_external_texture: + * @engine: an #FlEngine. + * @texture_id: an int64_t. + * + * Tells the Flutter engine that a new external texture is available. + * + * Returns: true on success. + */ +bool fl_engine_register_external_texture(FlEngine* engine, int64_t texture_id); + +/** + * fl_engine_unregister_external_texture: + * @engine: an #FlEngine. + * @texture_id: an int64_t. + * + * Tells the Flutter engine that an existing external texture is not available + * anymore. + */ +void fl_engine_unregister_external_texture(FlEngine* engine, + int64_t texture_id); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_ diff --git a/shell/platform/linux/fl_external_texture_gl.cc b/shell/platform/linux/fl_external_texture_gl.cc new file mode 100644 index 0000000000000..675097a3e4d91 --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -0,0 +1,131 @@ +// Copyright 2020 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_external_texture_gl.h" + +#include +#include +#include + +struct _FlExternalTextureGl { + GLuint gl_texture_id; + FlTextureCallback callback; + struct { + bool valid; + void (*genTextures)(GLsizei n, GLuint* textures); + void (*bindTexture)(GLenum target, GLuint texture); + void (*texParameteri)(GLenum target, GLenum pname, GLenum param); + void (*texImage2D)(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* data); + void (*deleteTextures)(GLsizei n, const GLuint* textures); + } gl; + void* user_data; +}; + +G_DEFINE_TYPE(FlExternalTextureGl, fl_external_texture_gl, G_TYPE_OBJECT) + +static void fl_external_texture_gl_dispose(GObject* object) { + FlExternalTextureGl* self = FL_EXTERNAL_TEXTURE_GL(object); + if (self->gl.valid) { + self->gl.deleteTextures(1, &self->gl_texture_id); + } + + G_OBJECT_CLASS(fl_external_texture_gl_parent_class)->dispose(object); +} + +static void fl_external_texture_gl_class_init(FlExternalTextureGlClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_external_texture_gl_dispose; +} + +static void fl_external_texture_gl_init(FlExternalTextureGl* self) {} + +int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self) { + return reinterpret_cast(self); +} + +bool fl_external_texture_gl_populate_texture( + FlExternalTextureGl* self, + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture) { + size_t real_width = width, real_height = height; + if (!fl_external_texture_gl_copy_pixel_buffer(self, &real_width, + &real_height)) + return false; + + opengl_texture->target = GL_TEXTURE_2D; + opengl_texture->name = self->gl_texture_id; + opengl_texture->format = GL_RGBA8; + opengl_texture->destruction_callback = nullptr; + opengl_texture->user_data = static_cast(self); + opengl_texture->width = real_width; + opengl_texture->height = real_height; + + return true; +} + +void fl_external_texture_gl_load_funcs(FlExternalTextureGl* self) { + self->gl.genTextures = reinterpret_cast( + eglGetProcAddress("glGenTextures")); + self->gl.bindTexture = reinterpret_cast( + eglGetProcAddress("glBindTexture")); + self->gl.texParameteri = reinterpret_cast( + eglGetProcAddress("glTexParameteri")); + self->gl.texImage2D = + reinterpret_cast( + eglGetProcAddress("glTexImage2D")); + self->gl.deleteTextures = reinterpret_cast( + eglGetProcAddress("glDeleteTextures")); + self->gl.valid = true; +} + +bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, + size_t* width, + size_t* height) { + const FlPixelBuffer* pixel_buffer = + self->callback(*width, *height, self->user_data); + if (!pixel_buffer || !pixel_buffer->buffer) + return false; + *width = pixel_buffer->width; + *height = pixel_buffer->height; + + if (!self->gl.valid) + fl_external_texture_gl_load_funcs(self); + if (self->gl_texture_id == 0) { + self->gl.genTextures(1, &self->gl_texture_id); + self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_BORDER); + self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_BORDER); + self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + } + self->gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_buffer->width, + pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, + pixel_buffer->buffer); + return true; +} + +FlExternalTextureGl* fl_external_texture_gl_new( + FlTextureCallback texture_callback, + void* user_data) { + FlExternalTextureGl* self = FL_EXTERNAL_TEXTURE_GL( + g_object_new(fl_external_texture_gl_get_type(), nullptr)); + + self->callback = texture_callback; + self->user_data = user_data; + + return self; +} diff --git a/shell/platform/linux/fl_external_texture_gl.h b/shell/platform/linux/fl_external_texture_gl.h new file mode 100644 index 0000000000000..cfbb0499f50ff --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl.h @@ -0,0 +1,85 @@ +// Copyright 2020 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_EXTERNAL_TEXURE_GL_H +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_EXTERNAL_TEXURE_GL_H + +#include +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlExternalTextureGl, + fl_external_texture_gl, + FL, + EXTERNAL_TEXTURE_GL, + GObject) + +/** + * FlExternalTextureGl: + * + * #FlExternalTextureGl is an abstraction over OpenGL textures. + */ + +/** + * fl_external_texture_gl_new: + * @texture_callback: An #FlTextureCallback. + * @user_data: A void*. + * + * Creates a new #FlExternalTextureGl. + * + * Returns: a new #FlExternalTextureGl. + */ +FlExternalTextureGl* fl_external_texture_gl_new( + FlTextureCallback texture_callback, + void* user_data); + +/** + * fl_external_texture_gl_populate_texture: + * @width: a size_t. + * @height: a size_t. + * @opengl_texture: a FlutterOpenGLTexture*. + * + * Attempts to populate the specified |opengl_texture| with texture details + * such as the name, width, height and the pixel format upon successfully + * copying the buffer provided by |texture_callback_|. See + * |fl_external_texture_gl_copy_pixel_buffer|. + * + * Returns true on success or false if the pixel buffer could not be copied. + */ +bool fl_external_texture_gl_populate_texture( + FlExternalTextureGl* self, + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture); + +/** + * fl_external_texture_gl_texture_id: + * + * Retrieves the unique id of this texture. + * + * Returns an int64_t, which is the unique id of this texture. + */ +int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self); + +/** + * fl_external_texture_gl_copy_pixel_buffer: + * @width: a size_t. + * @height: a size_t. + * + * Attempts to copy the pixel buffer returned by |texture_callback_| to + * OpenGL. The |width| and |height| will be set to the actual bounds of the + * copied pixel buffer. + * + * Returns true on success or false if the pixel buffer returned by + * |texture_callback_| was invalid. + */ +bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, + size_t* width, + size_t* height); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_EXTERNAL_TEXURE_GL_H diff --git a/shell/platform/linux/fl_plugin_registrar.cc b/shell/platform/linux/fl_plugin_registrar.cc index 9ca72258b6e73..6be2049510f26 100644 --- a/shell/platform/linux/fl_plugin_registrar.cc +++ b/shell/platform/linux/fl_plugin_registrar.cc @@ -15,6 +15,8 @@ struct _FlPluginRegistrar { // Messenger to communicate on. FlBinaryMessenger* messenger; + + FlTextureRegistrar* texture_registrar; }; // Added here to stop the compiler from optimising this function away. @@ -36,6 +38,7 @@ static void fl_plugin_registrar_dispose(GObject* object) { } g_clear_object(&self->messenger); + g_clear_object(&self->texture_registrar); G_OBJECT_CLASS(fl_plugin_registrar_parent_class)->dispose(object); } @@ -46,8 +49,10 @@ static void fl_plugin_registrar_class_init(FlPluginRegistrarClass* klass) { static void fl_plugin_registrar_init(FlPluginRegistrar* self) {} -FlPluginRegistrar* fl_plugin_registrar_new(FlView* view, - FlBinaryMessenger* messenger) { +FlPluginRegistrar* fl_plugin_registrar_new( + FlView* view, + FlBinaryMessenger* messenger, + FlTextureRegistrar* texture_registrar) { g_return_val_if_fail(view == nullptr || FL_IS_VIEW(view), nullptr); g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); @@ -58,6 +63,8 @@ FlPluginRegistrar* fl_plugin_registrar_new(FlView* view, if (view != nullptr) g_object_weak_ref(G_OBJECT(view), view_weak_notify_cb, self); self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger)); + self->texture_registrar = + FL_TEXTURE_REGISTRAR(g_object_ref(texture_registrar)); return self; } @@ -69,6 +76,13 @@ G_MODULE_EXPORT FlBinaryMessenger* fl_plugin_registrar_get_messenger( return self->messenger; } +G_MODULE_EXPORT FlTextureRegistrar* fl_plugin_registrar_get_texture_registrar( + FlPluginRegistrar* self) { + g_return_val_if_fail(FL_IS_PLUGIN_REGISTRAR(self), nullptr); + + return self->texture_registrar; +} + G_MODULE_EXPORT FlView* fl_plugin_registrar_get_view(FlPluginRegistrar* self) { g_return_val_if_fail(FL_IS_PLUGIN_REGISTRAR(self), nullptr); diff --git a/shell/platform/linux/fl_plugin_registrar_private.h b/shell/platform/linux/fl_plugin_registrar_private.h index 712f32a3d98c3..90e3f8378b197 100644 --- a/shell/platform/linux/fl_plugin_registrar_private.h +++ b/shell/platform/linux/fl_plugin_registrar_private.h @@ -15,13 +15,16 @@ G_BEGIN_DECLS * @view: (allow-none): the #FlView that is being plugged into or %NULL for * headless mode. * @messenger: the #FlBinaryMessenger to communicate with. + * @texture_registrar: The #FlTextureRegistrar to communicate with. * * Creates a new #FlPluginRegistrar. * * Returns: a new #FlPluginRegistrar. */ -FlPluginRegistrar* fl_plugin_registrar_new(FlView* view, - FlBinaryMessenger* messenger); +FlPluginRegistrar* fl_plugin_registrar_new( + FlView* view, + FlBinaryMessenger* messenger, + FlTextureRegistrar* texture_registrar); G_END_DECLS diff --git a/shell/platform/linux/fl_texture_registrar.cc b/shell/platform/linux/fl_texture_registrar.cc new file mode 100644 index 0000000000000..0d7ec7f98d4e4 --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar.cc @@ -0,0 +1,93 @@ +// Copyright 2020 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/public/flutter_linux/fl_texture_registrar.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_external_texture_gl.h" +#include "flutter/shell/platform/linux/fl_texture_registrar_private.h" + +#include + +struct _FlTextureRegistrar { + GObject parent_instance; + + FlEngine* engine; + + GHashTable* textures; +}; + +// Added here to stop the compiler from optimising this function away. +G_MODULE_EXPORT GType fl_texture_registrar_get_type(); + +G_DEFINE_TYPE(FlTextureRegistrar, fl_texture_registrar, G_TYPE_OBJECT) + +static void fl_texture_registrar_dispose(GObject* object) { + FlTextureRegistrar* self = FL_TEXTURE_REGISTRAR(object); + + if (self->textures != nullptr) { + g_hash_table_destroy(self->textures); + self->textures = nullptr; + } + + g_clear_object(&self->engine); + + G_OBJECT_CLASS(fl_texture_registrar_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_init(FlTextureRegistrar* self) { + self->textures = g_hash_table_new(nullptr, nullptr); +} + +G_MODULE_EXPORT int64_t +fl_texture_registrar_register_texture(FlTextureRegistrar* self, + FlTextureCallback texture_callback, + void* user_data) { + FlExternalTextureGl* texture = + fl_external_texture_gl_new(texture_callback, user_data); + int64_t id = fl_external_texture_gl_texture_id(texture); + g_hash_table_insert(self->textures, reinterpret_cast(id), texture); + fl_engine_register_external_texture(self->engine, id); + return id; +} + +G_MODULE_EXPORT void fl_texture_registrar_mark_texture_frame_available( + FlTextureRegistrar* self, + int64_t texture_id) { + fl_engine_mark_texture_frame_available(self->engine, texture_id); +} + +bool fl_texture_registrar_populate_texture( + FlTextureRegistrar* self, + int64_t texture_id, + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture) { + FlExternalTextureGl* texture = FL_EXTERNAL_TEXTURE_GL(g_hash_table_lookup( + self->textures, reinterpret_cast(texture_id))); + if (texture == nullptr) + return false; + return fl_external_texture_gl_populate_texture(texture, width, height, + opengl_texture); +} + +G_MODULE_EXPORT void fl_texture_registrar_unregister_texture( + FlTextureRegistrar* self, + int64_t texture_id) { + g_hash_table_remove(self->textures, reinterpret_cast(texture_id)); + fl_engine_unregister_external_texture(self->engine, texture_id); +} + +FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine) { + FlTextureRegistrar* self = FL_TEXTURE_REGISTRAR( + g_object_new(fl_texture_registrar_get_type(), nullptr)); + + self->engine = FL_ENGINE(g_object_ref(engine)); + + return self; +} diff --git a/shell/platform/linux/fl_texture_registrar_private.h b/shell/platform/linux/fl_texture_registrar_private.h new file mode 100644 index 0000000000000..20c6b9f56b9c3 --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar_private.h @@ -0,0 +1,46 @@ +// Copyright 2020 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_TEXTURE_REGISTRAR_PRIVATE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXTURE_REGISTRAR_PRIVATE_H_ + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h" + +G_BEGIN_DECLS + +/** + * fl_texture_registrar_new: + * @engine: An #FlEngine. + * + * Creates a new #FlTextureRegistrar. + * + * Returns: a new #FlTextureRegistrar. + */ +FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine); + +/** + * fl_texture_registrar_populate_texture: + * @registrar: an #FlTextureRegistrar. + * @texture_id: an int64_t. + * @width: a size_t. + * @height: a size_t. + * @opengl_texture: an FlutterOpenGLTexture*. + * + * Attempts to populate the given |texture| by copying the contents of the + * texture identified by |texture_id|. + * + * Returns true on success. + */ +bool fl_texture_registrar_populate_texture( + FlTextureRegistrar* registrar, + int64_t texture_id, + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXTURE_REGISTRAR_PRIVATE_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 473df507acea5..bded9bdddde15 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -120,7 +120,8 @@ static FlPluginRegistrar* fl_view_get_registrar_for_plugin( FlView* self = FL_VIEW(registry); return fl_plugin_registrar_new(self, - fl_engine_get_binary_messenger(self->engine)); + fl_engine_get_binary_messenger(self->engine), + fl_engine_get_texture_registrar(self->engine)); } static void fl_view_plugin_registry_iface_init( diff --git a/shell/platform/linux/public/flutter_linux/fl_engine.h b/shell/platform/linux/public/flutter_linux/fl_engine.h index 201c38f4a06d2..6740c0bd8cd81 100644 --- a/shell/platform/linux/public/flutter_linux/fl_engine.h +++ b/shell/platform/linux/public/flutter_linux/fl_engine.h @@ -13,6 +13,7 @@ #include "fl_binary_messenger.h" #include "fl_dart_project.h" +#include "fl_texture_registrar.h" G_BEGIN_DECLS @@ -44,6 +45,16 @@ FlEngine* fl_engine_new_headless(FlDartProject* project); */ FlBinaryMessenger* fl_engine_get_binary_messenger(FlEngine* engine); +/** + * fl_engine_get_texture_registrar: + * @engine: an #FlEngine. + * + * Gets the texture registrar for registering textures. + * + * Returns: an #FlTextureRegistrar. + */ +FlTextureRegistrar* fl_engine_get_texture_registrar(FlEngine* engine); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_H_ diff --git a/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h b/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h index 1d5dc14db9299..11fa238089337 100644 --- a/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h +++ b/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h @@ -38,6 +38,17 @@ G_DECLARE_FINAL_TYPE(FlPluginRegistrar, FlBinaryMessenger* fl_plugin_registrar_get_messenger( FlPluginRegistrar* registrar); +/** + * fl_plugin_registrar_get_texture_registrar: + * @registrar: an #FlPluginRegistrar. + * + * Gets the texture registrar this plugin can communicate with. + * + * Returns: an #FlTextureRegistrar. + */ +FlTextureRegistrar* fl_plugin_registrar_get_texture_registrar( + FlPluginRegistrar* registrar); + /** * fl_plugin_registrar_get_view: * @registrar: an #FlPluginRegistrar. diff --git a/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h b/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h new file mode 100644 index 0000000000000..15746d32caffe --- /dev/null +++ b/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h @@ -0,0 +1,84 @@ +// Copyright 2020 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_TEXTURE_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXTURE_REGISTRAR_H_ + +#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +/** + * An image buffer object. + */ +typedef struct { + const uint8_t* buffer; + size_t width; + size_t height; +} FlPixelBuffer; + +/** + * The pixel buffer copy callback provided to the Flutter engine to copy the + * texture. + */ +typedef const FlPixelBuffer* (*FlTextureCallback)(size_t width, + size_t height, + void* user_data); + +G_DECLARE_FINAL_TYPE(FlTextureRegistrar, + fl_texture_registrar, + FL, + TEXTURE_REGISTRAR, + GObject) + +/** + * FlTextureRegistrar: + * + * #FlTextureRegistrar is used when registering textures. + */ + +/** + * fl_texture_registrar_register_texture: + * @registrar: an #FlTextureRegistrar. + * @texture: an #FlTexture. + * + * Registers a texture callback and returns the ID for that texture. + * + * Returns: an int64_t. + */ +int64_t fl_texture_registrar_register_texture( + FlTextureRegistrar* registrar, + FlTextureCallback texture_callback, + void* user_data); + +/** + * fl_texture_registrar_mark_texture_frame_available: + * @registrar: an #FlTextureRegistrar. + * @texture_id: an int64_t. + * + * Notifies the flutter engine that the texture object corresponding + * to texture_id needs to render a new texture. + */ +void fl_texture_registrar_mark_texture_frame_available( + FlTextureRegistrar* registrar, + int64_t texture_id); + +/** + * fl_texture_registrar_unregister_texture: + * @registrar: an #FlTextureRegistrar. + * @texture_id: an int64_t. + * + * Unregisters an existing texture object. + */ +void fl_texture_registrar_unregister_texture(FlTextureRegistrar* registrar, + int64_t texture_id); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXTURE_REGISTRAR_H_ diff --git a/shell/platform/linux/public/flutter_linux/flutter_linux.h b/shell/platform/linux/public/flutter_linux/flutter_linux.h index aeaef59aead42..9479c83a2f19f 100644 --- a/shell/platform/linux/public/flutter_linux/flutter_linux.h +++ b/shell/platform/linux/public/flutter_linux/flutter_linux.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index f82394bdd4ca3..31a46ee2b6e32 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -389,3 +389,21 @@ FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) size_t locales_count) { return kSuccess; } + +FlutterEngineResult FlutterEngineRegisterExternalTexture( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier) { + return kSuccess; +} + +FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier) { + return kSuccess; +} + +FlutterEngineResult FlutterEngineUnregisterExternalTexture( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier) { + return kSuccess; +} From 1b7722843edb73cd0dee7697741cbdcfa66cb315 Mon Sep 17 00:00:00 2001 From: anirudhb Date: Sat, 22 Aug 2020 17:08:52 -0700 Subject: [PATCH 2/8] Fix clang-tidy errors --- shell/platform/linux/fl_external_texture_gl.cc | 9 ++++++--- shell/platform/linux/fl_texture_registrar.cc | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/shell/platform/linux/fl_external_texture_gl.cc b/shell/platform/linux/fl_external_texture_gl.cc index 675097a3e4d91..688522ae7faf5 100644 --- a/shell/platform/linux/fl_external_texture_gl.cc +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -58,8 +58,9 @@ bool fl_external_texture_gl_populate_texture( FlutterOpenGLTexture* opengl_texture) { size_t real_width = width, real_height = height; if (!fl_external_texture_gl_copy_pixel_buffer(self, &real_width, - &real_height)) + &real_height)) { return false; + } opengl_texture->target = GL_TEXTURE_2D; opengl_texture->name = self->gl_texture_id; @@ -93,13 +94,15 @@ bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, size_t* height) { const FlPixelBuffer* pixel_buffer = self->callback(*width, *height, self->user_data); - if (!pixel_buffer || !pixel_buffer->buffer) + if (!pixel_buffer || !pixel_buffer->buffer) { return false; + } *width = pixel_buffer->width; *height = pixel_buffer->height; - if (!self->gl.valid) + if (!self->gl.valid) { fl_external_texture_gl_load_funcs(self); + } if (self->gl_texture_id == 0) { self->gl.genTextures(1, &self->gl_texture_id); self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); diff --git a/shell/platform/linux/fl_texture_registrar.cc b/shell/platform/linux/fl_texture_registrar.cc index 0d7ec7f98d4e4..2c1a8c8c9695a 100644 --- a/shell/platform/linux/fl_texture_registrar.cc +++ b/shell/platform/linux/fl_texture_registrar.cc @@ -70,8 +70,9 @@ bool fl_texture_registrar_populate_texture( FlutterOpenGLTexture* opengl_texture) { FlExternalTextureGl* texture = FL_EXTERNAL_TEXTURE_GL(g_hash_table_lookup( self->textures, reinterpret_cast(texture_id))); - if (texture == nullptr) + if (texture == nullptr) { return false; + } return fl_external_texture_gl_populate_texture(texture, width, height, opengl_texture); } From 013cd2a9b2bce00b5ba0b8a6ede591f8ea87befe Mon Sep 17 00:00:00 2001 From: anirudhb Date: Wed, 26 Aug 2020 17:40:20 -0700 Subject: [PATCH 3/8] Tests (partial) Also addresses nits from code review. Testing will be complete once I figure out how to stub `eglGetProcAddress` in the tests. --- shell/platform/linux/BUILD.gn | 1 + .../linux/fl_binary_messenger_test.cc | 15 +--- shell/platform/linux/fl_engine.cc | 9 ++- .../platform/linux/fl_external_texture_gl.cc | 75 +++++++++---------- shell/platform/linux/fl_external_texture_gl.h | 1 + shell/platform/linux/fl_texture_registrar.cc | 5 +- .../linux/fl_texture_registrar_test.cc | 72 ++++++++++++++++++ shell/platform/linux/testing/fl_test.cc | 20 +++++ shell/platform/linux/testing/fl_test.h | 5 ++ shell/platform/linux/testing/mock_engine.cc | 16 ++++ 10 files changed, 161 insertions(+), 58 deletions(-) create mode 100644 shell/platform/linux/fl_texture_registrar_test.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index f6e49a65633ee..1e844adf0bf4c 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -150,6 +150,7 @@ executable("flutter_linux_unittests") { "fl_standard_message_codec_test.cc", "fl_standard_method_codec_test.cc", "fl_string_codec_test.cc", + "fl_texture_registrar_test.cc", "fl_value_test.cc", "testing/fl_test.cc", "testing/mock_egl.cc", diff --git a/shell/platform/linux/fl_binary_messenger_test.cc b/shell/platform/linux/fl_binary_messenger_test.cc index bb0d7ff3666ca..c443e4d39fa99 100644 --- a/shell/platform/linux/fl_binary_messenger_test.cc +++ b/shell/platform/linux/fl_binary_messenger_test.cc @@ -6,21 +6,8 @@ #include "gtest/gtest.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/testing/mock_renderer.h" - -// Creates a mock engine that responds to platform messages. -static FlEngine* make_mock_engine() { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); - g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer)); - g_autoptr(GError) engine_error = nullptr; - EXPECT_TRUE(fl_engine_start(engine, &engine_error)); - EXPECT_EQ(engine_error, nullptr); - - return static_cast(g_object_ref(engine)); -} +#include "flutter/shell/platform/linux/testing/fl_test.h" // Checks sending nullptr for a message works. TEST(FlBinaryMessengerTest, SendNullptrMessage) { diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 4f687a78ae6cd..c837e0a6dd92f 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -3,9 +3,9 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" -#include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer.h" @@ -596,13 +596,14 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, bool fl_engine_mark_texture_frame_available(FlEngine* self, int64_t texture_id) { g_return_val_if_fail(FL_IS_ENGINE(self), false); - return !FlutterEngineMarkExternalTextureFrameAvailable(self->engine, - texture_id); + return FlutterEngineMarkExternalTextureFrameAvailable(self->engine, + texture_id) == kSuccess; } bool fl_engine_register_external_texture(FlEngine* self, int64_t texture_id) { g_return_val_if_fail(FL_IS_ENGINE(self), false); - return !FlutterEngineRegisterExternalTexture(self->engine, texture_id); + return FlutterEngineRegisterExternalTexture(self->engine, texture_id) == + kSuccess; } void fl_engine_unregister_external_texture(FlEngine* self, int64_t texture_id) { diff --git a/shell/platform/linux/fl_external_texture_gl.cc b/shell/platform/linux/fl_external_texture_gl.cc index 688522ae7faf5..0ad818f4bc1df 100644 --- a/shell/platform/linux/fl_external_texture_gl.cc +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -8,25 +8,26 @@ #include #include +struct { + bool valid; + void (*genTextures)(GLsizei n, GLuint* textures); + void (*bindTexture)(GLenum target, GLuint texture); + void (*texParameteri)(GLenum target, GLenum pname, GLenum param); + void (*texImage2D)(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* data); + void (*deleteTextures)(GLsizei n, const GLuint* textures); +} gl; + struct _FlExternalTextureGl { GLuint gl_texture_id; FlTextureCallback callback; - struct { - bool valid; - void (*genTextures)(GLsizei n, GLuint* textures); - void (*bindTexture)(GLenum target, GLuint texture); - void (*texParameteri)(GLenum target, GLenum pname, GLenum param); - void (*texImage2D)(GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* data); - void (*deleteTextures)(GLsizei n, const GLuint* textures); - } gl; void* user_data; }; @@ -34,8 +35,8 @@ G_DEFINE_TYPE(FlExternalTextureGl, fl_external_texture_gl, G_TYPE_OBJECT) static void fl_external_texture_gl_dispose(GObject* object) { FlExternalTextureGl* self = FL_EXTERNAL_TEXTURE_GL(object); - if (self->gl.valid) { - self->gl.deleteTextures(1, &self->gl_texture_id); + if (gl.valid) { + gl.deleteTextures(1, &self->gl_texture_id); } G_OBJECT_CLASS(fl_external_texture_gl_parent_class)->dispose(object); @@ -66,7 +67,7 @@ bool fl_external_texture_gl_populate_texture( opengl_texture->name = self->gl_texture_id; opengl_texture->format = GL_RGBA8; opengl_texture->destruction_callback = nullptr; - opengl_texture->user_data = static_cast(self); + opengl_texture->user_data = nullptr; opengl_texture->width = real_width; opengl_texture->height = real_height; @@ -74,19 +75,19 @@ bool fl_external_texture_gl_populate_texture( } void fl_external_texture_gl_load_funcs(FlExternalTextureGl* self) { - self->gl.genTextures = reinterpret_cast( + gl.genTextures = reinterpret_cast( eglGetProcAddress("glGenTextures")); - self->gl.bindTexture = reinterpret_cast( + gl.bindTexture = reinterpret_cast( eglGetProcAddress("glBindTexture")); - self->gl.texParameteri = reinterpret_cast( + gl.texParameteri = reinterpret_cast( eglGetProcAddress("glTexParameteri")); - self->gl.texImage2D = + gl.texImage2D = reinterpret_cast( eglGetProcAddress("glTexImage2D")); - self->gl.deleteTextures = reinterpret_cast( + gl.deleteTextures = reinterpret_cast( eglGetProcAddress("glDeleteTextures")); - self->gl.valid = true; + gl.valid = true; } bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, @@ -100,24 +101,22 @@ bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, *width = pixel_buffer->width; *height = pixel_buffer->height; - if (!self->gl.valid) { + if (!gl.valid) { fl_external_texture_gl_load_funcs(self); } if (self->gl_texture_id == 0) { - self->gl.genTextures(1, &self->gl_texture_id); - self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); - self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_BORDER); - self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_BORDER); - self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl.genTextures(1, &self->gl_texture_id); + gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { - self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); } - self->gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_buffer->width, - pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, - pixel_buffer->buffer); + gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_buffer->width, + pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, + pixel_buffer->buffer); return true; } diff --git a/shell/platform/linux/fl_external_texture_gl.h b/shell/platform/linux/fl_external_texture_gl.h index cfbb0499f50ff..73453494e49e3 100644 --- a/shell/platform/linux/fl_external_texture_gl.h +++ b/shell/platform/linux/fl_external_texture_gl.h @@ -6,6 +6,7 @@ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_EXTERNAL_TEXURE_GL_H #include + #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h" diff --git a/shell/platform/linux/fl_texture_registrar.cc b/shell/platform/linux/fl_texture_registrar.cc index 2c1a8c8c9695a..0c253caff60c0 100644 --- a/shell/platform/linux/fl_texture_registrar.cc +++ b/shell/platform/linux/fl_texture_registrar.cc @@ -3,13 +3,14 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h" + +#include + #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_external_texture_gl.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" -#include - struct _FlTextureRegistrar { GObject parent_instance; diff --git a/shell/platform/linux/fl_texture_registrar_test.cc b/shell/platform/linux/fl_texture_registrar_test.cc new file mode 100644 index 0000000000000..4824d676dcfe9 --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar_test.cc @@ -0,0 +1,72 @@ +// Copyright 2020 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/public/flutter_linux/fl_texture_registrar.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/fl_external_texture_gl.h" +#include "flutter/shell/platform/linux/fl_texture_registrar_private.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "gtest/gtest.h" + +#include + +// Implements eglGetProcAddress but returns dummy functions. +// static void* eglGetProcAddress(const char* name) { +// return reinterpret_cast(+[]() {}); +// } + +// Test that registering a texture works. +TEST(FlTextureRegistrarTest, RegisterTexture) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); + fl_texture_registrar_register_texture(registrar, nullptr, nullptr); +} + +// Test that unregistering a texture works. +TEST(FlTextureRegistrarTest, UnregisterTexture) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); + int64_t id = + fl_texture_registrar_register_texture(registrar, nullptr, nullptr); + fl_texture_registrar_unregister_texture(registrar, id); +} + +// Test that marking a texture frame available works. +TEST(FlTextureRegistrarTest, MarkTextureFrameAvailable) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); + int64_t id = + fl_texture_registrar_register_texture(registrar, nullptr, nullptr); + fl_texture_registrar_mark_texture_frame_available(registrar, id); +} + +// TODO(anirudhb): Re-enable after figuring out how to stub out +// eglGetProcAddress. Also write tests for #FlExternalTextureGl as well. +// +// Test that populating an OpenGL texture works. +// TEST(FlTextureRegistrarTest, PopulateTexture) { +// g_autoptr(FlEngine) engine = make_mock_engine(); +// FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); +// const uint8_t buffer[] = {0x7a, 0x8a, 0x9a, 0xaa}; +// FlPixelBuffer pixel_buffer; +// pixel_buffer.buffer = buffer; +// pixel_buffer.width = 2; +// pixel_buffer.height = 2; +// FlTextureCallback callback = [](size_t width, size_t height, +// void* user_data) -> const FlPixelBuffer* { +// FlPixelBuffer* pixel_buffer = static_cast(user_data); +// EXPECT_EQ(width, pixel_buffer->width); +// EXPECT_EQ(height, pixel_buffer->height); +// return pixel_buffer; +// }; +// int64_t id = +// fl_texture_registrar_register_texture(registrar, callback, +// &pixel_buffer); +// FlutterOpenGLTexture opengl_texture; +// EXPECT_TRUE(fl_texture_registrar_populate_texture( +// registrar, id, pixel_buffer.width, pixel_buffer.height, +// &opengl_texture)); +// EXPECT_EQ(opengl_texture.width, pixel_buffer.width); +// EXPECT_EQ(opengl_texture.height, pixel_buffer.height); +// } diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index bd0864c62d315..c6a45a17b5e35 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -4,6 +4,14 @@ #include "flutter/shell/platform/linux/testing/fl_test.h" +#include + +// Doesn't work if included in the next block. +#include "gtest/gtest.h" + +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/testing/mock_renderer.h" + static uint8_t hex_digit_to_int(char value) { if (value >= '0' && value <= '9') return value - '0'; @@ -39,3 +47,15 @@ gchar* bytes_to_hex_string(GBytes* bytes) { g_string_append_printf(hex_string, "%02x", data[i]); return g_string_free(hex_string, FALSE); } + +// Creates a mock engine that responds to platform messages. +FlEngine* make_mock_engine() { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer)); + g_autoptr(GError) engine_error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &engine_error)); + EXPECT_EQ(engine_error, nullptr); + + return static_cast(g_object_ref(engine)); +} diff --git a/shell/platform/linux/testing/fl_test.h b/shell/platform/linux/testing/fl_test.h index 9f28da3f3b048..fe897fc71a769 100644 --- a/shell/platform/linux/testing/fl_test.h +++ b/shell/platform/linux/testing/fl_test.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_TEST_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_TEST_H_ +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" + #include #include @@ -18,6 +20,9 @@ GBytes* hex_string_to_bytes(const gchar* hex_string); // Helper function to convert GBytes into a hexadecimal string (e.g. "01feab") gchar* bytes_to_hex_string(GBytes* bytes); +// Creates a mock engine that responds to platform messages. +FlEngine* make_mock_engine(); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEST_H_ diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index 31a46ee2b6e32..3b4fbded60458 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -9,12 +9,19 @@ #include "gtest/gtest.h" #include +#include +#include + +struct _FlutterEngineTexture { + bool hasNewFrame; +}; struct _FlutterEngine { bool running; FlutterPlatformMessageCallback platform_message_callback; FlutterTaskRunnerPostTaskCallback platform_post_task_callback; void* user_data; + std::unordered_map textures; _FlutterEngine(FlutterPlatformMessageCallback platform_message_callback, FlutterTaskRunnerPostTaskCallback platform_post_task_callback, @@ -393,17 +400,26 @@ FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) FlutterEngineResult FlutterEngineRegisterExternalTexture( FLUTTER_API_SYMBOL(FlutterEngine) engine, int64_t texture_identifier) { + _FlutterEngineTexture texture; + texture.hasNewFrame = false; + engine->textures[texture_identifier] = texture; return kSuccess; } FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable( FLUTTER_API_SYMBOL(FlutterEngine) engine, int64_t texture_identifier) { + auto val = engine->textures.find(texture_identifier); + if (val == std::end(engine->textures)) { + return kInvalidArguments; + } + val->second.hasNewFrame = true; return kSuccess; } FlutterEngineResult FlutterEngineUnregisterExternalTexture( FLUTTER_API_SYMBOL(FlutterEngine) engine, int64_t texture_identifier) { + engine->textures.erase(texture_identifier); return kSuccess; } From 612995ae0a5c554e1d3fe751cbd0121a78b659ea Mon Sep 17 00:00:00 2001 From: anirudhb Date: Sat, 5 Sep 2020 16:45:09 -0700 Subject: [PATCH 4/8] Fix nits, finish tests --- shell/platform/linux/BUILD.gn | 1 + shell/platform/linux/fl_engine.cc | 19 ++-- shell/platform/linux/fl_engine_private.h | 17 +-- .../platform/linux/fl_external_texture_gl.cc | 97 +++++++++-------- shell/platform/linux/fl_external_texture_gl.h | 30 ++--- .../linux/fl_external_texture_gl_test.cc | 103 ++++++++++++++++++ shell/platform/linux/fl_plugin_registrar.cc | 1 + shell/platform/linux/fl_texture_registrar.cc | 2 +- .../linux/fl_texture_registrar_private.h | 2 +- .../linux/fl_texture_registrar_test.cc | 68 ++++++------ .../flutter_linux/fl_texture_registrar.h | 30 +++-- shell/platform/linux/testing/fl_test.cc | 2 +- shell/platform/linux/testing/fl_test.h | 2 +- shell/platform/linux/testing/mock_egl.cc | 51 ++++++++- shell/platform/linux/testing/mock_engine.cc | 1 + 15 files changed, 290 insertions(+), 136 deletions(-) create mode 100644 shell/platform/linux/fl_external_texture_gl_test.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 1e844adf0bf4c..c48cc55b62104 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -141,6 +141,7 @@ executable("flutter_linux_unittests") { "fl_binary_codec_test.cc", "fl_binary_messenger_test.cc", "fl_dart_project_test.cc", + "fl_external_texture_gl_test.cc", "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", "fl_message_codec_test.cc", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index c837e0a6dd92f..3ab42de8a4682 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -593,17 +593,22 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, FlutterEngineSendPointerEvent(self->engine, &fl_event, 1); } -bool fl_engine_mark_texture_frame_available(FlEngine* self, - int64_t texture_id) { - g_return_val_if_fail(FL_IS_ENGINE(self), false); +gboolean fl_engine_mark_texture_frame_available(FlEngine* self, + int64_t texture_id) { + g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); return FlutterEngineMarkExternalTextureFrameAvailable(self->engine, - texture_id) == kSuccess; + texture_id) == kSuccess + ? TRUE + : FALSE; } -bool fl_engine_register_external_texture(FlEngine* self, int64_t texture_id) { - g_return_val_if_fail(FL_IS_ENGINE(self), false); +gboolean fl_engine_register_external_texture(FlEngine* self, + int64_t texture_id) { + g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); return FlutterEngineRegisterExternalTexture(self->engine, texture_id) == - kSuccess; + kSuccess + ? TRUE + : FALSE; } void fl_engine_unregister_external_texture(FlEngine* self, int64_t texture_id) { diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index e399f1ef33479..362db2bd367b3 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -178,31 +178,32 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, /** * fl_engine_mark_texture_frame_available: * @engine: an #FlEngine. - * @texture_id: an int64_t. + * @texture_id: the identifier of the texture whose frame has been updated. * * Tells the Flutter engine that a new texture frame is available for the given * texture. * - * Returns: true on success. + * Returns: %TRUE on success. */ -bool fl_engine_mark_texture_frame_available(FlEngine* engine, - int64_t texture_id); +gboolean fl_engine_mark_texture_frame_available(FlEngine* engine, + int64_t texture_id); /** * fl_engine_register_external_texture: * @engine: an #FlEngine. - * @texture_id: an int64_t. + * @texture_id: the identifier of the texture that is available. * * Tells the Flutter engine that a new external texture is available. * - * Returns: true on success. + * Returns: %TRUE on success. */ -bool fl_engine_register_external_texture(FlEngine* engine, int64_t texture_id); +gboolean fl_engine_register_external_texture(FlEngine* engine, + int64_t texture_id); /** * fl_engine_unregister_external_texture: * @engine: an #FlEngine. - * @texture_id: an int64_t. + * @texture_id: the identifier of the texture that is not available anymore. * * Tells the Flutter engine that an existing external texture is not available * anymore. diff --git a/shell/platform/linux/fl_external_texture_gl.cc b/shell/platform/linux/fl_external_texture_gl.cc index 0ad818f4bc1df..189731210d93c 100644 --- a/shell/platform/linux/fl_external_texture_gl.cc +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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. @@ -8,7 +8,7 @@ #include #include -struct { +typedef struct { bool valid; void (*genTextures)(GLsizei n, GLuint* textures); void (*bindTexture)(GLenum target, GLuint texture); @@ -23,9 +23,30 @@ struct { GLenum type, const void* data); void (*deleteTextures)(GLsizei n, const GLuint* textures); -} gl; +} glFuncs; + +static glFuncs* load_gl_funcs() { + static glFuncs funcs; + if (!funcs.valid) { + funcs.genTextures = reinterpret_cast( + eglGetProcAddress("glGenTextures")); + funcs.bindTexture = reinterpret_cast( + eglGetProcAddress("glBindTexture")); + funcs.texParameteri = reinterpret_cast( + eglGetProcAddress("glTexParameteri")); + funcs.texImage2D = + reinterpret_cast( + eglGetProcAddress("glTexImage2D")); + funcs.deleteTextures = reinterpret_cast( + eglGetProcAddress("glDeleteTextures")); + funcs.valid = true; + } + return &funcs; +} struct _FlExternalTextureGl { + GObject parent_instance; GLuint gl_texture_id; FlTextureCallback callback; void* user_data; @@ -35,9 +56,8 @@ G_DEFINE_TYPE(FlExternalTextureGl, fl_external_texture_gl, G_TYPE_OBJECT) static void fl_external_texture_gl_dispose(GObject* object) { FlExternalTextureGl* self = FL_EXTERNAL_TEXTURE_GL(object); - if (gl.valid) { - gl.deleteTextures(1, &self->gl_texture_id); - } + glFuncs* gl = load_gl_funcs(); + gl->deleteTextures(1, &self->gl_texture_id); G_OBJECT_CLASS(fl_external_texture_gl_parent_class)->dispose(object); } @@ -49,14 +69,17 @@ static void fl_external_texture_gl_class_init(FlExternalTextureGlClass* klass) { static void fl_external_texture_gl_init(FlExternalTextureGl* self) {} int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self) { - return reinterpret_cast(self); + g_return_val_if_fail(FL_IS_EXTERNAL_TEXTURE_GL(self), -1); + return self->gl_texture_id; } -bool fl_external_texture_gl_populate_texture( +gboolean fl_external_texture_gl_populate_texture( FlExternalTextureGl* self, size_t width, size_t height, FlutterOpenGLTexture* opengl_texture) { + g_return_val_if_fail(FL_IS_EXTERNAL_TEXTURE_GL(self), FALSE); + size_t real_width = width, real_height = height; if (!fl_external_texture_gl_copy_pixel_buffer(self, &real_width, &real_height)) { @@ -71,53 +94,33 @@ bool fl_external_texture_gl_populate_texture( opengl_texture->width = real_width; opengl_texture->height = real_height; - return true; + return TRUE; } -void fl_external_texture_gl_load_funcs(FlExternalTextureGl* self) { - gl.genTextures = reinterpret_cast( - eglGetProcAddress("glGenTextures")); - gl.bindTexture = reinterpret_cast( - eglGetProcAddress("glBindTexture")); - gl.texParameteri = reinterpret_cast( - eglGetProcAddress("glTexParameteri")); - gl.texImage2D = - reinterpret_cast( - eglGetProcAddress("glTexImage2D")); - gl.deleteTextures = reinterpret_cast( - eglGetProcAddress("glDeleteTextures")); - gl.valid = true; -} +gboolean fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, + size_t* width, + size_t* height) { + g_return_val_if_fail(FL_IS_EXTERNAL_TEXTURE_GL(self), FALSE); -bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, - size_t* width, - size_t* height) { - const FlPixelBuffer* pixel_buffer = - self->callback(*width, *height, self->user_data); - if (!pixel_buffer || !pixel_buffer->buffer) { - return false; + const uint8_t* buffer; + if (self->callback(width, height, &buffer, self->user_data) != TRUE) { + return FALSE; } - *width = pixel_buffer->width; - *height = pixel_buffer->height; - if (!gl.valid) { - fl_external_texture_gl_load_funcs(self); - } + glFuncs* gl = load_gl_funcs(); if (self->gl_texture_id == 0) { - gl.genTextures(1, &self->gl_texture_id); - gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->genTextures(1, &self->gl_texture_id); + gl->bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { - gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + gl->bindTexture(GL_TEXTURE_2D, self->gl_texture_id); } - gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_buffer->width, - pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, - pixel_buffer->buffer); - return true; + gl->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, *width, *height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, buffer); + return TRUE; } FlExternalTextureGl* fl_external_texture_gl_new( diff --git a/shell/platform/linux/fl_external_texture_gl.h b/shell/platform/linux/fl_external_texture_gl.h index 73453494e49e3..743298d6ccd6b 100644 --- a/shell/platform/linux/fl_external_texture_gl.h +++ b/shell/platform/linux/fl_external_texture_gl.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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. @@ -39,19 +39,20 @@ FlExternalTextureGl* fl_external_texture_gl_new( /** * fl_external_texture_gl_populate_texture: - * @width: a size_t. - * @height: a size_t. + * @external_texture: an #FlExternalTextureGl. + * @width: a size_t representing the width of the texture. + * @height: a size_t representing the height of the texture. * @opengl_texture: a FlutterOpenGLTexture*. * * Attempts to populate the specified |opengl_texture| with texture details * such as the name, width, height and the pixel format upon successfully - * copying the buffer provided by |texture_callback_|. See + * copying the buffer provided by this texture's |texture_callback_|. See * |fl_external_texture_gl_copy_pixel_buffer|. * - * Returns true on success or false if the pixel buffer could not be copied. + * Returns %TRUE on success or %FALSE if the pixel buffer could not be copied. */ -bool fl_external_texture_gl_populate_texture( - FlExternalTextureGl* self, +gboolean fl_external_texture_gl_populate_texture( + FlExternalTextureGl* external_texture, size_t width, size_t height, FlutterOpenGLTexture* opengl_texture); @@ -63,10 +64,12 @@ bool fl_external_texture_gl_populate_texture( * * Returns an int64_t, which is the unique id of this texture. */ -int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self); +int64_t fl_external_texture_gl_texture_id( + FlExternalTextureGl* external_texture); /** * fl_external_texture_gl_copy_pixel_buffer: + * @external_texture: an #FlExternalTextureGl. * @width: a size_t. * @height: a size_t. * @@ -74,12 +77,13 @@ int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self); * OpenGL. The |width| and |height| will be set to the actual bounds of the * copied pixel buffer. * - * Returns true on success or false if the pixel buffer returned by - * |texture_callback_| was invalid. + * Returns %TRUE on success or %TRUE if the pixel buffer returned by + * this texture's |texture_callback_| was invalid. */ -bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self, - size_t* width, - size_t* height); +gboolean fl_external_texture_gl_copy_pixel_buffer( + FlExternalTextureGl* external_texture, + size_t* width, + size_t* height); G_END_DECLS diff --git a/shell/platform/linux/fl_external_texture_gl_test.cc b/shell/platform/linux/fl_external_texture_gl_test.cc new file mode 100644 index 0000000000000..799a095fe10a7 --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl_test.cc @@ -0,0 +1,103 @@ +// 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 + +#include "flutter/shell/platform/linux/fl_external_texture_gl.h" +#include "flutter/shell/platform/linux/fl_texture_registrar_private.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "gtest/gtest.h" + +#include + +// Test that getting the texture ID works. +TEST(FlExternalTextureGlTest, TextureID) { + // Texture ID is not assigned until the pixel buffer is copied once. +#define BUFFER_WIDTH 19u +#define BUFFER_HEIGHT 19u +#define REAL_BUFFER_WIDTH 7u +#define REAL_BUFFER_HEIGHT 7u + FlTextureCallback callback = [](size_t* width, size_t* height, + const uint8_t** out_buffer, + void* user_data) -> gboolean { + const uint8_t buffer[] = {0xc9, 0xc8, 0xc7, 0xc6}; + EXPECT_EQ(*width, BUFFER_WIDTH); + EXPECT_EQ(*height, BUFFER_HEIGHT); + *out_buffer = buffer; + *width = REAL_BUFFER_WIDTH; + *height = REAL_BUFFER_HEIGHT; + return TRUE; + }; + FlExternalTextureGl* texture = fl_external_texture_gl_new(callback, nullptr); + size_t width = BUFFER_WIDTH; + size_t height = BUFFER_HEIGHT; + EXPECT_EQ(fl_external_texture_gl_copy_pixel_buffer(texture, &width, &height), + TRUE); + EXPECT_EQ(fl_external_texture_gl_texture_id(texture), 99); +#undef REAL_BUFFER_HEIGHT +#undef REAL_BUFFER_WIDTH +#undef BUFFER_HEIGHT +#undef BUFFER_WIDTH +} + +// Test that copying a pixel buffer works. +TEST(FlExternalTextureGlTest, CopyPixelBuffer) { +#define BUFFER_WIDTH 8u +#define BUFFER_HEIGHT 8u +#define REAL_BUFFER_WIDTH 3u +#define REAL_BUFFER_HEIGHT 3u + FlTextureCallback callback = [](size_t* width, size_t* height, + const uint8_t** out_buffer, + void* user_data) -> gboolean { + const uint8_t buffer[] = {0xb3, 0xb4, 0xb5, 0xb6}; + EXPECT_EQ(*width, BUFFER_WIDTH); + EXPECT_EQ(*height, BUFFER_HEIGHT); + *out_buffer = buffer; + *width = REAL_BUFFER_WIDTH; + *height = REAL_BUFFER_HEIGHT; + return TRUE; + }; + FlExternalTextureGl* texture = fl_external_texture_gl_new(callback, nullptr); + size_t width = BUFFER_WIDTH; + size_t height = BUFFER_HEIGHT; + EXPECT_EQ(fl_external_texture_gl_copy_pixel_buffer(texture, &width, &height), + TRUE); + EXPECT_EQ(width, REAL_BUFFER_WIDTH); + EXPECT_EQ(height, REAL_BUFFER_HEIGHT); +#undef REAL_BUFFER_HEIGHT +#undef REAL_BUFFER_WIDTH +#undef BUFFER_HEIGHT +#undef BUFFER_WIDTH +} + +// Test that populating an OpenGL texture works. +TEST(FlExternalTextureGlTest, PopulateTexture) { +#define BUFFER_WIDTH 4u +#define BUFFER_HEIGHT 4u +#define REAL_BUFFER_WIDTH 2u +#define REAL_BUFFER_HEIGHT 2u + FlTextureCallback callback = [](size_t* width, size_t* height, + const uint8_t** out_buffer, + void* user_data) -> gboolean { + const uint8_t buffer[] = {0x7a, 0x8a, 0x9a, 0xaa}; + EXPECT_EQ(*width, BUFFER_WIDTH); + EXPECT_EQ(*height, BUFFER_HEIGHT); + *out_buffer = buffer; + *width = REAL_BUFFER_WIDTH; + *height = REAL_BUFFER_HEIGHT; + return TRUE; + }; + FlExternalTextureGl* texture = fl_external_texture_gl_new(callback, nullptr); + FlutterOpenGLTexture opengl_texture; + EXPECT_EQ(fl_external_texture_gl_populate_texture( + texture, BUFFER_WIDTH, BUFFER_HEIGHT, &opengl_texture), + TRUE); + EXPECT_EQ(opengl_texture.width, REAL_BUFFER_WIDTH); + EXPECT_EQ(opengl_texture.height, REAL_BUFFER_HEIGHT); +#undef REAL_BUFFER_HEIGHT +#undef REAL_BUFFER_WIDTH +#undef BUFFER_HEIGHT +#undef BUFFER_WIDTH +} diff --git a/shell/platform/linux/fl_plugin_registrar.cc b/shell/platform/linux/fl_plugin_registrar.cc index 6be2049510f26..073a6a6ee7e9d 100644 --- a/shell/platform/linux/fl_plugin_registrar.cc +++ b/shell/platform/linux/fl_plugin_registrar.cc @@ -1,6 +1,7 @@ // 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. +// FLUTTER_NOLINT #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" diff --git a/shell/platform/linux/fl_texture_registrar.cc b/shell/platform/linux/fl_texture_registrar.cc index 0c253caff60c0..a42d863dada0f 100644 --- a/shell/platform/linux/fl_texture_registrar.cc +++ b/shell/platform/linux/fl_texture_registrar.cc @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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. diff --git a/shell/platform/linux/fl_texture_registrar_private.h b/shell/platform/linux/fl_texture_registrar_private.h index 20c6b9f56b9c3..a8e20ee8efb76 100644 --- a/shell/platform/linux/fl_texture_registrar_private.h +++ b/shell/platform/linux/fl_texture_registrar_private.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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. diff --git a/shell/platform/linux/fl_texture_registrar_test.cc b/shell/platform/linux/fl_texture_registrar_test.cc index 4824d676dcfe9..0e4be5f744b00 100644 --- a/shell/platform/linux/fl_texture_registrar_test.cc +++ b/shell/platform/linux/fl_texture_registrar_test.cc @@ -1,21 +1,14 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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/public/flutter_linux/fl_texture_registrar.h" -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/linux/fl_external_texture_gl.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" #include "gtest/gtest.h" #include -// Implements eglGetProcAddress but returns dummy functions. -// static void* eglGetProcAddress(const char* name) { -// return reinterpret_cast(+[]() {}); -// } - // Test that registering a texture works. TEST(FlTextureRegistrarTest, RegisterTexture) { g_autoptr(FlEngine) engine = make_mock_engine(); @@ -41,32 +34,35 @@ TEST(FlTextureRegistrarTest, MarkTextureFrameAvailable) { fl_texture_registrar_mark_texture_frame_available(registrar, id); } -// TODO(anirudhb): Re-enable after figuring out how to stub out -// eglGetProcAddress. Also write tests for #FlExternalTextureGl as well. -// // Test that populating an OpenGL texture works. -// TEST(FlTextureRegistrarTest, PopulateTexture) { -// g_autoptr(FlEngine) engine = make_mock_engine(); -// FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); -// const uint8_t buffer[] = {0x7a, 0x8a, 0x9a, 0xaa}; -// FlPixelBuffer pixel_buffer; -// pixel_buffer.buffer = buffer; -// pixel_buffer.width = 2; -// pixel_buffer.height = 2; -// FlTextureCallback callback = [](size_t width, size_t height, -// void* user_data) -> const FlPixelBuffer* { -// FlPixelBuffer* pixel_buffer = static_cast(user_data); -// EXPECT_EQ(width, pixel_buffer->width); -// EXPECT_EQ(height, pixel_buffer->height); -// return pixel_buffer; -// }; -// int64_t id = -// fl_texture_registrar_register_texture(registrar, callback, -// &pixel_buffer); -// FlutterOpenGLTexture opengl_texture; -// EXPECT_TRUE(fl_texture_registrar_populate_texture( -// registrar, id, pixel_buffer.width, pixel_buffer.height, -// &opengl_texture)); -// EXPECT_EQ(opengl_texture.width, pixel_buffer.width); -// EXPECT_EQ(opengl_texture.height, pixel_buffer.height); -// } +TEST(FlTextureRegistrarTest, PopulateTexture) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlTextureRegistrar* registrar = fl_texture_registrar_new(engine); +#define BUFFER_WIDTH 4u +#define BUFFER_HEIGHT 4u +#define REAL_BUFFER_WIDTH 2u +#define REAL_BUFFER_HEIGHT 2u + FlTextureCallback callback = [](size_t* width, size_t* height, + const uint8_t** out_buffer, + void* user_data) -> gboolean { + const uint8_t buffer[] = {0x7a, 0x8a, 0x9a, 0xaa}; + EXPECT_EQ(*width, BUFFER_WIDTH); + EXPECT_EQ(*height, BUFFER_HEIGHT); + *out_buffer = buffer; + *width = REAL_BUFFER_WIDTH; + *height = REAL_BUFFER_HEIGHT; + return TRUE; + }; + int64_t id = + fl_texture_registrar_register_texture(registrar, callback, nullptr); + FlutterOpenGLTexture opengl_texture; + EXPECT_EQ(fl_texture_registrar_populate_texture( + registrar, id, BUFFER_WIDTH, BUFFER_HEIGHT, &opengl_texture), + TRUE); + EXPECT_EQ(opengl_texture.width, REAL_BUFFER_WIDTH); + EXPECT_EQ(opengl_texture.height, REAL_BUFFER_HEIGHT); +#undef REAL_BUFFER_HEIGHT +#undef REAL_BUFFER_WIDTH +#undef BUFFER_HEIGHT +#undef BUFFER_WIDTH +} diff --git a/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h b/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h index 15746d32caffe..5ca779492dd7d 100644 --- a/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h +++ b/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// 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. @@ -14,22 +14,19 @@ G_BEGIN_DECLS -/** - * An image buffer object. - */ -typedef struct { - const uint8_t* buffer; - size_t width; - size_t height; -} FlPixelBuffer; - /** * The pixel buffer copy callback provided to the Flutter engine to copy the * texture. + * @width: inout parameter representing the given width and the actual width. + * @height: inout parameter representing the given height and the actual height. + * @buffer: out parameter representing the pixel buffer. + * + * Returns: %TRUE on success. */ -typedef const FlPixelBuffer* (*FlTextureCallback)(size_t width, - size_t height, - void* user_data); +typedef gboolean (*FlTextureCallback)(size_t* width, + size_t* height, + const uint8_t** buffer, + void* user_data); G_DECLARE_FINAL_TYPE(FlTextureRegistrar, fl_texture_registrar, @@ -46,7 +43,8 @@ G_DECLARE_FINAL_TYPE(FlTextureRegistrar, /** * fl_texture_registrar_register_texture: * @registrar: an #FlTextureRegistrar. - * @texture: an #FlTexture. + * @texture_callback: the #FlTextureCallback to use for the texture. + * @user_data: user data to pass to the callback. * * Registers a texture callback and returns the ID for that texture. * @@ -60,7 +58,7 @@ int64_t fl_texture_registrar_register_texture( /** * fl_texture_registrar_mark_texture_frame_available: * @registrar: an #FlTextureRegistrar. - * @texture_id: an int64_t. + * @texture_id: the ID of the texture that has a frame available. * * Notifies the flutter engine that the texture object corresponding * to texture_id needs to render a new texture. @@ -72,7 +70,7 @@ void fl_texture_registrar_mark_texture_frame_available( /** * fl_texture_registrar_unregister_texture: * @registrar: an #FlTextureRegistrar. - * @texture_id: an int64_t. + * @texture_id: the ID of the texture that is being unregistered. * * Unregisters an existing texture object. */ diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index c6a45a17b5e35..b3bb3270c4fb6 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -1,6 +1,7 @@ // 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. +// FLUTTER_NOLINT #include "flutter/shell/platform/linux/testing/fl_test.h" @@ -48,7 +49,6 @@ gchar* bytes_to_hex_string(GBytes* bytes) { return g_string_free(hex_string, FALSE); } -// Creates a mock engine that responds to platform messages. FlEngine* make_mock_engine() { g_autoptr(FlDartProject) project = fl_dart_project_new(); g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); diff --git a/shell/platform/linux/testing/fl_test.h b/shell/platform/linux/testing/fl_test.h index fe897fc71a769..6c5c2107e6fb7 100644 --- a/shell/platform/linux/testing/fl_test.h +++ b/shell/platform/linux/testing/fl_test.h @@ -20,7 +20,7 @@ GBytes* hex_string_to_bytes(const gchar* hex_string); // Helper function to convert GBytes into a hexadecimal string (e.g. "01feab") gchar* bytes_to_hex_string(GBytes* bytes); -// Creates a mock engine that responds to platform messages. +// Creates an engine with a mock renderer that responds to platform messages. FlEngine* make_mock_engine(); G_END_DECLS diff --git a/shell/platform/linux/testing/mock_egl.cc b/shell/platform/linux/testing/mock_egl.cc index 8790aff19ef8c..426b2c42f31d7 100644 --- a/shell/platform/linux/testing/mock_egl.cc +++ b/shell/platform/linux/testing/mock_egl.cc @@ -1,8 +1,11 @@ // 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. +// FLUTTER_NOLINT #include +#include +#include typedef struct { EGLint config_id; @@ -255,11 +258,6 @@ EGLint eglGetError() { return error; } -void (*eglGetProcAddress(const char* procname))(void) { - mock_error = EGL_SUCCESS; - return nullptr; -} - EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { if (!check_display(dpy)) return EGL_FALSE; @@ -319,3 +317,46 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { return bool_success(); } + +void fakeGlGenTextures(GLsizei n, GLuint* textures) { + for (int i = 0; i < n; i++) { + textures[i] = 99 + i; + } +} +void fakeGlBindTexture(GLenum target, GLuint texture) {} +void fakeGlTexParameteri(GLenum target, GLenum pname, GLenum param) {} +void fakeGlTexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* data) {} +void fakeGlDeleteTextures(GLsizei n, const GLuint* textures) {} + +void (*eglGetProcAddress(const char* procname))(void) { + mock_error = EGL_SUCCESS; + if (strcmp(procname, "glGenTextures") == 0) { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>( + fakeGlGenTextures); + } + if (strcmp(procname, "glBindTexture") == 0) { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>( + fakeGlBindTexture); + } + if (strcmp(procname, "glTexParameteri") == 0) { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>( + fakeGlTexParameteri); + } + if (strcmp(procname, "glTexImage2D") == 0) { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>( + fakeGlTexImage2D); + } + if (strcmp(procname, "glDeleteTextures") == 0) { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>( + fakeGlDeleteTextures); + } + return nullptr; +} diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index 3b4fbded60458..c96ab858ab9d1 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -1,6 +1,7 @@ // 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. +// FLUTTER_NOLINT #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_method_codec_private.h" From 8a007ba74e96e2293ee3fc0f8f6ec3f058042d1c Mon Sep 17 00:00:00 2001 From: anirudhb Date: Sat, 5 Sep 2020 17:23:31 -0700 Subject: [PATCH 5/8] Change texture_id back to before --- shell/platform/linux/fl_external_texture_gl.cc | 2 +- shell/platform/linux/fl_external_texture_gl_test.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_external_texture_gl.cc b/shell/platform/linux/fl_external_texture_gl.cc index 189731210d93c..67d9018ab1f7e 100644 --- a/shell/platform/linux/fl_external_texture_gl.cc +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -70,7 +70,7 @@ static void fl_external_texture_gl_init(FlExternalTextureGl* self) {} int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self) { g_return_val_if_fail(FL_IS_EXTERNAL_TEXTURE_GL(self), -1); - return self->gl_texture_id; + return reinterpret_cast(self); } gboolean fl_external_texture_gl_populate_texture( diff --git a/shell/platform/linux/fl_external_texture_gl_test.cc b/shell/platform/linux/fl_external_texture_gl_test.cc index 799a095fe10a7..03f813e9adce7 100644 --- a/shell/platform/linux/fl_external_texture_gl_test.cc +++ b/shell/platform/linux/fl_external_texture_gl_test.cc @@ -35,7 +35,8 @@ TEST(FlExternalTextureGlTest, TextureID) { size_t height = BUFFER_HEIGHT; EXPECT_EQ(fl_external_texture_gl_copy_pixel_buffer(texture, &width, &height), TRUE); - EXPECT_EQ(fl_external_texture_gl_texture_id(texture), 99); + EXPECT_EQ(fl_external_texture_gl_texture_id(texture), + reinterpret_cast(texture)); #undef REAL_BUFFER_HEIGHT #undef REAL_BUFFER_WIDTH #undef BUFFER_HEIGHT From 051333b9f3395fa4008bfe4f43ee50f3a1904e54 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Tue, 8 Sep 2020 13:33:24 -0700 Subject: [PATCH 6/8] Update golden licenses with new files --- ci/licenses_golden/licenses_flutter | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 611cdc4dba0bf..e2f0b42675188 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1270,6 +1270,9 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc FILE: ../../../flutter/shell/platform/linux/fl_engine.cc FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h +FILE: ../../../flutter/shell/platform/linux/fl_external_texture_gl.cc +FILE: ../../../flutter/shell/platform/linux/fl_external_texture_gl.h +FILE: ../../../flutter/shell/platform/linux/fl_external_texture_gl_test.cc FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc @@ -1309,7 +1312,10 @@ FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.cc -FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h +FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h' +FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar.cc +FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_private.h +FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_test.cc FILE: ../../../flutter/shell/platform/linux/fl_value.cc FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc FILE: ../../../flutter/shell/platform/linux/fl_view.cc @@ -1330,6 +1336,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_plugin_regis FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h +FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_value.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h From e2e365f2a85173d6b4688d09d81a9a27b7020636 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Tue, 8 Sep 2020 13:45:37 -0700 Subject: [PATCH 7/8] Oops --- ci/licenses_golden/licenses_flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e2f0b42675188..bcc6de8ed9adc 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1312,7 +1312,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.cc -FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h' +FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar.cc FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_private.h FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_test.cc From db16569197a9ba9d015b3986a6e356776fff37dc Mon Sep 17 00:00:00 2001 From: anirudhb Date: Thu, 1 Oct 2020 18:59:15 -0700 Subject: [PATCH 8/8] Fix nits --- shell/platform/linux/fl_engine.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 3ab42de8a4682..787fda2f88420 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -213,6 +213,7 @@ static bool fl_engine_gl_make_resource_current(void* user_data) { return result; } +// Called by the engine to retrieve an external texture. static bool fl_engine_gl_external_texture_frame_callback( void* user_data, int64_t texture_id, @@ -597,18 +598,14 @@ gboolean fl_engine_mark_texture_frame_available(FlEngine* self, int64_t texture_id) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); return FlutterEngineMarkExternalTextureFrameAvailable(self->engine, - texture_id) == kSuccess - ? TRUE - : FALSE; + texture_id) == kSuccess; } gboolean fl_engine_register_external_texture(FlEngine* self, int64_t texture_id) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); return FlutterEngineRegisterExternalTexture(self->engine, texture_id) == - kSuccess - ? TRUE - : FALSE; + kSuccess; } void fl_engine_unregister_external_texture(FlEngine* self, int64_t texture_id) {