diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 611cdc4dba0bf..bcc6de8ed9adc 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 @@ -1310,6 +1313,9 @@ 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_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 diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index efad5e89d868e..c48cc55b62104 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", ] @@ -138,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", @@ -147,6 +151,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 eb952a30a52a3..787fda2f88420 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -5,10 +5,12 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.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" #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,21 @@ 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, + 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 +286,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 +310,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 +330,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 +361,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 +594,33 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, FlutterEngineSendPointerEvent(self->engine, &fl_event, 1); } +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; +} + +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; +} + +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..362db2bd367b3 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -175,6 +175,42 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, GAsyncResult* result, GError** error); +/** + * fl_engine_mark_texture_frame_available: + * @engine: an #FlEngine. + * @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. + */ +gboolean fl_engine_mark_texture_frame_available(FlEngine* engine, + int64_t texture_id); + +/** + * fl_engine_register_external_texture: + * @engine: an #FlEngine. + * @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. + */ +gboolean fl_engine_register_external_texture(FlEngine* engine, + int64_t texture_id); + +/** + * fl_engine_unregister_external_texture: + * @engine: an #FlEngine. + * @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. + */ +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..67d9018ab1f7e --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl.cc @@ -0,0 +1,136 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_external_texture_gl.h" + +#include +#include +#include + +typedef 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); +} 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; +}; + +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); + glFuncs* gl = load_gl_funcs(); + 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) { + g_return_val_if_fail(FL_IS_EXTERNAL_TEXTURE_GL(self), -1); + return reinterpret_cast(self); +} + +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)) { + 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 = nullptr; + opengl_texture->width = real_width; + opengl_texture->height = real_height; + + return 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); + + const uint8_t* buffer; + if (self->callback(width, height, &buffer, self->user_data) != TRUE) { + return FALSE; + } + + 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); + } else { + gl->bindTexture(GL_TEXTURE_2D, self->gl_texture_id); + } + 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( + 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..743298d6ccd6b --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl.h @@ -0,0 +1,90 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_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: + * @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 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. + */ +gboolean fl_external_texture_gl_populate_texture( + FlExternalTextureGl* external_texture, + 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* external_texture); + +/** + * fl_external_texture_gl_copy_pixel_buffer: + * @external_texture: an #FlExternalTextureGl. + * @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 %TRUE if the pixel buffer returned by + * this texture's |texture_callback_| was invalid. + */ +gboolean fl_external_texture_gl_copy_pixel_buffer( + FlExternalTextureGl* external_texture, + 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_external_texture_gl_test.cc b/shell/platform/linux/fl_external_texture_gl_test.cc new file mode 100644 index 0000000000000..03f813e9adce7 --- /dev/null +++ b/shell/platform/linux/fl_external_texture_gl_test.cc @@ -0,0 +1,104 @@ +// 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), + reinterpret_cast(texture)); +#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 9ca72258b6e73..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" @@ -15,6 +16,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 +39,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 +50,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 +64,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 +77,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..a42d863dada0f --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar.cc @@ -0,0 +1,95 @@ +// 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 + +#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" + +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..a8e20ee8efb76 --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar_private.h @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_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_texture_registrar_test.cc b/shell/platform/linux/fl_texture_registrar_test.cc new file mode 100644 index 0000000000000..0e4be5f744b00 --- /dev/null +++ b/shell/platform/linux/fl_texture_registrar_test.cc @@ -0,0 +1,68 @@ +// 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/linux/fl_texture_registrar_private.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "gtest/gtest.h" + +#include + +// 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); +} + +// Test that populating an OpenGL texture works. +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/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..5ca779492dd7d --- /dev/null +++ b/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h @@ -0,0 +1,82 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_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 + +/** + * 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 gboolean (*FlTextureCallback)(size_t* width, + size_t* height, + const uint8_t** buffer, + 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_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. + * + * 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: 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. + */ +void fl_texture_registrar_mark_texture_frame_available( + FlTextureRegistrar* registrar, + int64_t texture_id); + +/** + * fl_texture_registrar_unregister_texture: + * @registrar: an #FlTextureRegistrar. + * @texture_id: the ID of the texture that is being unregistered. + * + * 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/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index bd0864c62d315..b3bb3270c4fb6 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -1,9 +1,18 @@ // 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" +#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 +48,14 @@ gchar* bytes_to_hex_string(GBytes* bytes) { g_string_append_printf(hex_string, "%02x", data[i]); return g_string_free(hex_string, FALSE); } + +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..6c5c2107e6fb7 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 an engine with a mock renderer 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_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 f82394bdd4ca3..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" @@ -9,12 +10,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, @@ -389,3 +397,30 @@ FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) size_t locales_count) { return kSuccess; } + +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; +}