Skip to content

Commit

Permalink
Add support EGLImage-based texture
Browse files Browse the repository at this point in the history
  • Loading branch information
makotosato-at committed Feb 3, 2023
1 parent a03e186 commit d338eba
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 4 deletions.
1 change: 1 addition & 0 deletions cmake/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ int64_t TextureRegistrarImpl::RegisterTexture(TextureVariant* texture) {
auto texture = static_cast<GpuSurfaceTexture*>(user_data);
return texture->ObtainDescriptor(width, height);
};
} else if (auto egl_image_texture = std::get_if<EGLImageTexture>(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<EGLImageTexture*>(user_data);
return texture->GetEGLImage(width, height, egl_display, egl_context);
};
} else {
std::cerr << "Attempting to register unknown texture variant." << std::endl;
return -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<const FlutterDesktopEGLImage*(size_t width,
size_t height,
void* egl_display,
void* egl_context)>
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:
Expand Down Expand Up @@ -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<PixelBufferTexture, GpuSurfaceTexture> TextureVariant;
typedef std::variant<PixelBufferTexture, GpuSurfaceTexture, EGLImageTexture> TextureVariant;

// An object keeping track of external textures.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions src/flutter/shell/platform/linux_embedded/external_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -37,6 +39,7 @@ struct GlProcs {
glBindTextureProc glBindTexture;
glTexParameteriProc glTexParameteri;
glTexImage2DProc glTexImage2D;
glEGLImageTargetTexture2DOESProc glEGLImageTargetTexture2DOES;
bool valid;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <EGL/egl.h>
#include <EGL/eglext.h>

namespace flutter {

struct ExternalTextureEGLImageState {
GLuint gl_texture = 0;
};

ExternalTextureEGLImage::ExternalTextureEGLImage(
FlutterDesktopEGLImageTextureCallback texture_callback,
void* user_data,
const GlProcs& gl_procs)
: state_(std::make_unique<ExternalTextureEGLImageState>()),
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
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>

#include <memory>

#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<ExternalTextureEGLImageState> 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_
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -38,6 +39,15 @@ int64_t FlutterELinuxTextureRegistrar::RegisterTexture(
return EmplaceTexture(std::make_unique<flutter::ExternalTexturePixelBuffer>(
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<flutter::ExternalTextureEGLImage>(
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;
Expand Down Expand Up @@ -114,10 +124,12 @@ void FlutterELinuxTextureRegistrar::ResolveGlFunctions(GlProcs& procs) {
eglGetProcAddress("glTexParameteri"));
procs.glTexImage2D =
reinterpret_cast<glTexImage2DProc>(eglGetProcAddress("glTexImage2D"));

procs.glEGLImageTargetTexture2DOES =
reinterpret_cast<glEGLImageTargetTexture2DOESProc>(
eglGetProcAddress("glEGLImageTargetTexture2DOES"));
procs.valid = procs.glGenTextures && procs.glDeleteTextures &&
procs.glBindTexture && procs.glTexParameteri &&
procs.glTexImage2D;
procs.glTexImage2D && procs.glEGLImageTargetTexture2DOES;
}

}; // namespace flutter

0 comments on commit d338eba

Please sign in to comment.