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

Commit 814bb86

Browse files
committed
Run Flutter platform tasks in GLib main loop
Fixes flutter/flutter#54856
1 parent 50ae2b9 commit 814bb86

File tree

1 file changed

+77
-2
lines changed

1 file changed

+77
-2
lines changed

shell/platform/linux/fl_engine.cc

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@
88

99
#include <gmodule.h>
1010

11+
static constexpr int kMicrosecondsPerNanosecond = 1000;
12+
13+
// Unique number associated with platform tasks
14+
static constexpr size_t kPlatformTaskRunnerIdentifier = 1;
15+
1116
struct _FlEngine {
1217
GObject parent_instance;
1318

19+
// Thread the GLib main loop is running on
20+
GThread* thread;
21+
1422
FlDartProject* project;
1523
FlRenderer* renderer;
1624
FLUTTER_API_SYMBOL(FlutterEngine) engine;
@@ -20,7 +28,39 @@ G_DEFINE_QUARK(fl_engine_error_quark, fl_engine_error)
2028

2129
G_DEFINE_TYPE(FlEngine, fl_engine, G_TYPE_OBJECT)
2230

23-
// Callback from Flutter engine that are passed to the renderer
31+
// Subclass of GSource that integrates Flutter tasks into the GLib main loop
32+
typedef struct {
33+
GSource parent;
34+
FlEngine* self;
35+
FlutterTask task;
36+
} FlutterSource;
37+
38+
// Callback to run a Flutter task in the GLib main loop
39+
static gboolean flutter_source_dispatch(GSource* source,
40+
GSourceFunc callback,
41+
gpointer user_data) {
42+
FlutterSource* fl_source = reinterpret_cast<FlutterSource*>(source);
43+
FlEngine* self = fl_source->self;
44+
45+
FlutterEngineResult result =
46+
FlutterEngineRunTask(self->engine, &fl_source->task);
47+
if (result != kSuccess)
48+
g_warning("Failed to run Flutter task\n");
49+
50+
return G_SOURCE_REMOVE;
51+
}
52+
53+
// Table of functions for Flutter GLib main loop integration
54+
static GSourceFuncs flutter_source_funcs = {
55+
nullptr, // prepare
56+
nullptr, // check
57+
flutter_source_dispatch, // dispatch
58+
nullptr, // finalize
59+
nullptr,
60+
nullptr // Internal usage
61+
};
62+
63+
// Flutter engine callbacks
2464

2565
static void* fl_engine_gl_proc_resolver(void* user_data, const char* name) {
2666
FlEngine* self = static_cast<FlEngine*>(user_data);
@@ -59,6 +99,26 @@ static bool fl_engine_gl_present(void* user_data) {
5999
return result;
60100
}
61101

102+
static bool fl_engine_runs_task_on_current_thread(void* user_data) {
103+
FlEngine* self = static_cast<FlEngine*>(user_data);
104+
return self->thread == g_thread_self();
105+
}
106+
107+
static void fl_engine_post_task_callback(FlutterTask task,
108+
uint64_t target_time_nanos,
109+
void* user_data) {
110+
FlEngine* self = static_cast<FlEngine*>(user_data);
111+
112+
g_autoptr(GSource) source =
113+
g_source_new(&flutter_source_funcs, sizeof(FlutterSource));
114+
FlutterSource* fl_source = reinterpret_cast<FlutterSource*>(source);
115+
fl_source->self = self;
116+
fl_source->task = task;
117+
g_source_set_ready_time(source,
118+
target_time_nanos / kMicrosecondsPerNanosecond);
119+
g_source_attach(source, nullptr);
120+
}
121+
62122
static void fl_engine_dispose(GObject* object) {
63123
FlEngine* self = FL_ENGINE(object);
64124

@@ -74,7 +134,9 @@ static void fl_engine_class_init(FlEngineClass* klass) {
74134
G_OBJECT_CLASS(klass)->dispose = fl_engine_dispose;
75135
}
76136

77-
static void fl_engine_init(FlEngine* self) {}
137+
static void fl_engine_init(FlEngine* self) {
138+
self->thread = g_thread_self();
139+
}
78140

79141
FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer) {
80142
g_return_val_if_fail(FL_IS_DART_PROJECT(project), nullptr);
@@ -102,10 +164,23 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
102164
config.open_gl.fbo_callback = fl_engine_gl_fbo_callback;
103165
config.open_gl.present = fl_engine_gl_present;
104166

167+
FlutterTaskRunnerDescription platform_task_runner = {};
168+
platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription);
169+
platform_task_runner.user_data = self;
170+
platform_task_runner.runs_task_on_current_thread_callback =
171+
fl_engine_runs_task_on_current_thread;
172+
platform_task_runner.post_task_callback = fl_engine_post_task_callback;
173+
platform_task_runner.identifier = kPlatformTaskRunnerIdentifier;
174+
175+
FlutterCustomTaskRunners custom_task_runners = {};
176+
custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners);
177+
custom_task_runners.platform_task_runner = &platform_task_runner;
178+
105179
FlutterProjectArgs args = {};
106180
args.struct_size = sizeof(FlutterProjectArgs);
107181
args.assets_path = fl_dart_project_get_assets_path(self->project);
108182
args.icu_data_path = fl_dart_project_get_icu_data_path(self->project);
183+
args.custom_task_runners = &custom_task_runners;
109184

110185
FlutterEngineResult result = FlutterEngineInitialize(
111186
FLUTTER_ENGINE_VERSION, &config, &args, self, &self->engine);

0 commit comments

Comments
 (0)