From d338ebac74880372c7738824cd37fcb3ea01fce9 Mon Sep 17 00:00:00 2001 From: Makoto Sato Date: Fri, 3 Feb 2023 10:17:51 +0900 Subject: [PATCH] Add support EGLImage-based texture --- cmake/build.cmake | 1 + .../client_wrapper/core_implementations.cc | 9 ++ .../include/flutter/texture_registrar.h | 34 +++++++- .../common/public/flutter_texture_registrar.h | 34 +++++++- .../linux_embedded/external_texture.h | 3 + .../external_texture_egl_image.cc | 87 +++++++++++++++++++ .../external_texture_egl_image.h | 51 +++++++++++ .../flutter_elinux_texture_registrar.cc | 16 +++- 8 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 src/flutter/shell/platform/linux_embedded/external_texture_egl_image.cc create mode 100644 src/flutter/shell/platform/linux_embedded/external_texture_egl_image.h diff --git a/cmake/build.cmake b/cmake/build.cmake index 8ea841a6..42308b4d 100644 --- a/cmake/build.cmake +++ b/cmake/build.cmake @@ -136,6 +136,7 @@ set(ELINUX_COMMON_SRC "src/flutter/shell/platform/linux_embedded/system_utils.cc" "src/flutter/shell/platform/linux_embedded/logger.cc" "src/flutter/shell/platform/linux_embedded/external_texture_pixelbuffer.cc" + "src/flutter/shell/platform/linux_embedded/external_texture_egl_image.cc" "src/flutter/shell/platform/linux_embedded/vsync_waiter.cc" "src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc" "src/flutter/shell/platform/linux_embedded/plugins/keyboard_glfw_util.cc" diff --git a/src/flutter/shell/platform/common/client_wrapper/core_implementations.cc b/src/flutter/shell/platform/common/client_wrapper/core_implementations.cc index e90b26cd..3aae66ca 100644 --- a/src/flutter/shell/platform/common/client_wrapper/core_implementations.cc +++ b/src/flutter/shell/platform/common/client_wrapper/core_implementations.cc @@ -180,6 +180,15 @@ int64_t TextureRegistrarImpl::RegisterTexture(TextureVariant* texture) { auto texture = static_cast(user_data); return texture->ObtainDescriptor(width, height); }; + } else if (auto egl_image_texture = std::get_if(texture)) { + info.type = kFlutterDesktopEGLImageTexture; + info.egl_image_config.user_data = egl_image_texture; + info.egl_image_config.callback = + [](size_t width, size_t height, void* egl_display, void* egl_context, + void* user_data) -> const FlutterDesktopEGLImage* { + auto texture = static_cast(user_data); + return texture->GetEGLImage(width, height, egl_display, egl_context); + }; } else { std::cerr << "Attempting to register unknown texture variant." << std::endl; return -1; diff --git a/src/flutter/shell/platform/common/client_wrapper/include/flutter/texture_registrar.h b/src/flutter/shell/platform/common/client_wrapper/include/flutter/texture_registrar.h index 7a2078f1..4abe19d9 100644 --- a/src/flutter/shell/platform/common/client_wrapper/include/flutter/texture_registrar.h +++ b/src/flutter/shell/platform/common/client_wrapper/include/flutter/texture_registrar.h @@ -42,6 +42,38 @@ class PixelBufferTexture { const CopyBufferCallback copy_buffer_callback_; }; +// A EGLImage texture. +class EGLImageTexture { + public: + // A callback used for retrieving pixel buffers. + typedef std::function + GetEGLImageCallback; + + // Creates a EGLImage texture that uses the provided |get_egl_image_cb| to + // retrieve the EGLImage. + // As the callback is usually invoked from the render thread, the callee must + // take care of proper synchronization. It also needs to be ensured that the + // returned buffer isn't released prior to unregistering this texture. + explicit EGLImageTexture(GetEGLImageCallback get_egl_image_callback) + : get_egl_image_callback_(get_egl_image_callback) {} + + // Returns the callback-provided FlutterDesktopEGLImage. + // The intended surface size is specified by |width| and + // |height|. + const FlutterDesktopEGLImage* GetEGLImage(size_t width, + size_t height, + void* egl_display, + void* egl_context) const { + return get_egl_image_callback_(width, height, egl_display, egl_context); + } + + private: + const GetEGLImageCallback get_egl_image_callback_; +}; + // A GPU surface-based texture. class GpuSurfaceTexture { public: @@ -75,7 +107,7 @@ class GpuSurfaceTexture { // The available texture variants. // Only PixelBufferTexture is currently implemented. // Other variants are expected to be added in the future. -typedef std::variant TextureVariant; +typedef std::variant TextureVariant; // An object keeping track of external textures. // diff --git a/src/flutter/shell/platform/common/public/flutter_texture_registrar.h b/src/flutter/shell/platform/common/public/flutter_texture_registrar.h index 3ca0785e..cc0dbd2d 100644 --- a/src/flutter/shell/platform/common/public/flutter_texture_registrar.h +++ b/src/flutter/shell/platform/common/public/flutter_texture_registrar.h @@ -25,7 +25,9 @@ typedef enum { // A Pixel buffer-based texture. kFlutterDesktopPixelBufferTexture, // A platform-specific GPU surface-backed texture. - kFlutterDesktopGpuSurfaceTexture + kFlutterDesktopGpuSurfaceTexture, + // An EGLImage-based texture + kFlutterDesktopEGLImageTexture } FlutterDesktopTextureType; // Supported GPU surface types. @@ -66,6 +68,20 @@ typedef struct { void* release_context; } FlutterDesktopPixelBuffer; +// An EGLImage object. +typedef struct { + // The EGLImage object.(opaque) + const void* egl_image; + // Width of the EGLImage. + size_t width; + // Height of the EGLImage. + size_t height; + // An optional callback that gets invoked when the |egl_image| can be released. + void (*release_callback)(void* release_context); + // Opaque data passed to |release_callback|. + void* release_context; +} FlutterDesktopEGLImage; + // A GPU surface descriptor. typedef struct { // The size of this struct. Must be @@ -126,6 +142,13 @@ typedef const FlutterDesktopGpuSurfaceDescriptor* ( size_t height, void* user_data); +typedef const FlutterDesktopEGLImage* ( + *FlutterDesktopEGLImageTextureCallback)(size_t width, + size_t height, + void* egl_display, + void* egl_context, + void* user_data); + // An object used to configure pixel buffer textures. typedef struct { // The callback used by the engine to copy the pixel buffer object. @@ -148,11 +171,20 @@ typedef struct { void* user_data; } FlutterDesktopGpuSurfaceTextureConfig; +// An object used to configure EGLImage textures. +typedef struct { + // The callback used by the engine to get the EGLImage object. + FlutterDesktopEGLImageTextureCallback callback; + // Opaque data that will get passed to the provided |callback|. + void* user_data; +} FlutterDesktopEGLImageTextureConfig; + typedef struct { FlutterDesktopTextureType type; union { FlutterDesktopPixelBufferTextureConfig pixel_buffer_config; FlutterDesktopGpuSurfaceTextureConfig gpu_surface_config; + FlutterDesktopEGLImageTextureConfig egl_image_config; }; } FlutterDesktopTextureInfo; diff --git a/src/flutter/shell/platform/linux_embedded/external_texture.h b/src/flutter/shell/platform/linux_embedded/external_texture.h index e6e92c8f..0a4ce93d 100644 --- a/src/flutter/shell/platform/linux_embedded/external_texture.h +++ b/src/flutter/shell/platform/linux_embedded/external_texture.h @@ -29,6 +29,8 @@ typedef void (*glTexImage2DProc)(GLenum target, GLenum format, GLenum type, const void* data); +typedef void (*glEGLImageTargetTexture2DOESProc)(GLenum target, + GLeglImageOES image); // A struct containing pointers to resolved gl* functions. struct GlProcs { @@ -37,6 +39,7 @@ struct GlProcs { glBindTextureProc glBindTexture; glTexParameteriProc glTexParameteri; glTexImage2DProc glTexImage2D; + glEGLImageTargetTexture2DOESProc glEGLImageTargetTexture2DOES; bool valid; }; diff --git a/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.cc b/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.cc new file mode 100644 index 00000000..c9bd22ac --- /dev/null +++ b/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.cc @@ -0,0 +1,87 @@ +// 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_embedded/external_texture_egl_image.h" +#include +#include + +namespace flutter { + +struct ExternalTextureEGLImageState { + GLuint gl_texture = 0; +}; + +ExternalTextureEGLImage::ExternalTextureEGLImage( + FlutterDesktopEGLImageTextureCallback texture_callback, + void* user_data, + const GlProcs& gl_procs) + : state_(std::make_unique()), + texture_callback_(texture_callback), + user_data_(user_data), + gl_(gl_procs) {} + +ExternalTextureEGLImage::~ExternalTextureEGLImage() { + if (state_->gl_texture != 0) { + gl_.glDeleteTextures(1, &state_->gl_texture); + } +} + +bool ExternalTextureEGLImage::PopulateTexture( + size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture) { + if (!GetEGLImage(width, height, eglGetCurrentDisplay(), eglGetCurrentContext())) { + return false; + } + + // Populate the texture object used by the engine. + opengl_texture->target = GL_TEXTURE_2D; + opengl_texture->name = state_->gl_texture; +#ifdef USE_GLES3 + opengl_texture->format = GL_RGBA8; +#else + opengl_texture->format = GL_RGBA8_OES; +#endif + opengl_texture->destruction_callback = nullptr; + opengl_texture->user_data = nullptr; + opengl_texture->width = width; + opengl_texture->height = height; + + return true; +} + +bool ExternalTextureEGLImage::GetEGLImage(size_t& width, + size_t& height, + void* egl_display, + void* egl_context) { + using namespace std; + + const FlutterDesktopEGLImage* egl_image = + texture_callback_(width, height, egl_display, egl_context, user_data_); + if (!egl_image || !egl_image->egl_image) { + return false; + } + width = egl_image->width; + height = egl_image->height; + + if (state_->gl_texture == 0) { + gl_.glGenTextures(1, &state_->gl_texture); + + gl_.glBindTexture(GL_TEXTURE_2D, state_->gl_texture); + gl_.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl_.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl_.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl_.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + gl_.glBindTexture(GL_TEXTURE_2D, state_->gl_texture); + } + gl_.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (EGLImageKHR) egl_image->egl_image); + + if (egl_image->release_callback) { + egl_image->release_callback(egl_image->release_context); + } + return true; +} + +} // namespace flutter diff --git a/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.h b/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.h new file mode 100644 index 00000000..3de389a0 --- /dev/null +++ b/src/flutter/shell/platform/linux_embedded/external_texture_egl_image.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_LINUX_EMBEDDED_EXTERNAL_TEXTURE_EGL_IMAGE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_EMBEDDED_EXTERNAL_TEXTURE_EGL_IMAGE_H_ + +#include + +#include + +#include "flutter/shell/platform/common/public/flutter_texture_registrar.h" + +#include "flutter/shell/platform/linux_embedded/external_texture.h" + +namespace flutter { + +typedef struct ExternalTextureEGLImageState ExternalTextureEGLImageState; + +// An abstraction of an EGL Image based texture. +class ExternalTextureEGLImage : public ExternalTexture { + public: + ExternalTextureEGLImage( + FlutterDesktopEGLImageTextureCallback texture_callback, + void* user_data, + const GlProcs& gl_procs); + + virtual ~ExternalTextureEGLImage(); + + // |ExternalTexture| + bool PopulateTexture(size_t width, + size_t height, + FlutterOpenGLTexture* opengl_texture) override; + + private: + // Attempts to get the EGLImage returned by |texture_callback_| to + // OpenGL. + // The |width| and |height| will be set to the actual bounds of the EGLImage + // Returns true on success or false if the EGLImage returned + // by |texture_callback_| was invalid. + bool GetEGLImage(size_t& width, size_t& height, void* egl_display, void* egl_context); + + std::unique_ptr state_; + FlutterDesktopEGLImageTextureCallback texture_callback_ = nullptr; + void* const user_data_ = nullptr; + const GlProcs& gl_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_EMBEDDED_EXTERNAL_TEXTURE_EGL_IMAGE_H_ diff --git a/src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc b/src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc index 29fcbdd9..2a1c2695 100644 --- a/src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc +++ b/src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc @@ -9,6 +9,7 @@ #include "flutter/shell/platform/embedder/embedder_struct_macros.h" #include "flutter/shell/platform/linux_embedded/external_texture_pixelbuffer.h" +#include "flutter/shell/platform/linux_embedded/external_texture_egl_image.h" #include "flutter/shell/platform/linux_embedded/flutter_elinux_engine.h" #include "flutter/shell/platform/linux_embedded/flutter_elinux_view.h" @@ -38,6 +39,15 @@ int64_t FlutterELinuxTextureRegistrar::RegisterTexture( return EmplaceTexture(std::make_unique( texture_info->pixel_buffer_config.callback, texture_info->pixel_buffer_config.user_data, gl_procs_)); + } else if (texture_info->type == kFlutterDesktopEGLImageTexture){ + if (!texture_info->egl_image_config.callback) { + std::cerr << "Invalid EGLImage texture callback." << std::endl; + return kInvalidTexture; + } + + return EmplaceTexture(std::make_unique( + texture_info->egl_image_config.callback, + texture_info->egl_image_config.user_data, gl_procs_)); } else if (texture_info->type == kFlutterDesktopGpuSurfaceTexture) { std::cerr << "GpuSurfaceTexture is not yet supported." << std::endl; return kInvalidTexture; @@ -114,10 +124,12 @@ void FlutterELinuxTextureRegistrar::ResolveGlFunctions(GlProcs& procs) { eglGetProcAddress("glTexParameteri")); procs.glTexImage2D = reinterpret_cast(eglGetProcAddress("glTexImage2D")); - + procs.glEGLImageTargetTexture2DOES = + reinterpret_cast( + eglGetProcAddress("glEGLImageTargetTexture2DOES")); procs.valid = procs.glGenTextures && procs.glDeleteTextures && procs.glBindTexture && procs.glTexParameteri && - procs.glTexImage2D; + procs.glTexImage2D && procs.glEGLImageTargetTexture2DOES; } }; // namespace flutter