Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 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",
Comment thread
anirudhb marked this conversation as 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 @@ -147,6 +150,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
48 changes: 47 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,20 @@ static bool fl_engine_gl_make_resource_current(void* user_data) {
return result;
}

static bool fl_engine_gl_external_texture_frame_callback(
Comment thread
anirudhb marked this conversation as 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 +285,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 +309,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 +329,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 +360,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 +593,32 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self,
FlutterEngineSendPointerEvent(self->engine, &fl_event, 1);
}

bool 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;
}

bool 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;
}
35 changes: 35 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,41 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine,
GAsyncResult* result,
GError** error);

/**
* fl_engine_mark_texture_frame_available:
* @engine: an #FlEngine.
* @texture_id: an int64_t.
Comment thread
anirudhb marked this conversation as resolved.
Outdated
*
* Tells the Flutter engine that a new texture frame is available for the given
* texture.
*
* Returns: true on success.
*/
bool fl_engine_mark_texture_frame_available(FlEngine* engine,
Comment thread
anirudhb marked this conversation as resolved.
Outdated
int64_t texture_id);

/**
* fl_engine_register_external_texture:
* @engine: an #FlEngine.
* @texture_id: an int64_t.
*
* Tells the Flutter engine that a new external texture is available.
*
* Returns: true on success.
*/
bool fl_engine_register_external_texture(FlEngine* engine, int64_t texture_id);

/**
* fl_engine_unregister_external_texture:
* @engine: an #FlEngine.
* @texture_id: an int64_t.
*
* 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_
133 changes: 133 additions & 0 deletions shell/platform/linux/fl_external_texture_gl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2020 The Flutter Authors. All rights reserved.
Comment thread
anirudhb marked this conversation as resolved.
Outdated
// 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>

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);
} gl;
Comment thread
anirudhb marked this conversation as resolved.
Outdated

struct _FlExternalTextureGl {
GLuint gl_texture_id;
Comment thread
anirudhb marked this conversation as 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);
if (gl.valid) {
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) {
return reinterpret_cast<int64_t>(self);
Comment thread
robert-ancell marked this conversation as resolved.
}

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

void fl_external_texture_gl_load_funcs(FlExternalTextureGl* self) {
gl.genTextures = reinterpret_cast<void (*)(GLsizei, GLuint*)>(
eglGetProcAddress("glGenTextures"));
gl.bindTexture = reinterpret_cast<void (*)(GLenum, GLuint)>(
eglGetProcAddress("glBindTexture"));
gl.texParameteri = reinterpret_cast<void (*)(GLenum, GLenum, GLenum)>(
eglGetProcAddress("glTexParameteri"));
gl.texImage2D =
reinterpret_cast<void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint,
GLenum, GLenum, const void*)>(
eglGetProcAddress("glTexImage2D"));
gl.deleteTextures = reinterpret_cast<void (*)(GLsizei, const GLuint*)>(
eglGetProcAddress("glDeleteTextures"));
gl.valid = true;
}

bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self,
size_t* width,
size_t* height) {
const FlPixelBuffer* pixel_buffer =
self->callback(*width, *height, self->user_data);
if (!pixel_buffer || !pixel_buffer->buffer) {
return false;
}
*width = pixel_buffer->width;
*height = pixel_buffer->height;

if (!gl.valid) {
fl_external_texture_gl_load_funcs(self);
}
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, pixel_buffer->width,
pixel_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixel_buffer->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