blob: 5fa6e57978bb54219a8d636680d254137d32b453 [file] [log] [blame]
// Copyright 2013 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 "fl_renderer_x11.h"
#include "flutter/shell/platform/linux/egl_utils.h"
struct _FlRendererX11 {
FlRenderer parent_instance;
};
G_DEFINE_TYPE(FlRendererX11, fl_renderer_x11, fl_renderer_get_type())
// Implements FlRenderer::setup_window_attr.
static gboolean fl_renderer_x11_setup_window_attr(
FlRenderer* renderer,
GtkWidget* widget,
EGLDisplay display,
EGLConfig config,
GdkWindowAttr* window_attributes,
gint* mask,
GError** error) {
EGLint visual_id;
if (!eglGetConfigAttrib(display, 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 FALSE;
}
GdkX11Screen* screen = GDK_X11_SCREEN(gtk_widget_get_screen(widget));
if (!screen) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"View widget is not on an X11 screen");
return FALSE;
}
window_attributes->visual = gdk_x11_screen_lookup_visual(screen, visual_id);
if (window_attributes->visual == nullptr) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to find visual 0x%x", visual_id);
return FALSE;
}
*mask |= GDK_WA_VISUAL;
return TRUE;
}
// Implements FlRenderer::create_display.
static EGLDisplay fl_renderer_x11_create_display(FlRenderer* renderer) {
// Note the use of EGL_DEFAULT_DISPLAY rather than sharing the existing
// display connection from GTK. This is because this EGL display is going to
// be accessed by a thread from Flutter. The GTK/X11 display connection is not
// thread safe and would cause a crash.
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
// Implements FlRenderer::create_surfaces.
static gboolean fl_renderer_x11_create_surfaces(FlRenderer* renderer,
GtkWidget* widget,
EGLDisplay display,
EGLConfig config,
EGLSurface* visible,
EGLSurface* resource,
GError** error) {
GdkWindow* window = gtk_widget_get_window(widget);
if (!GDK_IS_X11_WINDOW(window)) {
g_set_error(
error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Can not create EGL surface: view doesn't have an X11 GDK window");
return FALSE;
}
*visible = eglCreateWindowSurface(display, config,
gdk_x11_window_get_xid(window), nullptr);
if (*visible == EGL_NO_SURFACE) {
EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
g_autofree gchar* config_string = egl_config_to_string(display, 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(egl_error));
return FALSE;
}
const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
*resource = eglCreatePbufferSurface(display, config, attribs);
if (*resource == EGL_NO_SURFACE) {
EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
g_autofree gchar* config_string = egl_config_to_string(display, config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL resource using configuration (%s): %s",
config_string, egl_error_to_string(egl_error));
return FALSE;
}
return TRUE;
}
static void fl_renderer_x11_class_init(FlRendererX11Class* klass) {
FL_RENDERER_CLASS(klass)->setup_window_attr =
fl_renderer_x11_setup_window_attr;
FL_RENDERER_CLASS(klass)->create_display = fl_renderer_x11_create_display;
FL_RENDERER_CLASS(klass)->create_surfaces = fl_renderer_x11_create_surfaces;
}
static void fl_renderer_x11_init(FlRendererX11* self) {}
FlRendererX11* fl_renderer_x11_new() {
return FL_RENDERER_X11(g_object_new(fl_renderer_x11_get_type(), nullptr));
}