Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
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
8 changes: 4 additions & 4 deletions shell/platform/linux/egl_utils_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ TEST(EGLUtils, ErrorToStringNegative) {

TEST(EGLUtils, ConfigToString) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);
EXPECT_TRUE(eglInitialize(display, nullptr, nullptr));
EGLConfig config;
eglChooseConfig(display, nullptr, &config, 1, nullptr);
EXPECT_TRUE(eglChooseConfig(display, nullptr, &config, 1, nullptr));
g_autofree gchar* config_string = egl_config_to_string(display, config);
EXPECT_STREQ(
config_string,
Expand All @@ -46,9 +46,9 @@ TEST(EGLUtils, ConfigToString) {

TEST(EGLUtils, ConfigToStringNullptr) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);
EXPECT_TRUE(eglInitialize(display, nullptr, nullptr));
EGLConfig config;
eglChooseConfig(display, nullptr, &config, 1, nullptr);
EXPECT_TRUE(eglChooseConfig(display, nullptr, &config, 1, nullptr));
g_autofree gchar* config_string1 = egl_config_to_string(nullptr, config);
EXPECT_STREQ(config_string1, "");
g_autofree gchar* config_string2 = egl_config_to_string(display, nullptr);
Expand Down
9 changes: 6 additions & 3 deletions shell/platform/linux/fl_basic_message_channel_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
static FlEngine* make_mock_engine() {
g_autoptr(FlDartProject) project = fl_dart_project_new();
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
g_autoptr(GError) renderer_error = nullptr;
EXPECT_TRUE(fl_renderer_setup(FL_RENDERER(renderer), &renderer_error));
EXPECT_EQ(renderer_error, nullptr);
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));
EXPECT_EQ(error, nullptr);
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));
}
Expand Down
9 changes: 6 additions & 3 deletions shell/platform/linux/fl_binary_messenger_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
static FlEngine* make_mock_engine() {
g_autoptr(FlDartProject) project = fl_dart_project_new();
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
g_autoptr(GError) renderer_error = nullptr;
EXPECT_TRUE(fl_renderer_setup(FL_RENDERER(renderer), &renderer_error));
EXPECT_EQ(renderer_error, nullptr);
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));
EXPECT_EQ(error, nullptr);
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));
}
Expand Down
9 changes: 6 additions & 3 deletions shell/platform/linux/fl_method_channel_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
static FlEngine* make_mock_engine() {
g_autoptr(FlDartProject) project = fl_dart_project_new();
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
g_autoptr(GError) renderer_error = nullptr;
EXPECT_TRUE(fl_renderer_setup(FL_RENDERER(renderer), &renderer_error));
EXPECT_EQ(renderer_error, nullptr);
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));
EXPECT_EQ(error, nullptr);
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));
}
Expand Down
84 changes: 54 additions & 30 deletions shell/platform/linux/fl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error)

