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 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
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
94 changes: 88 additions & 6 deletions shell/platform/linux/fl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,52 @@ 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)

// Gets a string representation of the last EGL error.
static const gchar* get_egl_error() {
EGLint error = eglGetError();
switch (error) {
case EGL_SUCCESS:
return "Success";
case EGL_NOT_INITIALIZED:
return "Not Initialized";
case EGL_BAD_ACCESS:
return "Bad Access";
case EGL_BAD_ALLOC:
return "Bad Allocation";
case EGL_BAD_ATTRIBUTE:
return "Bad Attribute";
case EGL_BAD_CONTEXT:
return "Bad Context";
case EGL_BAD_CONFIG:
return "Bad Configuration";
case EGL_BAD_CURRENT_SURFACE:
return "Bad Current Surface";
case EGL_BAD_DISPLAY:
return "Bad Display";
case EGL_BAD_SURFACE:
return "Bad Surface";
case EGL_BAD_MATCH:
return "Bad Match";
case EGL_BAD_PARAMETER:
return "Bad Parameter";
case EGL_BAD_NATIVE_PIXMAP:
return "Bad Native Pixmap";
case EGL_BAD_NATIVE_WINDOW:
return "Bad Native Window";
case EGL_CONTEXT_LOST:
return "Context Lost";
default:
return "Unknown 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) {
Expand Down Expand Up @@ -52,29 +94,55 @@ static gboolean fl_renderer_real_start(FlRenderer* self, GError** error) {
if (!eglChooseConfig(priv->egl_display, attributes, &egl_config, 1,
&n_config)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to choose EGL config");
"Failed to choose EGL config: %s", get_egl_error());
return FALSE;
}
if (n_config == 0) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to find appropriate EGL config");
"Failed to find appropriate EGL config: %s", get_egl_error());
return FALSE;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to bind EGL OpenGL ES API");
"Failed to bind EGL OpenGL ES API: %s", get_egl_error());
return FALSE;
}

priv->egl_surface = FL_RENDERER_GET_CLASS(self)->create_surface(
self, priv->egl_display, egl_config);
if (priv->egl_surface == nullptr) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL surface: %s", get_egl_error());
return FALSE;
}
EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
priv->egl_context = eglCreateContext(priv->egl_display, egl_config,
EGL_NO_CONTEXT, context_attributes);
if (priv->egl_context == nullptr) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL context: %s", get_egl_error());
return FALSE;
}
EGLint value;
eglQueryContext(priv->egl_display, priv->egl_context,
EGL_CONTEXT_CLIENT_VERSION, &value);

const EGLint shared_context_attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1,
EGL_NONE};
priv->resource_surface = eglCreatePbufferSurface(
priv->egl_display, egl_config, shared_context_attribs);
if (priv->resource_surface == nullptr) {
g_warning(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL resource surface: %s", get_egl_error());
}
priv->resource_context = eglCreateContext(
priv->egl_display, egl_config, priv->egl_context, context_attributes);
if (priv->resource_context == nullptr) {
g_warning(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL resource context: %s", get_egl_error());
return FALSE;
}

return TRUE;
}

Expand All @@ -99,7 +167,21 @@ gboolean fl_renderer_make_current(FlRenderer* self, GError** error) {
if (!eglMakeCurrent(priv->egl_display, priv->egl_surface, priv->egl_surface,
priv->egl_context)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL context current");
"Failed to make EGL context current: %s", get_egl_error());
return FALSE;
}

return TRUE;
}

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

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

Expand All @@ -113,7 +195,7 @@ gboolean fl_renderer_clear_current(FlRenderer* self, GError** error) {
if (!eglMakeCurrent(priv->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to clear EGL context");
"Failed to clear EGL context: %s", get_egl_error());
return FALSE;
}

Expand All @@ -131,7 +213,7 @@ gboolean fl_renderer_present(FlRenderer* self, GError** error) {

if (!eglSwapBuffers(priv->egl_display, priv->egl_surface)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to swap EGL buffers");
"Failed to swap EGL buffers: %s", get_egl_error());
return FALSE;
}

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
10 changes: 10 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 All @@ -34,6 +40,10 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
return nullptr;
}

EGLint eglGetError() {
return EGL_SUCCESS;
}

void (*eglGetProcAddress(const char* procname))(void) {
return nullptr;
}
Expand Down