Skip to content

Commit

Permalink
Linux texture support
Browse files Browse the repository at this point in the history
  • Loading branch information
anirudhb committed Aug 27, 2020
1 parent b83762a commit 55a8182
Show file tree
Hide file tree
Showing 15 changed files with 587 additions and 6 deletions.
3 changes: 3 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",
"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
47 changes: 46 additions & 1 deletion shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
// found in the LICENSE file.

#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_engine_private.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(
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 @@ -344,6 +364,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 @@ -575,8 +597,31 @@ 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);
}

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

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.
*
* 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,
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_
131 changes: 131 additions & 0 deletions shell/platform/linux/fl_external_texture_gl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2020 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>

struct _FlExternalTextureGl {
GLuint gl_texture_id;
FlTextureCallback callback;
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;
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 (self->gl.valid) {
self->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);
}

bool fl_external_texture_gl_populate_texture(
FlExternalTextureGl* self,
size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture) {
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 = static_cast<void*>(self);
opengl_texture->width = real_width;
opengl_texture->height = real_height;

return true;
}

void fl_external_texture_gl_load_funcs(FlExternalTextureGl* self) {
self->gl.genTextures = reinterpret_cast<void (*)(GLsizei, GLuint*)>(
eglGetProcAddress("glGenTextures"));
self->gl.bindTexture = reinterpret_cast<void (*)(GLenum, GLuint)>(
eglGetProcAddress("glBindTexture"));
self->gl.texParameteri = reinterpret_cast<void (*)(GLenum, GLenum, GLenum)>(
eglGetProcAddress("glTexParameteri"));
self->gl.texImage2D =
reinterpret_cast<void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint,
GLenum, GLenum, const void*)>(
eglGetProcAddress("glTexImage2D"));
self->gl.deleteTextures = reinterpret_cast<void (*)(GLsizei, const GLuint*)>(
eglGetProcAddress("glDeleteTextures"));
self->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 (!self->gl.valid)
fl_external_texture_gl_load_funcs(self);
if (self->gl_texture_id == 0) {
self->gl.genTextures(1, &self->gl_texture_id);
self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id);
self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_BORDER);
self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_BORDER);
self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
self->gl.bindTexture(GL_TEXTURE_2D, self->gl_texture_id);
}
self->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;
}
85 changes: 85 additions & 0 deletions shell/platform/linux/fl_external_texture_gl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2020 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_FL_EXTERNAL_TEXURE_GL_H
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_EXTERNAL_TEXURE_GL_H

#include <glib-object.h>
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h"

G_BEGIN_DECLS

G_DECLARE_FINAL_TYPE(FlExternalTextureGl,
fl_external_texture_gl,
FL,
EXTERNAL_TEXTURE_GL,
GObject)

/**
* FlExternalTextureGl:
*
* #FlExternalTextureGl is an abstraction over OpenGL textures.
*/

/**
* fl_external_texture_gl_new:
* @texture_callback: An #FlTextureCallback.
* @user_data: A void*.
*
* Creates a new #FlExternalTextureGl.
*
* Returns: a new #FlExternalTextureGl.
*/
FlExternalTextureGl* fl_external_texture_gl_new(
FlTextureCallback texture_callback,
void* user_data);

/**
* fl_external_texture_gl_populate_texture:
* @width: a size_t.
* @height: a size_t.
* @opengl_texture: a FlutterOpenGLTexture*.
*
* Attempts to populate the specified |opengl_texture| with texture details
* such as the name, width, height and the pixel format upon successfully
* copying the buffer provided by |texture_callback_|. See
* |fl_external_texture_gl_copy_pixel_buffer|.
*
* Returns true on success or false if the pixel buffer could not be copied.
*/
bool fl_external_texture_gl_populate_texture(
FlExternalTextureGl* self,
size_t width,
size_t height,
FlutterOpenGLTexture* opengl_texture);

/**
* fl_external_texture_gl_texture_id:
*
* Retrieves the unique id of this texture.
*
* Returns an int64_t, which is the unique id of this texture.
*/
int64_t fl_external_texture_gl_texture_id(FlExternalTextureGl* self);

/**
* fl_external_texture_gl_copy_pixel_buffer:
* @width: a size_t.
* @height: a size_t.
*
* Attempts to copy the pixel buffer returned by |texture_callback_| to
* OpenGL. The |width| and |height| will be set to the actual bounds of the
* copied pixel buffer.
*
* Returns true on success or false if the pixel buffer returned by
* |texture_callback_| was invalid.
*/
bool fl_external_texture_gl_copy_pixel_buffer(FlExternalTextureGl* self,
size_t* width,
size_t* height);

G_END_DECLS

#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_EXTERNAL_TEXURE_GL_H
Loading

0 comments on commit 55a8182

Please sign in to comment.