diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter old mode 100755 new mode 100644 index 60751e774da1a..b108bc01c79f4 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -835,6 +835,7 @@ FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/ FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registry.h FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_message_codec.h FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_method_codec.h +FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/texture_registrar.h FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/method_call_unittests.cc FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/method_channel_unittests.cc FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/method_result_functions_unittests.cc @@ -858,6 +859,7 @@ FILE: ../../../flutter/shell/platform/common/cpp/path_utils_unittests.cc FILE: ../../../flutter/shell/platform/common/cpp/public/flutter_export.h FILE: ../../../flutter/shell/platform/common/cpp/public/flutter_messenger.h FILE: ../../../flutter/shell/platform/common/cpp/public/flutter_plugin_registrar.h +FILE: ../../../flutter/shell/platform/common/cpp/public/flutter_texture_registrar.h FILE: ../../../flutter/shell/platform/common/cpp/text_input_model.cc FILE: ../../../flutter/shell/platform/common/cpp/text_input_model.h FILE: ../../../flutter/shell/platform/common/cpp/text_input_model_unittests.cc @@ -1306,6 +1308,8 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc +FILE: ../../../flutter/shell/platform/windows/external_texture_gl.cc +FILE: ../../../flutter/shell/platform/windows/external_texture_gl.h FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h diff --git a/shell/platform/common/cpp/BUILD.gn b/shell/platform/common/cpp/BUILD.gn index 2027ac55f3de8..098347cc0c815 100644 --- a/shell/platform/common/cpp/BUILD.gn +++ b/shell/platform/common/cpp/BUILD.gn @@ -12,6 +12,7 @@ _public_headers = [ "public/flutter_export.h", "public/flutter_messenger.h", "public/flutter_plugin_registrar.h", + "public/flutter_texture_registrar.h", ] # Any files that are built by clients (client_wrapper code, library headers for diff --git a/shell/platform/common/cpp/client_wrapper/core_wrapper_files.gni b/shell/platform/common/cpp/client_wrapper/core_wrapper_files.gni index 18b0897e2a987..44630338e5a66 100644 --- a/shell/platform/common/cpp/client_wrapper/core_wrapper_files.gni +++ b/shell/platform/common/cpp/client_wrapper/core_wrapper_files.gni @@ -20,6 +20,7 @@ core_cpp_client_wrapper_includes = "include/flutter/method_result.h", "include/flutter/plugin_registrar.h", "include/flutter/plugin_registry.h", + "include/flutter/texture_registrar.h", "include/flutter/standard_message_codec.h", "include/flutter/standard_method_codec.h", ], diff --git a/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h b/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h index 647b7cbb48e8b..3c5c824399d61 100644 --- a/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h +++ b/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h @@ -13,6 +13,7 @@ #include #include "binary_messenger.h" +#include "texture_registrar.h" namespace flutter { @@ -41,6 +42,10 @@ class PluginRegistrar { // This pointer will remain valid for the lifetime of this instance. BinaryMessenger* messenger() { return messenger_.get(); } + // Returns the texture registrar to use for the plugin to render a pixel + // buffer. + TextureRegistrar* textures() { return textures_.get(); } + // Takes ownership of |plugin|. // // Plugins are not required to call this method if they have other lifetime @@ -60,6 +65,8 @@ class PluginRegistrar { std::unique_ptr messenger_; + std::unique_ptr textures_; + // Plugins registered for ownership. std::set> plugins_; }; diff --git a/shell/platform/common/cpp/client_wrapper/include/flutter/texture_registrar.h b/shell/platform/common/cpp/client_wrapper/include/flutter/texture_registrar.h new file mode 100644 index 0000000000000..b3cff321c6e0a --- /dev/null +++ b/shell/platform/common/cpp/client_wrapper/include/flutter/texture_registrar.h @@ -0,0 +1,49 @@ +// 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_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ + +#include + +#include +#include + +namespace flutter { + +// An external texture interface declaration. +class Texture { + public: + virtual ~Texture() {} + // This interface is used to respond to texture copy requests from the Flutter + // engine, Flutter engine will be providing the |height| and |width| + // parameters of bounds. In some cases, the user can be scale the texture to + // the size of the bounds to reduce memory usage. + virtual const PixelBuffer* CopyPixelBuffer(size_t width, size_t height) = 0; +}; + +class TextureRegistrar { + public: + virtual ~TextureRegistrar() {} + + /** + * Registers a |texture| object and returns the ID for that texture. + */ + virtual int64_t RegisterTexture(Texture* texture) = 0; + + /** + * Notify the flutter engine that the texture object corresponding + * to |texure_id| needs to render a new texture. + */ + virtual void MarkTextureFrameAvailable(int64_t texture_id) = 0; + + /** + * Unregisters an existing Texture object. + */ + virtual void UnregisterTexture(int64_t texture_id) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ diff --git a/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc b/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc index 9527dd73ead3d..9218d3ac3196c 100644 --- a/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc +++ b/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc @@ -126,12 +126,52 @@ void BinaryMessengerImpl::SetMessageHandler(const std::string& channel, ForwardToHandler, message_handler); } +// Wrapper around a FlutterDesktopTextureRegistrarRef that implements the +// TextureRegistrar API. +class TextureRegistrarImpl : public TextureRegistrar { + public: + explicit TextureRegistrarImpl( + FlutterDesktopTextureRegistrarRef texture_registrar_ref) + : texture_registrar_ref_(texture_registrar_ref) {} + + virtual ~TextureRegistrarImpl() = default; + + // Prevent copying. + TextureRegistrarImpl(TextureRegistrarImpl const&) = delete; + TextureRegistrarImpl& operator=(TextureRegistrarImpl const&) = delete; + + virtual int64_t RegisterTexture(Texture* texture) override { + FlutterTextureCallback callback = + [](size_t width, size_t height, void* user_data) -> const PixelBuffer* { + return static_cast(user_data)->CopyPixelBuffer(width, height); + }; + int64_t texture_id = FlutterDesktopRegisterExternalTexture( + texture_registrar_ref_, callback, texture); + return texture_id; + } + + virtual void MarkTextureFrameAvailable(int64_t texture_id) override { + FlutterDesktopMarkExternalTextureFrameAvailable(texture_registrar_ref_, + texture_id); + } + + virtual void UnregisterTexture(int64_t texture_id) override { + FlutterDesktopUnregisterExternalTexture(texture_registrar_ref_, texture_id); + } + + private: + // Handle for interacting with the C API. + FlutterDesktopTextureRegistrarRef texture_registrar_ref_; +}; + // ===== PluginRegistrar ===== PluginRegistrar::PluginRegistrar(FlutterDesktopPluginRegistrarRef registrar) : registrar_(registrar) { auto core_messenger = FlutterDesktopRegistrarGetMessenger(registrar_); messenger_ = std::make_unique(core_messenger); + auto texture_registrar = FlutterDesktopGetTextureRegistrar(registrar_); + textures_ = std::make_unique(texture_registrar); } PluginRegistrar::~PluginRegistrar() {} diff --git a/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc b/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc index 58cb1f5fcaa48..b4b09a0e08657 100644 --- a/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc +++ b/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include #include #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/texture_registrar.h" #include "flutter/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h" #include "gtest/gtest.h" @@ -15,6 +17,14 @@ namespace { // Stub implementation to validate calls to the API. class TestApi : public testing::StubFlutterApi { + public: + struct FakeTexture { + int64_t texture_id; + int32_t mark_count; + FlutterTextureCallback texture_callback; + void* user_data; + }; + public: // |flutter::testing::StubFlutterApi| bool MessengerSend(const char* channel, @@ -52,10 +62,55 @@ class TestApi : public testing::StubFlutterApi { return last_destruction_callback_set_; } + int64_t RegisterExternalTexture(FlutterTextureCallback texture_callback, + void* user_data) override { + last_texture_id_++; + + auto texture = std::make_unique(); + texture->texture_callback = texture_callback; + texture->user_data = user_data; + texture->mark_count = 0; + texture->texture_id = last_texture_id_; + + textures_[last_texture_id_] = std::move(texture); + return last_texture_id_; + } + + bool UnregisterExternalTexture(int64_t texture_id) override { + auto it = textures_.find(texture_id); + if (it != textures_.end()) { + textures_.erase(it); + return true; + } + return false; + } + + bool TextureFrameAvailable(int64_t texture_id) override { + auto it = textures_.find(texture_id); + if (it != textures_.end()) { + it->second->mark_count++; + return true; + } + return false; + } + + FakeTexture* GetFakeTexture(int64_t texture_id) { + auto it = textures_.find(texture_id); + if (it != textures_.end()) + return it->second.get(); + return nullptr; + } + + int64_t last_texture_id() { return last_texture_id_; } + + size_t textures_size() { return textures_.size(); } + private: const uint8_t* last_data_sent_ = nullptr; FlutterDesktopMessageCallback last_message_callback_set_ = nullptr; FlutterDesktopOnRegistrarDestroyed last_destruction_callback_set_ = nullptr; + int64_t last_texture_id_ = -1; + std::map> textures_; }; // A PluginRegistrar whose destruction can be watched for by tests. @@ -179,4 +234,37 @@ TEST(PluginRegistrarTest, ManagerRemovesOnDestruction) { nullptr); } +// Tests texture register that calls through to the C API. +TEST(MethodCallTest, RegisterTexture) { + testing::ScopedStubFlutterApi scoped_api_stub(std::make_unique()); + auto test_api = static_cast(scoped_api_stub.stub()); + + auto dummy_registrar_handle = + reinterpret_cast(1); + PluginRegistrar registrar(dummy_registrar_handle); + TextureRegistrar* textures = registrar.textures(); + + EXPECT_EQ(test_api->last_texture_id(), -1); + auto texture = test_api->GetFakeTexture(0); + EXPECT_EQ(texture, nullptr); + + int64_t texture_id = textures->RegisterTexture(reinterpret_cast(2)); + EXPECT_EQ(test_api->last_texture_id(), texture_id); + EXPECT_EQ(test_api->textures_size(), static_cast(1)); + + texture = test_api->GetFakeTexture(texture_id); + EXPECT_EQ(texture->texture_id, texture_id); + EXPECT_EQ(texture->user_data, reinterpret_cast(2)); + + textures->MarkTextureFrameAvailable(texture_id); + textures->MarkTextureFrameAvailable(texture_id); + textures->MarkTextureFrameAvailable(texture_id); + EXPECT_EQ(texture->mark_count, 3); + + textures->UnregisterTexture(texture_id); + texture = test_api->GetFakeTexture(texture_id); + EXPECT_EQ(texture, nullptr); + EXPECT_EQ(test_api->textures_size(), static_cast(0)); +} + } // namespace flutter diff --git a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc index 580df48645aa9..ebe2f8d202750 100644 --- a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc +++ b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc @@ -104,3 +104,40 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, s_stub_implementation->MessengerSetCallback(channel, callback, user_data); } } + +FlutterDesktopTextureRegistrarRef FlutterDesktopGetTextureRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + return reinterpret_cast(1); +} + +int64_t FlutterDesktopRegisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + FlutterTextureCallback texture_callback, + void* user_data) { + uint64_t result = -1; + if (s_stub_implementation) { + result = s_stub_implementation->RegisterExternalTexture(texture_callback, + user_data); + } + return result; +} + +bool FlutterDesktopUnregisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + bool result = false; + if (s_stub_implementation) { + result = s_stub_implementation->UnregisterExternalTexture(texture_id); + } + return result; +} + +bool FlutterDesktopMarkExternalTextureFrameAvailable( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + bool result = false; + if (s_stub_implementation) { + result = s_stub_implementation->TextureFrameAvailable(texture_id); + } + return result; +} diff --git a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h index 284d15e974947..677155004b0d5 100644 --- a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h +++ b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h @@ -67,6 +67,19 @@ class StubFlutterApi { virtual void MessengerSetCallback(const char* channel, FlutterDesktopMessageCallback callback, void* user_data) {} + + // Called for FlutterDesktopRegisterExternalTexture. + virtual int64_t RegisterExternalTexture( + FlutterTextureCallback texture_callback, + void* user_data) { + return -1; + } + + // Called for FlutterDesktopUnregisterExternalTexture. + virtual bool UnregisterExternalTexture(int64_t texture_id) { return false; } + + // Called for FlutterDesktopMarkExternalTextureFrameAvailable. + virtual bool TextureFrameAvailable(int64_t texture_id) { return false; } }; // A test helper that owns a stub implementation, making it the test stub for diff --git a/shell/platform/common/cpp/public/flutter_plugin_registrar.h b/shell/platform/common/cpp/public/flutter_plugin_registrar.h index 95f0abf139608..124407a41ab0c 100644 --- a/shell/platform/common/cpp/public/flutter_plugin_registrar.h +++ b/shell/platform/common/cpp/public/flutter_plugin_registrar.h @@ -10,6 +10,7 @@ #include "flutter_export.h" #include "flutter_messenger.h" +#include "flutter_texture_registrar.h" #if defined(__cplusplus) extern "C" { @@ -26,6 +27,10 @@ typedef void (*FlutterDesktopOnRegistrarDestroyed)( FLUTTER_EXPORT FlutterDesktopMessengerRef FlutterDesktopRegistrarGetMessenger(FlutterDesktopPluginRegistrarRef registrar); +// Returns the texture registrar associated with this registrar. +FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef +FlutterDesktopGetTextureRegistrar(FlutterDesktopPluginRegistrarRef registrar); + // Registers a callback to be called when the plugin registrar is destroyed. FLUTTER_EXPORT void FlutterDesktopRegistrarSetDestructionHandler( FlutterDesktopPluginRegistrarRef registrar, diff --git a/shell/platform/common/cpp/public/flutter_texture_registrar.h b/shell/platform/common/cpp/public/flutter_texture_registrar.h new file mode 100644 index 0000000000000..0f57ffc685b8f --- /dev/null +++ b/shell/platform/common/cpp/public/flutter_texture_registrar.h @@ -0,0 +1,62 @@ +// 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_COMMON_CPP_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ + +#include +#include + +#include "flutter_export.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +// Opaque reference to a texture registrar. +typedef struct FlutterDesktopTextureRegistrar* + FlutterDesktopTextureRegistrarRef; + +// Constructs a pixel buffer object for the plugin side, providing +// height/width and buffer pointers. +typedef struct { + // Bitmap buffer pointer, currently only supports RGBA. + const uint8_t* buffer; + // Width of the pixel buffer. + size_t width; + // Height of the pixel buffer. + size_t height; +} PixelBuffer; + +// The pixel buffer copy callback definition is provided to +// the Flutter engine to copy the texture. +typedef const PixelBuffer* (*FlutterTextureCallback)(size_t width, + size_t height, + void* user_data); + +// Registers a new texture with the Flutter engine and returns the texture ID, +// The engine will use the |texture_callback| +// function to copy the pixel buffer from the plugin caller. +FLUTTER_EXPORT int64_t FlutterDesktopRegisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + FlutterTextureCallback texture_callback, + void* user_data); + +// Unregisters an existing texture from the Flutter engine for a |texture_id|. +// Returns true on success, false on failure. +FLUTTER_EXPORT bool FlutterDesktopUnregisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id); + +// Marks that a new texture frame is available for a given |texture_id|. +// Returns true on success, false on failure. +FLUTTER_EXPORT bool FlutterDesktopMarkExternalTextureFrameAvailable( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 8658b31203372..6a4e977ca2d0a 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -1045,3 +1045,31 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, messenger->engine->message_dispatcher->SetMessageCallback(channel, callback, user_data); } + +FlutterDesktopTextureRegistrarRef FlutterDesktopGetTextureRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + std::cerr << "GLFW Texture support is not implemented yet." << std::endl; + return nullptr; +} + +int64_t FlutterDesktopRegisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + FlutterTextureCallback texture_callback, + void* user_data) { + std::cerr << "GLFW Texture support is not implemented yet." << std::endl; + return -1; +} + +bool FlutterDesktopUnregisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + std::cerr << "GLFW Texture support is not implemented yet." << std::endl; + return false; +} + +bool FlutterDesktopMarkExternalTextureFrameAvailable( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + std::cerr << "GLFW Texture support is not implemented yet." << std::endl; + return false; +} diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index a5760a2522e6c..670628e483670 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -41,6 +41,8 @@ source_set("flutter_windows_source") { sources = [ "angle_surface_manager.cc", "angle_surface_manager.h", + "external_texture_gl.cc", + "external_texture_gl.h", "flutter_windows.cc", "flutter_windows_view.cc", "flutter_windows_view.h", @@ -75,6 +77,7 @@ source_set("flutter_windows_source") { deps = [ ":flutter_windows_headers", + "//flutter/fml", "//flutter/shell/platform/common/cpp:common_cpp", "//flutter/shell/platform/common/cpp:common_cpp_input", "//flutter/shell/platform/common/cpp/client_wrapper:client_wrapper", diff --git a/shell/platform/windows/external_texture_gl.cc b/shell/platform/windows/external_texture_gl.cc new file mode 100644 index 0000000000000..654eb95912943 --- /dev/null +++ b/shell/platform/windows/external_texture_gl.cc @@ -0,0 +1,131 @@ +// 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/windows/external_texture_gl.h" + +#include "flutter/fml/logging.h" + +// OpenGL ES and EGL includes +#include +#include +#include +#include +#include + +#include + +namespace flutter { + +typedef void (*glGenTexturesProc)(GLsizei n, GLuint* textures); +typedef void (*glDeleteTexturesProc)(GLsizei n, const GLuint* textures); +typedef void (*glBindTextureProc)(GLenum target, GLuint texture); +typedef void (*glTexParameteriProc)(GLenum target, GLenum pname, GLint param); +typedef void (*glTexImage2DProc)(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* data); + +struct GlProcs { + explicit GlProcs() { + glGenTextures = + reinterpret_cast(eglGetProcAddress("glGenTextures")); + glDeleteTextures = reinterpret_cast( + eglGetProcAddress("glDeleteTextures")); + glBindTexture = + reinterpret_cast(eglGetProcAddress("glBindTexture")); + glTexParameteri = reinterpret_cast( + eglGetProcAddress("glTexParameteri")); + glTexImage2D = + reinterpret_cast(eglGetProcAddress("glTexImage2D")); + + FML_DCHECK(glGenTextures); + FML_DCHECK(glDeleteTextures); + FML_DCHECK(glBindTexture); + FML_DCHECK(glTexParameteri); + FML_DCHECK(glTexImage2D); + } + + glGenTexturesProc glGenTextures; + glDeleteTexturesProc glDeleteTextures; + glBindTextureProc glBindTexture; + glTexParameteriProc glTexParameteri; + glTexImage2DProc glTexImage2D; +}; + +struct ExternalTextureGLState { + GLuint gl_texture = 0; + static const GlProcs procs; +}; + +const GlProcs ExternalTextureGLState::procs = []() { + GlProcs procs; + return procs; +}(); + +ExternalTextureGL::ExternalTextureGL(FlutterTextureCallback texture_callback, + void* user_data) + : state_(std::make_unique()), + texture_callback_(texture_callback), + user_data_(user_data) {} + +ExternalTextureGL::~ExternalTextureGL() { + auto deleteTextures = state_->procs.glDeleteTextures; + + if (state_->gl_texture != 0) { + deleteTextures(1, &state_->gl_texture); + } +} + +bool ExternalTextureGL::PopulateTextureWithIdentifier( + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture) { + const PixelBuffer* pixel_buffer = + texture_callback_(width, height, user_data_); + + if (!pixel_buffer || !pixel_buffer->buffer) { + std::cerr << "Failed to copy pixel buffer from plugin." << std::endl; + return false; + } + + if (state_->gl_texture == 0) { + state_->procs.glGenTextures(1, &state_->gl_texture); + + state_->procs.glBindTexture(GL_TEXTURE_2D, state_->gl_texture); + + state_->procs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_BORDER); + state_->procs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_BORDER); + + state_->procs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + state_->procs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + + } else { + state_->procs.glBindTexture(GL_TEXTURE_2D, state_->gl_texture); + } + + state_->procs.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_buffer->width, + pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, + pixel_buffer->buffer); + + opengl_texture->target = GL_TEXTURE_2D; + opengl_texture->name = state_->gl_texture; + opengl_texture->format = GL_RGBA8; + opengl_texture->destruction_callback = (VoidCallback) nullptr; + opengl_texture->user_data = static_cast(this); + opengl_texture->width = pixel_buffer->width; + opengl_texture->height = pixel_buffer->height; + + return true; +} + +} // namespace flutter diff --git a/shell/platform/windows/external_texture_gl.h b/shell/platform/windows/external_texture_gl.h new file mode 100644 index 0000000000000..2f398d9ef036e --- /dev/null +++ b/shell/platform/windows/external_texture_gl.h @@ -0,0 +1,51 @@ +// 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_WINDOWS_EXTERNAL_TEXTURE_GL_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_EXTERNAL_TEXTURE_GL_H_ + +#include + +#include + +#include "flutter/shell/platform/common/cpp/public/flutter_texture_registrar.h" +#include "flutter/shell/platform/embedder/embedder.h" + +namespace flutter { + +typedef struct ExternalTextureGLState ExternalTextureGLState; + +// An adaptation class of flutter engine and external texture interface. +class ExternalTextureGL { + public: + ExternalTextureGL(FlutterTextureCallback texture_callback, void* user_data); + + virtual ~ExternalTextureGL(); + + /** + * Returns the unique id for the ExternalTextureGL instance. + */ + int64_t texture_id() { return reinterpret_cast(this); } + + /** + * Accepts texture buffer copy request from the Flutter engine. + * When the user side marks the texture_id as available, the Flutter engine + * will callback to this method and ask for populate the |opengl_texture| + * object, such as the texture type and the format of the pixel buffer and the + * texture object. + * Returns true on success, false on failure. + */ + bool PopulateTextureWithIdentifier(size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture); + + private: + std::unique_ptr state_; + FlutterTextureCallback texture_callback_ = nullptr; + void* user_data_ = nullptr; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_EXTERNAL_TEXTURE_GL_H_ diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index b3dec79eb20cd..c91743e09355e 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -59,6 +59,23 @@ UniqueAotDataPtr LoadAotData(std::filesystem::path aot_data_path) { return UniqueAotDataPtr(data); } +static bool OnAcquireExternalTexture(void* user_data, + int64_t texture_id, + size_t width, + size_t height, + FlutterOpenGLTexture* texture) { + auto host = static_cast(user_data); + + const auto& textures = host->GetRegistrar()->texture_registrar->textures; + + auto it = textures.find(texture_id); + if (it != textures.end()) { + return it->second->PopulateTextureWithIdentifier(width, height, texture); + } + + return false; +} + // Spins up an instance of the Flutter Engine. // // This function launches the Flutter Engine in a background thread, supplying @@ -108,6 +125,7 @@ static std::unique_ptr RunFlutterEngine( auto host = static_cast(user_data); return host->MakeResourceCurrent(); }; + config.open_gl.gl_external_texture_frame_callback = OnAcquireExternalTexture; // Configure task runner interop. auto state_ptr = state.get(); @@ -383,3 +401,40 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, void* user_data) { messenger->dispatcher->SetMessageCallback(channel, callback, user_data); } + +FlutterDesktopTextureRegistrarRef FlutterDesktopGetTextureRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + return registrar->texture_registrar; +} + +int64_t FlutterDesktopRegisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + FlutterTextureCallback texture_callback, + void* user_data) { + auto texture_gl = + std::make_unique(texture_callback, user_data); + int64_t texture_id = texture_gl->texture_id(); + texture_registrar->textures[texture_id] = std::move(texture_gl); + if (FlutterEngineRegisterExternalTexture(texture_registrar->engine, + texture_id) == kSuccess) { + return texture_id; + } + return -1; +} + +bool FlutterDesktopUnregisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + auto it = texture_registrar->textures.find(texture_id); + if (it != texture_registrar->textures.end()) + texture_registrar->textures.erase(it); + return (FlutterEngineUnregisterExternalTexture(texture_registrar->engine, + texture_id) == kSuccess); +} + +bool FlutterDesktopMarkExternalTextureFrameAvailable( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id) { + return (FlutterEngineMarkExternalTextureFrameAvailable( + texture_registrar->engine, texture_id) == kSuccess); +} diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 4f6f55e12dc58..cbe1c7700c515 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -48,10 +48,15 @@ void FlutterWindowsView::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { messenger->engine = engine_; messenger->dispatcher = message_dispatcher_.get(); + texture_registrar_ = std::make_unique(); + texture_registrar_->engine = engine_; + window_wrapper_ = std::make_unique(); window_wrapper_->view = this; + plugin_registrar_ = std::make_unique(); plugin_registrar_->messenger = std::move(messenger); + plugin_registrar_->texture_registrar = texture_registrar_.get(); plugin_registrar_->view = window_wrapper_.get(); internal_plugin_registrar_ = diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 9a7b0994d2438..254f936ffd6e3 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -200,6 +200,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // The plugin registrar handle given to API clients. std::unique_ptr plugin_registrar_; + // The texture registrar handle given to API clients. + std::unique_ptr texture_registrar_; + // Message dispatch manager for messages from the Flutter engine. std::unique_ptr message_dispatcher_; diff --git a/shell/platform/windows/window_state.h b/shell/platform/windows/window_state.h index d1eceb866f507..c71fec7c588bd 100644 --- a/shell/platform/windows/window_state.h +++ b/shell/platform/windows/window_state.h @@ -8,6 +8,7 @@ #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/external_texture_gl.h" #include "flutter/shell/platform/windows/key_event_handler.h" #include "flutter/shell/platform/windows/keyboard_hook_handler.h" #include "flutter/shell/platform/windows/text_input_plugin.h" @@ -64,6 +65,9 @@ struct FlutterDesktopPluginRegistrar { // The plugin messenger handle given to API clients. std::unique_ptr messenger; + // The plugin texture registrar handle given to API clients. + FlutterDesktopTextureRegistrar* texture_registrar; + // The handle for the view associated with this registrar. FlutterDesktopView* view; @@ -71,6 +75,13 @@ struct FlutterDesktopPluginRegistrar { FlutterDesktopOnRegistrarDestroyed destruction_handler; }; +// State associated with the texture registrar. +struct FlutterDesktopTextureRegistrar { + FLUTTER_API_SYMBOL(FlutterEngine) engine; + // The texture registrar managing external texture adapters. + std::map> textures; +}; + // State associated with the messenger used to communicate with the engine. struct FlutterDesktopMessenger { // The Flutter engine this messenger sends outgoing messages to.