Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux texture support #20714

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions shell/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
anirudhb marked this conversation as resolved.
Show resolved Hide resolved
"fl_json_message_codec.cc",
"fl_json_method_codec.cc",
"fl_key_event_plugin.cc",
Expand All @@ -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",
]
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
15 changes: 1 addition & 14 deletions shell/platform/linux/fl_binary_messenger_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<FlEngine*>(g_object_ref(engine));
}
#include "flutter/shell/platform/linux/testing/fl_test.h"

// Checks sending nullptr for a message works.
TEST(FlBinaryMessengerTest, SendNullptrMessage) {
Expand Down
50 changes: 49 additions & 1 deletion shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <gmodule.h>
Expand All @@ -27,6 +29,7 @@ struct _FlEngine {
FlDartProject* project;
FlRenderer* renderer;
FlBinaryMessenger* binary_messenger;
FlTextureRegistrar* texture_registrar;
FlutterEngineAOTData aot_data;
FLUTTER_API_SYMBOL(FlutterEngine) engine;

Expand Down Expand Up @@ -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(
anirudhb marked this conversation as resolved.
Show resolved Hide resolved
void* user_data,
int64_t texture_id,
size_t width,
size_t height,
FlutterOpenGLTexture* texture) {
FlEngine* self = static_cast<FlEngine*>(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<FlEngine*>(user_data);
Expand Down Expand Up @@ -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(
Expand All @@ -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) {
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
36 changes: 36 additions & 0 deletions shell/platform/linux/fl_engine_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
136 changes: 136 additions & 0 deletions shell/platform/linux/fl_external_texture_gl.cc
Original file line number Diff line number Diff line change
@@ -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 <EGL/egl.h>
#include <GL/gl.h>
#include <gmodule.h>

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<void (*)(GLsizei, GLuint*)>(
eglGetProcAddress("glGenTextures"));
funcs.bindTexture = reinterpret_cast<void (*)(GLenum, GLuint)>(
eglGetProcAddress("glBindTexture"));
funcs.texParameteri = reinterpret_cast<void (*)(GLenum, GLenum, GLenum)>(
eglGetProcAddress("glTexParameteri"));
funcs.texImage2D =
reinterpret_cast<void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint,
GLenum, GLenum, const void*)>(
eglGetProcAddress("glTexImage2D"));
funcs.deleteTextures = reinterpret_cast<void (*)(GLsizei, const GLuint*)>(
eglGetProcAddress("glDeleteTextures"));
funcs.valid = true;
}
return &funcs;
}

struct _FlExternalTextureGl {
GObject parent_instance;
GLuint gl_texture_id;
anirudhb marked this conversation as resolved.
Show resolved Hide resolved
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<int64_t>(self);
robert-ancell marked this conversation as resolved.
Show resolved Hide resolved
}

gboolean fl_external_texture_gl_populate_texture(
FlExternalTextureGl* self,
size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) {
anirudhb marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Loading