typedef struct {
EGLDisplay egl_display;
EGLConfig egl_config;
EGLSurface egl_surface;
EGLContext egl_context;

Expand All @@ -30,22 +31,24 @@ static void create_resource_surface(FlRenderer* self, EGLConfig config) {
EGL_NONE};
priv->resource_surface = eglCreatePbufferSurface(priv->egl_display, config,
resource_context_attribs);
if (priv->resource_surface == nullptr) {
if (priv->resource_surface == EGL_NO_SURFACE) {
g_warning("Failed to create EGL resource surface: %s",
egl_error_to_string(eglGetError()));
return;
}

priv->resource_context = eglCreateContext(
priv->egl_display, config, priv->egl_context, context_attributes);
if (priv->resource_context == nullptr)
if (priv->resource_context == EGL_NO_CONTEXT)
g_warning("Failed to create EGL resource context: %s",
egl_error_to_string(eglGetError()));
}

// Default implementation for the start virtual method.
// Provided so subclasses can chain up to here.
static gboolean fl_renderer_real_start(FlRenderer* self, GError** error) {
static void fl_renderer_class_init(FlRendererClass* klass) {}

static void fl_renderer_init(FlRenderer* self) {}

gboolean fl_renderer_setup(FlRenderer* self, GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

Expand Down Expand Up @@ -73,71 +76,91 @@ static gboolean fl_renderer_real_start(FlRenderer* self, GError** error) {
EGL_ALPHA_SIZE,
8,
EGL_NONE};
EGLConfig egl_config;
EGLint n_config;
if (!eglChooseConfig(priv->egl_display, attributes, &egl_config, 1,
if (!eglChooseConfig(priv->egl_display, attributes, &priv->egl_config, 1,
&n_config)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to choose EGL config: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}

if (n_config == 0) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to find appropriate EGL config: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}

if (!eglBindAPI(EGL_OPENGL_ES_API)) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
egl_config_to_string(priv->egl_display, priv->egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to bind EGL OpenGL ES API using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}

return TRUE;
}

GdkVisual* fl_renderer_get_visual(FlRenderer* self,
GdkScreen* screen,
GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

EGLint visual_id;
if (!eglGetConfigAttrib(priv->egl_display, priv->egl_config,
EGL_NATIVE_VISUAL_ID, &visual_id)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to determine EGL configuration visual");
return nullptr;
}

GdkVisual* visual =
FL_RENDERER_GET_CLASS(self)->get_visual(self, screen, visual_id);
if (visual == nullptr) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to find visual 0x%x", visual_id);
return nullptr;
}

return visual;
}

gboolean fl_renderer_start(FlRenderer* self, GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

priv->egl_surface = FL_RENDERER_GET_CLASS(self)->create_surface(
self, priv->egl_display, egl_config);
if (priv->egl_surface == nullptr) {
self, priv->egl_display, priv->egl_config);
if (priv->egl_surface == EGL_NO_SURFACE) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
egl_config_to_string(priv->egl_display, priv->egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL surface using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}

EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
priv->egl_context = eglCreateContext(priv->egl_display, egl_config,
priv->egl_context = eglCreateContext(priv->egl_display, priv->egl_config,
EGL_NO_CONTEXT, context_attributes);
if (priv->egl_context == nullptr) {
if (priv->egl_context == EGL_NO_CONTEXT) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
egl_config_to_string(priv->egl_display, priv->egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL context using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}

create_resource_surface(self, egl_config);

EGLint value;
eglQueryContext(priv->egl_display, priv->egl_context,
EGL_CONTEXT_CLIENT_VERSION, &value);
create_resource_surface(self, priv->egl_config);

return TRUE;
}

static void fl_renderer_class_init(FlRendererClass* klass) {
klass->start = fl_renderer_real_start;
}

static void fl_renderer_init(FlRenderer* self) {}

gboolean fl_renderer_start(FlRenderer* self, GError** error) {
return FL_RENDERER_GET_CLASS(self)->start(self, error);
}

void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) {
return reinterpret_cast<void*>(eglGetProcAddress(name));
}
Expand All @@ -161,7 +184,8 @@ gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

if (priv->resource_surface == nullptr || priv->resource_context == nullptr)
if (priv->resource_surface == EGL_NO_SURFACE ||
priv->resource_context == EGL_NO_CONTEXT)
return FALSE;

if (!eglMakeCurrent(priv->egl_display, priv->resource_surface,
Expand Down
40 changes: 34 additions & 6 deletions shell/platform/linux/fl_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include <EGL/egl.h>

#include <glib-object.h>
#include <gtk/gtk.h>

#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"

Expand Down Expand Up @@ -35,23 +35,51 @@ G_DECLARE_DERIVABLE_TYPE(FlRenderer, fl_renderer, FL, RENDERER, GObject)
struct _FlRendererClass {
GObjectClass parent_class;

// Virtual method called when Flutter has set up EGL and is ready for the
// renderer to start.
gboolean (*start)(FlRenderer* renderer, GError** error);
// Virtual method called to get the visual that matches the given ID.
GdkVisual* (*get_visual)(FlRenderer* renderer,
GdkScreen* screen,
EGLint visual_id);

// Virtual method called when flutter needs a surface to render to.
// Virtual method called when Flutter needs a surface to render to.
EGLSurface (*create_surface)(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config);
};

/**
* fl_renderer_setup:
* @renderer: an #FlRenderer.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Set up the renderer.
*
* Returns: %TRUE if successfully setup.
*/
gboolean fl_renderer_setup(FlRenderer* self, GError** error);

/**
* fl_renderer_get_visual:
* @renderer: an #FlRenderer.
* @screen: the screen being rendered on.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Gets the visual required to render on.
*
* Returns: a #GdkVisual.
*/
GdkVisual* fl_renderer_get_visual(FlRenderer* self,
GdkScreen* screen,
GError** error);

/**
* fl_renderer_start:
* @renderer: an #FlRenderer.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Start the renderer. EGL must be set up before this call.
* Start the renderer.
*
* Returns: %TRUE if successfully started.
*/
Expand Down
27 changes: 23 additions & 4 deletions shell/platform/linux/fl_renderer_x11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,38 @@
struct _FlRendererX11 {
FlRenderer parent_instance;

Window xid;
GdkX11Window* window;
};

G_DEFINE_TYPE(FlRendererX11, fl_renderer_x11, fl_renderer_get_type())

static void fl_renderer_x11_dispose(GObject* object) {
FlRendererX11* self = FL_RENDERER_X11(object);

g_clear_object(&self->window);

G_OBJECT_CLASS(fl_renderer_x11_parent_class)->dispose(object);
}

// Implments FlRenderer::get_visual.
static GdkVisual* fl_renderer_x11_get_visual(FlRenderer* renderer,
GdkScreen* screen,
EGLint visual_id) {
return gdk_x11_screen_lookup_visual(GDK_X11_SCREEN(screen), visual_id);
}

// Implments FlRenderer::create_surface.
static EGLSurface fl_renderer_x11_create_surface(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config) {
FlRendererX11* self = FL_RENDERER_X11(renderer);
return eglCreateWindowSurface(display, config, self->xid, nullptr);
return eglCreateWindowSurface(display, config,
gdk_x11_window_get_xid(self->window), nullptr);
}

static void fl_renderer_x11_class_init(FlRendererX11Class* klass) {
G_OBJECT_CLASS(klass)->dispose = fl_renderer_x11_dispose;
FL_RENDERER_CLASS(klass)->get_visual = fl_renderer_x11_get_visual;
FL_RENDERER_CLASS(klass)->create_surface = fl_renderer_x11_create_surface;
}

Expand All @@ -29,7 +48,7 @@ FlRendererX11* fl_renderer_x11_new() {
return FL_RENDERER_X11(g_object_new(fl_renderer_x11_get_type(), nullptr));
}

void fl_renderer_x11_set_xid(FlRendererX11* self, Window xid) {
void fl_renderer_x11_set_window(FlRendererX11* self, GdkX11Window* window) {
g_return_if_fail(FL_IS_RENDERER_X11(self));
self->xid = xid;
self->window = GDK_X11_WINDOW(g_object_ref(window));
}
6 changes: 3 additions & 3 deletions shell/platform/linux/fl_renderer_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ G_DECLARE_FINAL_TYPE(FlRendererX11,
FlRendererX11* fl_renderer_x11_new();

/**
* fl_renderer_x11_set_xid:
* fl_renderer_x11_set_window:
* @renderer: an #FlRendererX11.
* @xid: The X window being rendered to.
* @window: the X window being rendered to.
*
* Sets the X11 window that is being rendered to.
*/
void fl_renderer_x11_set_xid(FlRendererX11* renderer, Window xid);
void fl_renderer_x11_set_window(FlRendererX11* renderer, GdkX11Window* window);

G_END_DECLS

Expand Down
Loading