Skip to content

Commit

Permalink
Support EmbedderExternalTextureGL for impeller (flutter-tizen#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaowei-guan committed Oct 23, 2024
1 parent c3db5d8 commit a71524f
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 15 deletions.
15 changes: 14 additions & 1 deletion flutter/shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ typedef struct {
} FlutterTransformation;

typedef void (*VoidCallback)(void* /* user data */);
typedef bool (*BoolCallback)(void* /* user data */);

typedef enum {
/// Specifies an OpenGL texture target type. Textures are specified using
Expand Down Expand Up @@ -361,6 +362,11 @@ typedef enum {
kFlutterSoftwarePixelFormatNative32,
} FlutterSoftwarePixelFormat;

typedef enum {
kFlutterGLImpellerTexturePixelBuffer,
kFlutterGLImpellerTextureGpuSurface,
} FlutterGLImpellerTextureType;

typedef struct {
/// Target texture of the active texture unit (example GL_TEXTURE_2D or
/// GL_TEXTURE_RECTANGLE).
Expand All @@ -369,6 +375,14 @@ typedef struct {
uint32_t name;
/// The texture format (example GL_RGBA8).
uint32_t format;
/// The pixel data buffer.
const uint8_t* buffer;
/// The size of pixel buffer.
size_t buffer_size;
/// Callback invoked that the gpu surface texture start binding.
BoolCallback bind_callback;
/// The type of the texture.
FlutterGLImpellerTextureType impeller_texture_type;
/// User data to be returned on the invocation of the destruction callback.
void* user_data;
/// Callback invoked (on an engine managed thread) that asks the embedder to
Expand Down Expand Up @@ -401,7 +415,6 @@ typedef struct {
VoidCallback destruction_callback;
} FlutterOpenGLFramebuffer;

typedef bool (*BoolCallback)(void* /* user data */);
typedef FlutterTransformation (*TransformationCallback)(void* /* user data */);
typedef uint32_t (*UIntCallback)(void* /* user data */);
typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */,
Expand Down
2 changes: 2 additions & 0 deletions flutter/shell/platform/tizen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ template("embedder") {
"channels/text_input_channel.cc",
"channels/window_channel.cc",
"external_texture_pixel_egl.cc",
"external_texture_pixel_egl_impeller.cc",
"external_texture_pixel_evas_gl.cc",
"external_texture_surface_egl.cc",
"external_texture_surface_egl_impeller.cc",
"external_texture_surface_evas_gl.cc",
"flutter_platform_node_delegate_tizen.cc",
"flutter_project_bundle.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "external_texture_pixel_egl_impeller.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl32.h>

#include "flutter/shell/platform/tizen/logger.h"

namespace flutter {

bool ExternalTexturePixelEGLImpeller::PopulateTexture(
size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) {
if (!texture_callback_) {
return false;
}

const FlutterDesktopPixelBuffer* pixel_buffer =
texture_callback_(width, height, user_data_);

if (!pixel_buffer || !pixel_buffer->buffer) {
return false;
}

width = pixel_buffer->width;
height = pixel_buffer->height;

// Populate the texture object used by the engine.
opengl_texture->impeller_texture_type =
FlutterGLImpellerTextureType::kFlutterGLImpellerTexturePixelBuffer;
opengl_texture->buffer = pixel_buffer->buffer;
opengl_texture->buffer_size =
size_t(pixel_buffer->width) * size_t(pixel_buffer->height) * 4;
opengl_texture->destruction_callback = nullptr;
opengl_texture->user_data = nullptr;
opengl_texture->width = width;
opengl_texture->height = height;
return true;
}

ExternalTexturePixelEGLImpeller::ExternalTexturePixelEGLImpeller(
FlutterDesktopPixelBufferTextureCallback texture_callback,
void* user_data)
: ExternalTexture(),
texture_callback_(texture_callback),
user_data_(user_data) {}

} // namespace flutter
33 changes: 33 additions & 0 deletions flutter/shell/platform/tizen/external_texture_pixel_egl_impeller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EMBEDDER_EXTERNAL_TEXTURE_PIXEL_EGL_IMPELLER_H
#define EMBEDDER_EXTERNAL_TEXTURE_PIXEL_EGL_IMPELLER_H

#include "flutter/shell/platform/common/public/flutter_texture_registrar.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/tizen/external_texture.h"

namespace flutter {

class ExternalTexturePixelEGLImpeller : public ExternalTexture {
public:
ExternalTexturePixelEGLImpeller(
FlutterDesktopPixelBufferTextureCallback texture_callback,
void* user_data);

~ExternalTexturePixelEGLImpeller() = default;

bool PopulateTexture(size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) override;

private:
FlutterDesktopPixelBufferTextureCallback texture_callback_ = nullptr;
void* user_data_ = nullptr;
};

} // namespace flutter

#endif // EMBEDDER_EXTERNAL_TEXTURE_PIXEL_EGL_IMPELLER_H
189 changes: 189 additions & 0 deletions flutter/shell/platform/tizen/external_texture_surface_egl_impeller.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "external_texture_surface_egl_impeller.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl32.h>
#include <tbm_bufmgr.h>
#include <tbm_surface.h>
#include <tbm_surface_internal.h>
#include <type_traits>
#ifndef EGL_DMA_BUF_PLANE3_FD_EXT
#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
#endif
#ifndef EGL_DMA_BUF_PLANE3_OFFSET_EXT
#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
#endif
#ifndef EGL_DMA_BUF_PLANE3_PITCH_EXT
#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
#endif

#include "flutter/shell/platform/tizen/logger.h"

namespace flutter {

ExternalTextureSurfaceEGLImpeller::ExternalTextureSurfaceEGLImpeller(
ExternalTextureExtensionType gl_extension,
FlutterDesktopGpuSurfaceTextureCallback texture_callback,
void* user_data)
: ExternalTexture(gl_extension),
texture_callback_(texture_callback),
user_data_(user_data) {}

ExternalTextureSurfaceEGLImpeller::~ExternalTextureSurfaceEGLImpeller() {
ReleaseImage();
}

bool ExternalTextureSurfaceEGLImpeller::PopulateTexture(
size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) {
if (!texture_callback_) {
return false;
}
const FlutterDesktopGpuSurfaceDescriptor* gpu_surface =
texture_callback_(width, height, user_data_);
if (!gpu_surface) {
FT_LOG(Info) << "gpu_surface is null for texture ID: " << texture_id_;
return false;
}

if (!CreateOrUpdateEglImage(gpu_surface)) {
FT_LOG(Info) << "CreateOrUpdateEglImage fail for texture ID: "
<< texture_id_;
return false;
}

opengl_texture->impeller_texture_type =
FlutterGLImpellerTextureType::kFlutterGLImpellerTextureGpuSurface;
opengl_texture->bind_callback = OnBindCallback;
opengl_texture->destruction_callback = nullptr;
opengl_texture->user_data = this;
opengl_texture->width = width;
opengl_texture->height = height;
return true;
}

bool ExternalTextureSurfaceEGLImpeller::CreateOrUpdateEglImage(
const FlutterDesktopGpuSurfaceDescriptor* descriptor) {
if (descriptor == nullptr || descriptor->handle == nullptr) {
ReleaseImage();
return false;
}
void* handle = descriptor->handle;
if (handle != last_surface_handle_) {
ReleaseImage();

const tbm_surface_h tbm_surface =
reinterpret_cast<tbm_surface_h>(descriptor->handle);

tbm_surface_info_s info;
if (tbm_surface_get_info(tbm_surface, &info) != TBM_SURFACE_ERROR_NONE) {
if (descriptor->release_callback) {
descriptor->release_callback(descriptor->release_context);
}
return false;
}

PFNEGLCREATEIMAGEKHRPROC n_eglCreateImageKHR =
reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(
eglGetProcAddress("eglCreateImageKHR"));

if (state_->gl_extension == ExternalTextureExtensionType::kNativeSurface) {
const EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE,
EGL_NONE};
egl_src_image_ =
n_eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
EGL_NATIVE_SURFACE_TIZEN, tbm_surface, attribs);
} else if (state_->gl_extension ==
ExternalTextureExtensionType::kDmaBuffer) {
EGLint attribs[50];
int atti = 0;
int plane_fd_ext[4] = {
EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE1_FD_EXT,
EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE3_FD_EXT};
int plane_offset_ext[4] = {
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT,
EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT};
int plane_pitch_ext[4] = {
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT,
EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT};

attribs[atti++] = EGL_WIDTH;
attribs[atti++] = info.width;
attribs[atti++] = EGL_HEIGHT;
attribs[atti++] = info.height;
attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[atti++] = info.format;

int num_planes = tbm_surface_internal_get_num_planes(info.format);
for (int i = 0; i < num_planes; i++) {
int bo_idx = tbm_surface_internal_get_plane_bo_idx(tbm_surface, i);
tbm_bo tbo = tbm_surface_internal_get_bo(tbm_surface, bo_idx);
attribs[atti++] = plane_fd_ext[i];
attribs[atti++] = static_cast<int>(reinterpret_cast<size_t>(
tbm_bo_get_handle(tbo, TBM_DEVICE_3D).ptr));
attribs[atti++] = plane_offset_ext[i];
attribs[atti++] = info.planes[i].offset;
attribs[atti++] = plane_pitch_ext[i];
attribs[atti++] = info.planes[i].stride;
}
attribs[atti++] = EGL_NONE;
egl_src_image_ =
n_eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, nullptr, attribs);
}
if (!egl_src_image_) {
if (state_->gl_extension != ExternalTextureExtensionType::kNone) {
FT_LOG(Error) << "eglCreateImageKHR failed with an error "
<< eglGetError() << " for texture ID: " << texture_id_;
} else {
FT_LOG(Error) << "Either EGL_TIZEN_image_native_surface or "
"EGL_EXT_image_dma_buf_import shoule be supported.";
}
if (descriptor->release_callback) {
descriptor->release_callback(descriptor->release_context);
}
return false;
}
last_surface_handle_ = handle;
}
if (descriptor->release_callback) {
descriptor->release_callback(descriptor->release_context);
}
return true;
}

void ExternalTextureSurfaceEGLImpeller::ReleaseImage() {
if (egl_src_image_) {
PFNEGLDESTROYIMAGEKHRPROC n_eglDestroyImageKHR =
reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(
eglGetProcAddress("eglDestroyImageKHR"));
n_eglDestroyImageKHR(eglGetCurrentDisplay(), egl_src_image_);
egl_src_image_ = nullptr;
}
}

bool ExternalTextureSurfaceEGLImpeller::OnBindCallback(void* user_data) {
ExternalTextureSurfaceEGLImpeller* self =
static_cast<ExternalTextureSurfaceEGLImpeller*>(user_data);
return self->OnBind();
}

bool ExternalTextureSurfaceEGLImpeller::OnBind() {
if (!egl_src_image_) {
return false;
}
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES =
reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
eglGetProcAddress("glEGLImageTargetTexture2DOES"));
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_src_image_);
return true;
}

} // namespace flutter
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EMBEDDER_EXTERNAL_TEXTURE_SURFACE_EGL_IMPELLER_H_
#define EMBEDDER_EXTERNAL_TEXTURE_SURFACE_EGL_IMPELLER_H_

