Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Implement an EGL resource context for the Linux shell. #18918

Merged
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
10 changes: 10 additions & 0 deletions shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ static bool fl_engine_gl_present(void* user_data) {
return result;
}

static bool fl_engine_gl_make_resource_current(void* user_data) {
FlEngine* self = static_cast<FlEngine*>(user_data);
g_autoptr(GError) error = nullptr;
gboolean result = fl_renderer_make_resource_current(self->renderer, &error);
if (!result)
g_warning("%s", error->message);
return result;
}

// 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 @@ -222,6 +231,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
config.open_gl.clear_current = fl_engine_gl_clear_current;
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;

FlutterTaskRunnerDescription platform_task_runner = {};
platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription);
Expand Down
55 changes: 49 additions & 6 deletions shell/platform/linux/fl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ typedef struct {
EGLDisplay egl_display;
EGLSurface egl_surface;
EGLContext egl_context;

EGLSurface resource_surface;
EGLContext resource_context;
} FlRendererPrivate;

G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
Expand Down Expand Up @@ -55,18 +58,38 @@ static const gchar* get_egl_error() {
}
}

// Creates a resource surface.
static void create_resource_surface(FlRenderer* self, EGLConfig config) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
const EGLint resource_context_attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1,
EGL_NONE};
priv->resource_surface = eglCreatePbufferSurface(priv->egl_display, config,
resource_context_attribs);
if (priv->resource_surface != nullptr) {
g_warning("Failed to create EGL resource surface: %s", get_egl_error());
return;
}

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

// 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) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));

// Note the use of EGL_DEFAULT_DISPLAY rather than sharing an existing display
// connection (e.g. an X11 connection from GTK). This is because this EGL
// display is going to be accessed by a thread from Flutter. In the case
// of GTK/X11 the display connection is not thread safe and this would cause
// a crash.
//
// Note the use of EGL_DEFAULT_DISPLAY rather than sharing an existing
// display connection (e.g. an X11 connection from GTK). This is because
// this EGL display is going to be accessed by a thread from Flutter. In the
// case of GTK/X11 the display connection is not thread safe and this would
// cause a crash.
priv->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

if (!eglInitialize(priv->egl_display, nullptr, nullptr)) {
Expand Down Expand Up @@ -120,6 +143,9 @@ static gboolean fl_renderer_real_start(FlRenderer* self, GError** error) {
"Failed to create EGL context: %s", get_egl_error());
return FALSE;
}

create_resource_surface(self, egl_config);

EGLint value;
eglQueryContext(priv->egl_display, priv->egl_context,
EGL_CONTEXT_CLIENT_VERSION, &value);
Expand Down Expand Up @@ -155,6 +181,23 @@ gboolean fl_renderer_make_current(FlRenderer* self, GError** error) {
return TRUE;
}

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)
return FALSE;

if (!eglMakeCurrent(priv->egl_display, priv->resource_surface,
priv->resource_surface, priv->resource_context)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL context current: %s", get_egl_error());
return FALSE;
}

return TRUE;
}

gboolean fl_renderer_clear_current(FlRenderer* self, GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));
Expand Down
13 changes: 13 additions & 0 deletions shell/platform/linux/fl_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ void* fl_renderer_get_proc_address(FlRenderer* renderer, const char* name);
*/
gboolean fl_renderer_make_current(FlRenderer* renderer, GError** error);

/**
* fl_renderer_make_resource_current:
* @renderer: an #FlRenderer.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Makes the resource rendering context current.
*
* Returns %TRUE if successful.
*/
gboolean fl_renderer_make_resource_current(FlRenderer* renderer,
GError** error);

/**
* fl_renderer_clear_current:
* @renderer: an #FlRenderer.
Expand Down
6 changes: 6 additions & 0 deletions shell/platform/linux/testing/mock_egl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ EGLContext eglCreateContext(EGLDisplay dpy,
return nullptr;
}

EGLSurface eglCreatePbufferSurface(EGLDisplay dpy,
EGLConfig config,
const EGLint* attrib_list) {
return nullptr;
}

EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
EGLConfig config,
EGLNativeWindowType win,
Expand Down