未验证 提交 7a022774 编写于 作者: W William Wold 提交者: GitHub

Improve FlRenderer interface in preperation for Wayland on Linux (#20006)

上级 dd642b05
......@@ -21,30 +21,6 @@ typedef struct {
G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
// 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 == 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 == EGL_NO_CONTEXT) {
g_warning("Failed to create EGL resource context: %s",
egl_error_to_string(eglGetError()));
}
}
static void fl_renderer_class_init(FlRendererClass* klass) {}
static void fl_renderer_init(FlRenderer* self) {}
......@@ -53,12 +29,7 @@ gboolean fl_renderer_setup(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.
priv->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
priv->egl_display = FL_RENDERER_GET_CLASS(self)->create_display(self);
if (!eglInitialize(priv->egl_display, nullptr, nullptr)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
......@@ -94,7 +65,7 @@ gboolean fl_renderer_setup(FlRenderer* self, GError** error) {
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
EGLint egl_error = eglGetError(); // must be before egl_config_to_string().
EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, priv->egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
......@@ -131,40 +102,63 @@ GdkVisual* fl_renderer_get_visual(FlRenderer* self,
return visual;
}
void fl_renderer_set_window(FlRenderer* self, GdkWindow* window) {
g_return_if_fail(FL_IS_RENDERER(self));
g_return_if_fail(GDK_IS_WINDOW(window));
if (FL_RENDERER_GET_CLASS(self)->set_window) {
FL_RENDERER_GET_CLASS(self)->set_window(self, window);
}
}
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, priv->egl_config);
if (priv->egl_surface == EGL_NO_SURFACE) {
EGLint egl_error = eglGetError(); // must be before egl_config_to_string().
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, priv->egl_config);
if (priv->egl_surface != EGL_NO_SURFACE ||
priv->resource_surface != EGL_NO_SURFACE) {
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));
"fl_renderer_start() called after surfaces already created");
return FALSE;
}
if (!FL_RENDERER_GET_CLASS(self)->create_surfaces(
self, priv->egl_display, priv->egl_config, &priv->egl_surface,
&priv->resource_surface, error)) {
return FALSE;
}
EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
priv->egl_context = eglCreateContext(priv->egl_display, priv->egl_config,
EGL_NO_CONTEXT, context_attributes);
if (priv->egl_context == EGL_NO_CONTEXT) {
EGLint egl_error = eglGetError(); // must be before egl_config_to_string().
priv->resource_context =
eglCreateContext(priv->egl_display, priv->egl_config, priv->egl_context,
context_attributes);
if (priv->egl_context == EGL_NO_CONTEXT ||
priv->resource_context == EGL_NO_CONTEXT) {
EGLint egl_error = eglGetError(); // Must be before egl_config_to_string().
g_autofree gchar* config_string =
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",
"Failed to create EGL contexts using configuration (%s): %s",
config_string, egl_error_to_string(egl_error));
return FALSE;
}
create_resource_surface(self, priv->egl_config);
return TRUE;
}
void fl_renderer_set_geometry(FlRenderer* self,
GdkRectangle* geometry,
gint scale) {
g_return_if_fail(FL_IS_RENDERER(self));
if (FL_RENDERER_GET_CLASS(self)->set_geometry) {
FL_RENDERER_GET_CLASS(self)->set_geometry(self, geometry, scale);
}
}
void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) {
return reinterpret_cast<void*>(eglGetProcAddress(name));
}
......@@ -173,6 +167,13 @@ gboolean fl_renderer_make_current(FlRenderer* self, GError** error) {
FlRendererPrivate* priv =
static_cast<FlRendererPrivate*>(fl_renderer_get_instance_private(self));
if (priv->egl_surface == EGL_NO_SURFACE ||
priv->egl_context == EGL_NO_CONTEXT) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL context current: No surface created");
return FALSE;
}
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,
......@@ -190,13 +191,16 @@ gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) {
if (priv->resource_surface == EGL_NO_SURFACE ||
priv->resource_context == EGL_NO_CONTEXT) {
g_set_error(
error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL resource context current: No surface created");
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",
"Failed to make EGL resource context current: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
......
......@@ -40,10 +40,42 @@ struct _FlRendererClass {
GdkScreen* screen,
EGLint visual_id);
// Virtual method called when Flutter needs a surface to render to.
EGLSurface (*create_surface)(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config);
/**
* Virtual method called after a GDK window has been created.
* This is called once. Does not need to be implemented.
*/
void (*set_window)(FlRenderer* renderer, GdkWindow* window);
/**
* Virtual method to create a new EGL display.
*/
EGLDisplay (*create_display)(FlRenderer* renderer);
/**
* Virtual method called when Flutter needs surfaces to render to.
* @renderer: an #FlRenderer.
* @display: display to create surfaces on.
* @visible: (out): the visible surface that is created.
* @resource: (out): the resource surface that is created.
* @error: (allow-none): #GError location to store the error occurring, or
* %NULL to ignore.
*
* Returns: %TRUE if both surfaces were created, %FALSE if there was an error.
*/
gboolean (*create_surfaces)(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config,
EGLSurface* visible,
EGLSurface* resource,
GError** error);
/**
* Virtual method called when the EGL window needs to be resized.
* Does not need to be implemented.
*/
void (*set_geometry)(FlRenderer* renderer,
GdkRectangle* geometry,
gint scale);
};
/**
......@@ -73,6 +105,15 @@ GdkVisual* fl_renderer_get_visual(FlRenderer* renderer,
GdkScreen* screen,
GError** error);
/**
* fl_renderer_set_window:
* @renderer: an #FlRenderer.
* @window: the GDK Window this renderer will render to.
*
* Set the window this renderer will use.
*/
void fl_renderer_set_window(FlRenderer* renderer, GdkWindow* window);
/**
* fl_renderer_start:
* @renderer: an #FlRenderer.
......@@ -85,6 +126,16 @@ GdkVisual* fl_renderer_get_visual(FlRenderer* renderer,
*/
gboolean fl_renderer_start(FlRenderer* renderer, GError** error);
/**
* fl_renderer_set_geometry:
* @renderer: an #FlRenderer.
* @geometry: New size and position (unscaled) of the EGL window.
* @scale: Scale of the window.
*/
void fl_renderer_set_geometry(FlRenderer* renderer,
GdkRectangle* geometry,
gint scale);
/**
* fl_renderer_get_proc_address:
* @renderer: an #FlRenderer.
......
......@@ -10,15 +10,18 @@ struct _FlRendererHeadless {
G_DEFINE_TYPE(FlRendererHeadless, fl_renderer_headless, fl_renderer_get_type())
static EGLSurface fl_renderer_headless_create_surface(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config) {
return EGL_NO_SURFACE;
static gboolean fl_renderer_headless_create_surfaces(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config,
EGLSurface* visible,
EGLSurface* resource,
GError** error) {
return FALSE;
}
static void fl_renderer_headless_class_init(FlRendererHeadlessClass* klass) {
FL_RENDERER_CLASS(klass)->create_surface =
fl_renderer_headless_create_surface;
FL_RENDERER_CLASS(klass)->create_surfaces =
fl_renderer_headless_create_surfaces;
}
static void fl_renderer_headless_init(FlRendererHeadless* self) {}
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "fl_renderer_x11.h"
#include "flutter/shell/platform/linux/egl_utils.h"
struct _FlRendererX11 {
FlRenderer parent_instance;
......@@ -27,19 +28,70 @@ static GdkVisual* fl_renderer_x11_get_visual(FlRenderer* renderer,
return gdk_x11_screen_lookup_visual(GDK_X11_SCREEN(screen), visual_id);
}
// Implements FlRenderer::create_surface.
static EGLSurface fl_renderer_x11_create_surface(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config) {
// Implements FlRenderer::set_window.
static void fl_renderer_x11_set_window(FlRenderer* renderer,
GdkWindow* window) {
FlRendererX11* self = FL_RENDERER_X11(renderer);
return eglCreateWindowSurface(display, config,
gdk_x11_window_get_xid(self->window), nullptr);
g_return_if_fail(GDK_IS_X11_WINDOW(window));
g_assert_null(self->window);
self->window = GDK_X11_WINDOW(g_object_ref(window));
}
// 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,
EGLDisplay display,
EGLConfig config,
EGLSurface* visible,
EGLSurface* resource,
GError** error) {
FlRendererX11* self = FL_RENDERER_X11(renderer);
if (!self->window) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Can not create EGL surface: FlRendererX11::window not set");
return FALSE;
}
*visible = eglCreateWindowSurface(
display, config, gdk_x11_window_get_xid(self->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) {
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;
FL_RENDERER_CLASS(klass)->set_window = fl_renderer_x11_set_window;
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) {}
......@@ -47,8 +99,3 @@ 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));
}
void fl_renderer_x11_set_window(FlRendererX11* self, GdkX11Window* window) {
g_return_if_fail(FL_IS_RENDERER_X11(self));
self->window = GDK_X11_WINDOW(g_object_ref(window));
}
......@@ -33,15 +33,6 @@ G_DECLARE_FINAL_TYPE(FlRendererX11,
*/
FlRendererX11* fl_renderer_x11_new();
/**
* fl_renderer_x11_set_window:
* @renderer: an #FlRendererX11.
* @window: the X window being rendered to.
*
* Sets the X11 window that is being rendered to.
*/
void fl_renderer_x11_set_window(FlRendererX11* renderer, GdkX11Window* window);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_X11_H_
......@@ -103,13 +103,14 @@ static gboolean fl_view_send_pointer_button_event(FlView* self,
}
// Updates the engine with the current window metrics.
static void fl_view_send_window_metrics(FlView* self) {
static void fl_view_geometry_changed(FlView* self) {
GtkAllocation allocation;
gtk_widget_get_allocation(GTK_WIDGET(self), &allocation);
gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self));
fl_engine_send_window_metrics_event(
self->engine, allocation.width * scale_factor,
allocation.height * scale_factor, scale_factor);
fl_renderer_set_geometry(self->renderer, &allocation, scale_factor);
}
// Implements FlPluginRegistry::get_registrar_for_plugin.
......@@ -178,7 +179,7 @@ static void fl_view_notify(GObject* object, GParamSpec* pspec) {
FlView* self = FL_VIEW(object);
if (strcmp(pspec->name, "scale-factor") == 0) {
fl_view_send_window_metrics(self);
fl_view_geometry_changed(self);
}
if (G_OBJECT_CLASS(fl_view_parent_class)->notify != nullptr) {
......@@ -237,9 +238,7 @@ static void fl_view_realize(GtkWidget* widget) {
gtk_widget_register_window(widget, window);
gtk_widget_set_window(widget, window);
fl_renderer_x11_set_window(
FL_RENDERER_X11(self->renderer),
GDK_X11_WINDOW(gtk_widget_get_window(GTK_WIDGET(self))));
fl_renderer_set_window(self->renderer, window);
if (!fl_engine_start(self->engine, &error)) {
g_warning("Failed to start Flutter engine: %s", error->message);
......@@ -259,7 +258,7 @@ static void fl_view_size_allocate(GtkWidget* widget,
allocation->height);
}
fl_view_send_window_metrics(self);
fl_view_geometry_changed(self);
}
// Implements GtkWidget::button_press_event.
......
......@@ -17,16 +17,28 @@ static GdkVisual* fl_mock_renderer_get_visual(FlRenderer* renderer,
return static_cast<GdkVisual*>(g_object_new(GDK_TYPE_VISUAL, nullptr));
}
// Implements FlRenderer::create_surface.
static EGLSurface fl_mock_renderer_create_surface(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config) {
return eglCreateWindowSurface(display, config, 0, nullptr);
// Implements FlRenderer::create_display.
static EGLDisplay fl_mock_renderer_create_display(FlRenderer* renderer) {
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
// Implements FlRenderer::create_surfaces.
static gboolean fl_mock_renderer_create_surfaces(FlRenderer* renderer,
EGLDisplay display,
EGLConfig config,
EGLSurface* visible,
EGLSurface* resource,
GError** error) {
*visible = eglCreateWindowSurface(display, config, 0, nullptr);
const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
*resource = eglCreatePbufferSurface(display, config, attribs);
return TRUE;
}
static void fl_mock_renderer_class_init(FlMockRendererClass* klass) {
FL_RENDERER_CLASS(klass)->get_visual = fl_mock_renderer_get_visual;
FL_RENDERER_CLASS(klass)->create_surface = fl_mock_renderer_create_surface;
FL_RENDERER_CLASS(klass)->create_display = fl_mock_renderer_create_display;
FL_RENDERER_CLASS(klass)->create_surfaces = fl_mock_renderer_create_surfaces;
}
static void fl_mock_renderer_init(FlMockRenderer* self) {}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册