#include "flutter/shell/platform/common/public/flutter_texture_registrar.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/tizen/external_texture.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>

namespace flutter {

class ExternalTextureSurfaceEGLImpeller : public ExternalTexture {
public:
ExternalTextureSurfaceEGLImpeller(
ExternalTextureExtensionType gl_extension,
FlutterDesktopGpuSurfaceTextureCallback texture_callback,
void* user_data);

virtual ~ExternalTextureSurfaceEGLImpeller();

// 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 to 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 PopulateTexture(size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) override;

private:
static bool OnBindCallback(void* user_data);
bool CreateOrUpdateEglImage(
const FlutterDesktopGpuSurfaceDescriptor* descriptor);
void ReleaseImage();
bool OnBind();
FlutterDesktopGpuSurfaceTextureCallback texture_callback_ = nullptr;
void* user_data_ = nullptr;
EGLImageKHR egl_src_image_ = nullptr;
void* last_surface_handle_ = nullptr;
};

} // namespace flutter

#endif // EMBEDDER_EXTERNAL_TEXTURE_SURFACE_EGL_IMPELLER_H_
3 changes: 2 additions & 1 deletion flutter/shell/platform/tizen/flutter_tizen_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ bool FlutterTizenEngine::RunEngine() {
settings_channel_ = std::make_unique<SettingsChannel>(
internal_plugin_registrar_->messenger());
if (IsHeaded()) {
texture_registrar_ = std::make_unique<FlutterTizenTextureRegistrar>(this);
texture_registrar_ = std::make_unique<FlutterTizenTextureRegistrar>(
this, project_->HasArgument("--enable-impeller"));
keyboard_channel_ = std::make_unique<KeyboardChannel>(
internal_plugin_registrar_->messenger(),
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
Expand Down
Loading

0 comments on commit a71524f

Please sign in to comment.