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

Commit dc930a4

Browse files
committed
Refactor FlutterEngine usage in Linux shell
1 parent 05738d6 commit dc930a4

File tree

10 files changed

+602
-159
lines changed

10 files changed

+602
-159
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,8 +1147,14 @@ FILE: ../../../flutter/shell/platform/glfw/public/flutter_glfw.h
11471147
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
11481148
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
11491149
FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
1150+
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
1151+
FILE: ../../../flutter/shell/platform/linux/fl_engine_egl.cc
1152+
FILE: ../../../flutter/shell/platform/linux/fl_engine_x11.cc
11501153
FILE: ../../../flutter/shell/platform/linux/fl_view.cc
11511154
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
1155+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
1156+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine_egl.h
1157+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine_x11.h
11521158
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h
11531159
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h
11541160
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc

shell/platform/linux/BUILD.gn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ if (build_glfw_shell) {
4949
if (build_linux_shell) {
5050
_public_headers = [
5151
"public/flutter_linux/fl_dart_project.h",
52+
"public/flutter_linux/fl_engine.h",
53+
"public/flutter_linux/fl_engine_egl.h",
54+
"public/flutter_linux/fl_engine_x11.h",
5255
"public/flutter_linux/fl_view.h",
5356
"public/flutter_linux/flutter_linux.h",
5457
]
@@ -62,6 +65,9 @@ if (build_linux_shell) {
6265

6366
sources = [
6467
"fl_dart_project.cc",
68+
"fl_engine.cc",
69+
"fl_engine_egl.cc",
70+
"fl_engine_x11.cc",
6571
"fl_view.cc",
6672
]
6773

shell/platform/linux/fl_engine.cc

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
6+
7+
#include "flutter/shell/platform/embedder/embedder.h"
8+
9+
/**
10+
* FlEngine:
11+
*
12+
* #FlEngine is an abstract class that controls a FlutterEngine.
13+
*/
14+
15+
typedef struct {
16+
FlDartProject* project;
17+
FLUTTER_API_SYMBOL(FlutterEngine) engine;
18+
} FlEnginePrivate;
19+
20+
enum { PROP_FLUTTER_PROJECT = 1, PROP_LAST };
21+
22+
G_DEFINE_TYPE_WITH_PRIVATE(FlEngine, fl_engine, G_TYPE_OBJECT)
23+
24+
static void* fl_engine_gl_proc_resolver(void* user_data, const char* name) {
25+
FlEngine* self = static_cast<FlEngine*>(user_data);
26+
27+
return FL_ENGINE_GET_CLASS(self)->get_proc_address(self, name);
28+
}
29+
30+
static bool fl_engine_gl_make_current(void* user_data) {
31+
FlEngine* self = static_cast<FlEngine*>(user_data);
32+
33+
FL_ENGINE_GET_CLASS(self)->make_current(self);
34+
35+
return true;
36+
}
37+
38+
static bool fl_engine_gl_clear_current(void* user_data) {
39+
FlEngine* self = static_cast<FlEngine*>(user_data);
40+
41+
FL_ENGINE_GET_CLASS(self)->clear_current(self);
42+
43+
return true;
44+
}
45+
46+
static uint32_t fl_engine_gl_fbo_callback(void* user_data) {
47+
FlEngine* self = static_cast<FlEngine*>(user_data);
48+
49+
return FL_ENGINE_GET_CLASS(self)->get_fbo(self);
50+
}
51+
52+
static bool fl_engine_gl_present(void* user_data) {
53+
FlEngine* self = static_cast<FlEngine*>(user_data);
54+
55+
FL_ENGINE_GET_CLASS(self)->present(self);
56+
57+
return true;
58+
}
59+
60+
static void fl_engine_set_property(GObject* object,
61+
guint prop_id,
62+
const GValue* value,
63+
GParamSpec* pspec) {
64+
FlEngine* self = FL_ENGINE(object);
65+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
66+
67+
switch (prop_id) {
68+
case PROP_FLUTTER_PROJECT:
69+
g_set_object(&priv->project,
70+
static_cast<FlDartProject*>(g_value_get_object(value)));
71+
break;
72+
default:
73+
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
74+
break;
75+
}
76+
}
77+
78+
static void fl_engine_get_property(GObject* object,
79+
guint prop_id,
80+
GValue* value,
81+
GParamSpec* pspec) {
82+
FlEngine* self = FL_ENGINE(object);
83+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
84+
85+
switch (prop_id) {
86+
case PROP_FLUTTER_PROJECT:
87+
g_value_set_object(value, priv->project);
88+
break;
89+
default:
90+
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
91+
break;
92+
}
93+
}
94+
95+
static void fl_engine_dispose(GObject* object) {
96+
FlEngine* self = FL_ENGINE(object);
97+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
98+
99+
FlutterEngineDeinitialize(priv->engine);
100+
FlutterEngineShutdown(priv->engine);
101+
102+
g_clear_object(&priv->project);
103+
104+
G_OBJECT_CLASS(fl_engine_parent_class)->dispose(object);
105+
}
106+
107+
static gboolean fl_engine_real_start(FlEngine* self, GError **error) {
108+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
109+
110+
g_return_val_if_fail(FL_IS_ENGINE(self), FALSE);
111+
112+
FlutterRendererConfig config = {};
113+
config.type = kOpenGL;
114+
config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig);
115+
config.open_gl.gl_proc_resolver = fl_engine_gl_proc_resolver;
116+
config.open_gl.make_current = fl_engine_gl_make_current;
117+
config.open_gl.clear_current = fl_engine_gl_clear_current;
118+
config.open_gl.fbo_callback = fl_engine_gl_fbo_callback;
119+
config.open_gl.present = fl_engine_gl_present;
120+
121+
FlutterProjectArgs args = {};
122+
args.struct_size = sizeof(FlutterProjectArgs);
123+
args.assets_path = fl_dart_project_get_assets_path(priv->project);
124+
args.icu_data_path = fl_dart_project_get_icu_data_path(priv->project);
125+
126+
FlutterEngineResult result = FlutterEngineInitialize(
127+
FLUTTER_ENGINE_VERSION, &config, &args, self, &priv->engine);
128+
if (result != kSuccess) {
129+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to initialize Flutter engine");
130+
return FALSE;
131+
}
132+
133+
result = FlutterEngineRunInitialized(priv->engine);
134+
if (result != kSuccess) {
135+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to run Flutter engine");
136+
return FALSE;
137+
}
138+
139+
return TRUE;
140+
}
141+
142+
static void fl_engine_class_init(FlEngineClass* klass) {
143+
G_OBJECT_CLASS(klass)->set_property = fl_engine_set_property;
144+
G_OBJECT_CLASS(klass)->get_property = fl_engine_get_property;
145+
G_OBJECT_CLASS(klass)->dispose = fl_engine_dispose;
146+
klass->start = fl_engine_real_start;
147+
148+
g_object_class_install_property(
149+
G_OBJECT_CLASS(klass), PROP_FLUTTER_PROJECT,
150+
g_param_spec_object(
151+
"flutter-project", "flutter-project", "Flutter project in use",
152+
fl_dart_project_get_type(),
153+
static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
154+
G_PARAM_STATIC_STRINGS)));
155+
}
156+
157+
static void fl_engine_init(FlEngine* self) {}
158+
159+
G_DEFINE_QUARK(fl-engine-error-quark, fl_engine_error)
160+
161+
FlDartProject* fl_engine_get_project(FlEngine* self) {
162+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
163+
164+
g_return_val_if_fail(FL_IS_ENGINE(self), NULL);
165+
166+
return priv->project;
167+
}
168+
169+
gboolean fl_engine_start(FlEngine* self, GError **error) {
170+
return FL_ENGINE_GET_CLASS(self)->start(self, error);
171+
}
172+
173+
void fl_engine_send_window_metrics_event(FlEngine* self, size_t width, size_t height, double pixel_ratio) {
174+
FlEnginePrivate* priv = static_cast<FlEnginePrivate*>(fl_engine_get_instance_private(self));
175+
176+
FlutterWindowMetricsEvent event = {};
177+
event.struct_size = sizeof(FlutterWindowMetricsEvent);
178+
event.width = width;
179+
event.height = height;
180+
event.pixel_ratio = pixel_ratio;
181+
FlutterEngineSendWindowMetricsEvent(priv->engine, &event);
182+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine_egl.h"
6+
7+
#include <EGL/egl.h>
8+
#include <EGL/eglext.h>
9+
#include <GLES2/gl2.h>
10+
11+
#include "flutter/shell/platform/embedder/embedder.h"
12+
13+
/**
14+
* FlEngineEGL:
15+
*
16+
* #FlEngineEGL is an abstract class that renders a FlutterEngine using EGL.
17+
*/
18+
19+
typedef struct {
20+
EGLint egl_major;
21+
EGLint egl_minor;
22+
23+
EGLDisplay egl_display;
24+
EGLSurface egl_surface;
25+
EGLContext egl_context;
26+
} FlEngineEGLPrivate;
27+
28+
G_DEFINE_TYPE_WITH_PRIVATE(FlEngineEGL, fl_engine_egl, fl_engine_get_type())
29+
30+
static gboolean fl_engine_egl_start(FlEngine* engine, GError **error) {
31+
FlEngineEGL* self = FL_ENGINE_EGL(engine);
32+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
33+
34+
/* Note that we don't provide the XDisplay from GTK, this would make both
35+
* GTK and EGL share the same X connection and this would crash when used by
36+
* a Flutter thread. So the EGL display and GTK both have separate
37+
* connections.
38+
*/
39+
priv->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
40+
41+
if (!eglInitialize(priv->egl_display, &priv->egl_major, &priv->egl_minor)) {
42+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to initialze EGL");
43+
return FALSE;
44+
}
45+
46+
EGLint attributes[] = {EGL_RENDERABLE_TYPE,
47+
EGL_OPENGL_ES2_BIT,
48+
EGL_RED_SIZE,
49+
8,
50+
EGL_GREEN_SIZE,
51+
8,
52+
EGL_BLUE_SIZE,
53+
8,
54+
EGL_ALPHA_SIZE,
55+
8,
56+
EGL_NONE};
57+
EGLConfig egl_config;
58+
EGLint n_config;
59+
if (!eglChooseConfig(priv->egl_display, attributes, &egl_config, 1,
60+
&n_config)) {
61+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to choose EGL config");
62+
return FALSE;
63+
}
64+
if (n_config == 0) {
65+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to find appropriate EGL config");
66+
return FALSE;
67+
}
68+
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
69+
g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to bind EGL OpenGL ES API");
70+
return FALSE;
71+
}
72+
73+
priv->egl_surface = FL_ENGINE_EGL_GET_CLASS(self)->create_surface(self, priv->egl_display, egl_config);
74+
EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
75+
priv->egl_context = eglCreateContext(priv->egl_display, egl_config,
76+
EGL_NO_CONTEXT, context_attributes);
77+
EGLint value;
78+
eglQueryContext(priv->egl_display, priv->egl_context,
79+
EGL_CONTEXT_CLIENT_VERSION, &value);
80+
81+
return FL_ENGINE_CLASS(fl_engine_egl_parent_class)->start(engine, error);
82+
}
83+
84+
static void* fl_engine_egl_get_proc_address(FlEngine* engine, const char* name) {
85+
return reinterpret_cast<void*>(eglGetProcAddress(name));
86+
}
87+
88+
static void fl_engine_egl_make_current(FlEngine* engine) {
89+
FlEngineEGL* self = FL_ENGINE_EGL(engine);
90+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
91+
92+
if (!eglMakeCurrent(priv->egl_display, priv->egl_surface, priv->egl_surface,
93+
priv->egl_context))
94+
g_warning("Failed to make EGL context current");
95+
}
96+
97+
static void fl_engine_egl_clear_current(FlEngine* engine) {
98+
FlEngineEGL* self = FL_ENGINE_EGL(engine);
99+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
100+
101+
if (!eglMakeCurrent(priv->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
102+
EGL_NO_CONTEXT))
103+
g_warning("Failed to make EGL context current");
104+
}
105+
106+
static uint32_t fl_engine_egl_get_fbo(FlEngine* engine) {
107+
/* There is only one frame buffer object - always return that */
108+
return 0;
109+
}
110+
111+
static void fl_engine_egl_present(FlEngine* engine) {
112+
FlEngineEGL* self = FL_ENGINE_EGL(engine);
113+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
114+
115+
if (!eglSwapBuffers(priv->egl_display, priv->egl_surface))
116+
g_warning("Failed to swap EGL buffers");
117+
}
118+
119+
static void fl_engine_dispose(GObject* object) {
120+
FlEngineEGL* self = FL_ENGINE_EGL(object);
121+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
122+
123+
if (!eglDestroyContext(priv->egl_display, priv->egl_context))
124+
g_warning("Failed to destroy EGL context");
125+
if (!eglDestroySurface(priv->egl_display, priv->egl_surface))
126+
g_warning("Failed to destroy EGL surface");
127+
if (!eglTerminate(priv->egl_display))
128+
g_warning("Failed to terminate EGL display");
129+
130+
G_OBJECT_CLASS(fl_engine_egl_parent_class)->dispose(object);
131+
}
132+
133+
static void fl_engine_egl_class_init(FlEngineEGLClass* klass) {
134+
G_OBJECT_CLASS(klass)->dispose = fl_engine_dispose;
135+
FL_ENGINE_CLASS(klass)->start = fl_engine_egl_start;
136+
FL_ENGINE_CLASS(klass)->get_proc_address = fl_engine_egl_get_proc_address;
137+
FL_ENGINE_CLASS(klass)->make_current = fl_engine_egl_make_current;
138+
FL_ENGINE_CLASS(klass)->clear_current = fl_engine_egl_clear_current;
139+
FL_ENGINE_CLASS(klass)->get_fbo = fl_engine_egl_get_fbo;
140+
FL_ENGINE_CLASS(klass)->present = fl_engine_egl_present;
141+
}
142+
143+
static void fl_engine_egl_init(FlEngineEGL* self) {}
144+
145+
/**
146+
* fl_engine_egl_get_egl_version:
147+
* @engine: an #FlEglEngine
148+
* @major: (out) (optional): location to write the major EGL version or %NULL.
149+
* @minor: (out) (optional): location to write the major EGL version or %NULL.
150+
*
151+
* Get the EGL version is use by the engine. Only set once the engine is started.
152+
*/
153+
void fl_engine_egl_get_egl_version(FlEngineEGL* self, EGLint* major, EGLint* minor) {
154+
FlEngineEGLPrivate* priv = static_cast<FlEngineEGLPrivate*>(fl_engine_egl_get_instance_private(self));
155+
156+
g_return_if_fail(FL_IS_ENGINE_EGL(self));
157+
158+
if (major != NULL)
159+
*major = priv->egl_major;
160+
if (minor != NULL)
161+
*minor = priv->egl_minor;
162+
}

0 commit comments

Comments
 (0)