Skip to content

Commit e04098a

Browse files
committed
[Linux] Move rendering to raster thread
1 parent e0aae0d commit e04098a

File tree

7 files changed

+186
-15
lines changed

7 files changed

+186
-15
lines changed

engine/src/flutter/shell/platform/linux/fl_engine.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ static void fl_engine_post_task(FlutterTask task,
354354
void* user_data) {
355355
FlEngine* self = static_cast<FlEngine*>(user_data);
356356

357-
fl_task_runner_post_task(self->task_runner, task, target_time_nanos);
357+
fl_task_runner_post_flutter_task(self->task_runner, task, target_time_nanos);
358358
}
359359

360360
// Called when a platform message is received from the engine.
@@ -597,7 +597,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
597597
FlutterCustomTaskRunners custom_task_runners = {};
598598
custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners);
599599
custom_task_runners.platform_task_runner = &platform_task_runner;
600-
custom_task_runners.render_task_runner = &platform_task_runner;
601600

602601
g_autoptr(GPtrArray) command_line_args =
603602
g_ptr_array_new_with_free_func(g_free);

engine/src/flutter/shell/platform/linux/fl_renderer.cc

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ typedef struct {
7373

7474
// Framebuffers to render keyed by view ID.
7575
GHashTable* framebuffers_by_view_id;
76+
77+
// Mutex and condition used when block the raster thread until a task
78+
// is completed on platform thread.
79+
GMutex mutex;
80+
GCond cond;
7681
} FlRendererPrivate;
7782

7883
G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
@@ -313,10 +318,32 @@ static void fl_renderer_dispose(GObject* object) {
313318
g_clear_pointer(&priv->framebuffers_by_view_id, g_hash_table_unref);
314319

315320
G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(object);
321+
322+
g_mutex_clear(&priv->mutex);
323+
g_cond_clear(&priv->cond);
324+
}
325+
326+
static gboolean fl_renderer_schedule_on_main_thread(
327+
FlRenderer* self,
328+
void (*callback)(gpointer data),
329+
gpointer callback_data) {
330+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
331+
fl_renderer_get_instance_private(self));
332+
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&priv->engine));
333+
334+
if (engine == nullptr) {
335+
return FALSE;
336+
}
337+
338+
FlTaskRunner* task_runner = fl_engine_get_task_runner(engine);
339+
fl_task_runner_post_callback(task_runner, callback, callback_data);
340+
return TRUE;
316341
}
317342

318343
static void fl_renderer_class_init(FlRendererClass* klass) {
319344
G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose;
345+
FL_RENDERER_CLASS(klass)->schedule_on_main_thread =
346+
fl_renderer_schedule_on_main_thread;
320347
}
321348

322349
static void fl_renderer_init(FlRenderer* self) {
@@ -327,6 +354,8 @@ static void fl_renderer_init(FlRenderer* self) {
327354
priv->framebuffers_by_view_id = g_hash_table_new_full(
328355
g_direct_hash, g_direct_equal, nullptr,
329356
reinterpret_cast<GDestroyNotify>(g_ptr_array_unref));
357+
g_mutex_init(&priv->mutex);
358+
g_cond_init(&priv->cond);
330359
}
331360

332361
void fl_renderer_set_engine(FlRenderer* self, FlEngine* engine) {
@@ -388,6 +417,53 @@ guint32 fl_renderer_get_fbo(FlRenderer* self) {
388417
return 0;
389418
}
390419

420+
struct _FlRendererCallBlockingTrampolineData {
421+
FlRenderer* renderer;
422+
gboolean* finished;
423+
void (*callback)(gpointer data);
424+
gpointer data;
425+
};
426+
427+
static void fl_renderer_call_blocking_trampoline(gpointer user_data) {
428+
auto* data = static_cast<_FlRendererCallBlockingTrampolineData*>(user_data);
429+
data->callback(data->data);
430+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
431+
fl_renderer_get_instance_private(data->renderer));
432+
g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->mutex);
433+
*data->finished = TRUE;
434+
g_cond_signal(&priv->cond);
435+
}
436+
437+
// Executes the given function on the main thread and blocks until it completes.
438+
static void fl_renderer_call_blocking(FlRenderer* self,
439+
void (*callback)(gpointer data),
440+
gpointer callback_data) {
441+
gboolean finished = FALSE;
442+
_FlRendererCallBlockingTrampolineData trampoline_data = {
443+
self,
444+
&finished,
445+
callback,
446+
callback_data,
447+
};
448+
449+
gboolean scheduled = FL_RENDERER_GET_CLASS(self)->schedule_on_main_thread(
450+
self, fl_renderer_call_blocking_trampoline, &trampoline_data);
451+
452+
// Don't block if the task was not sucessfully scheduled.
453+
if (!scheduled) {
454+
return;
455+
}
456+
457+
// Wait for the task to complete.
458+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
459+
fl_renderer_get_instance_private(self));
460+
461+
g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->mutex);
462+
while (!finished) {
463+
g_cond_wait(&priv->cond, &priv->mutex);
464+
}
465+
}
466+
391467
gboolean fl_renderer_create_backing_store(
392468
FlRenderer* self,
393469
const FlutterBackingStoreConfig* config,
@@ -450,10 +526,11 @@ void fl_renderer_wait_for_frame(FlRenderer* self,
450526
}
451527
}
452528

453-
gboolean fl_renderer_present_layers(FlRenderer* self,
454-
FlutterViewId view_id,
455-
const FlutterLayer** layers,
456-
size_t layers_count) {
529+
static gboolean fl_renderer_present_layers_on_main_thread(
530+
FlRenderer* self,
531+
FlutterViewId view_id,
532+
const FlutterLayer** layers,
533+
size_t layers_count) {
457534
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
458535
fl_renderer_get_instance_private(self));
459536

@@ -564,6 +641,41 @@ gboolean fl_renderer_present_layers(FlRenderer* self,
564641
return TRUE;
565642
}
566643

644+
struct _FlRendererPresentLayersData {
645+
FlRenderer* self;
646+
FlutterViewId view_id;
647+
const FlutterLayer** layers;
648+
size_t layers_count;
649+
gboolean* res;
650+
};
651+
652+
static void fl_renderer_present_layers_trampoline(gpointer trampoline_data) {
653+
_FlRendererPresentLayersData* data =
654+
reinterpret_cast<_FlRendererPresentLayersData*>(trampoline_data);
655+
fl_renderer_make_current(data->self);
656+
*data->res = fl_renderer_present_layers_on_main_thread(
657+
data->self, data->view_id, data->layers, data->layers_count);
658+
fl_renderer_clear_current(data->self);
659+
}
660+
661+
gboolean fl_renderer_present_layers(FlRenderer* self,
662+
FlutterViewId view_id,
663+
const FlutterLayer** layers,
664+
size_t layers_count) {
665+
gboolean res = FALSE;
666+
_FlRendererPresentLayersData data = {
667+
.self = self,
668+
.view_id = view_id,
669+
.layers = layers,
670+
.layers_count = layers_count,
671+
.res = &res,
672+
};
673+
fl_renderer_clear_current(self);
674+
fl_renderer_call_blocking(self, fl_renderer_present_layers_trampoline, &data);
675+
fl_renderer_make_current(self);
676+
return res;
677+
}
678+
567679
void fl_renderer_setup(FlRenderer* self) {
568680
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
569681
fl_renderer_get_instance_private(self));

engine/src/flutter/shell/platform/linux/fl_renderer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ struct _FlRendererClass {
5555
* @renderer: an #FlRenderer.
5656
*/
5757
void (*clear_current)(FlRenderer* renderer);
58+
59+
/**
60+
* Virtual method responsible for scheduling the callback on the main thread.
61+
* Overriden in the mock renderer.
62+
*/
63+
gboolean (*schedule_on_main_thread)(FlRenderer* renderer,
64+
void (*callback)(gpointer data),
65+
gpointer data);
5866
};
5967

6068
/**

engine/src/flutter/shell/platform/linux/fl_task_runner.cc

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,16 @@ struct _FlTaskRunner {
2222
};
2323

2424
typedef struct _FlTaskRunnerTask {
25-
// absolute time of task (based on g_get_monotonic_time)
25+
// absolute time of task (based on g_get_monotonic_time).
2626
gint64 task_time_micros;
27+
28+
// flutter task to execute if schedule through
29+
// fl_task_runner_post_flutter_task.
2730
FlutterTask task;
31+
32+
// callback to execute if scheduled through fl_task_runner_post_callback.
33+
void (*callback)(gpointer data);
34+
gpointer callback_data;
2835
} FlTaskRunnerTask;
2936

3037
G_DEFINE_TYPE(FlTaskRunner, fl_task_runner, G_TYPE_OBJECT)
@@ -56,7 +63,11 @@ static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) {
5663
l = expired_tasks;
5764
while (l != nullptr) {
5865
FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
59-
fl_engine_execute_task(engine, &task->task);
66+
if (task->callback != nullptr) {
67+
task->callback(task->callback_data);
68+
} else {
69+
fl_engine_execute_task(engine, &task->task);
70+
}
6071
l = l->next;
6172
}
6273
}
@@ -158,9 +169,9 @@ FlTaskRunner* fl_task_runner_new(FlEngine* engine) {
158169
return self;
159170
}
160171

161-
void fl_task_runner_post_task(FlTaskRunner* self,
162-
FlutterTask task,
163-
uint64_t target_time_nanos) {
172+
void fl_task_runner_post_flutter_task(FlTaskRunner* self,
173+
FlutterTask task,
174+
uint64_t target_time_nanos) {
164175
g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
165176
(void)locker; // unused variable
166177

@@ -173,6 +184,20 @@ void fl_task_runner_post_task(FlTaskRunner* self,
173184
fl_task_runner_tasks_did_change_locked(self);
174185
}
175186

187+
void fl_task_runner_post_callback(FlTaskRunner* self,
188+
void (*callback)(gpointer data),
189+
gpointer data) {
190+
g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
191+
(void)locker; // unused variable
192+
193+
FlTaskRunnerTask* runner_task = g_new0(FlTaskRunnerTask, 1);
194+
runner_task->callback = callback;
195+
runner_task->callback_data = data;
196+
197+
self->pending_tasks = g_list_append(self->pending_tasks, runner_task);
198+
fl_task_runner_tasks_did_change_locked(self);
199+
}
200+
176201
void fl_task_runner_block_main_thread(FlTaskRunner* self) {
177202
g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
178203
(void)locker; // unused variable

engine/src/flutter/shell/platform/linux/fl_task_runner.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,29 @@ G_DECLARE_FINAL_TYPE(FlTaskRunner, fl_task_runner, FL, TASK_RUNNER, GObject);
2525
FlTaskRunner* fl_task_runner_new(FlEngine* engine);
2626

2727
/**
28-
* fl_task_runner_post_task:
28+
* fl_task_runner_post_flutter_task:
2929
* @task_runner: an #FlTaskRunner.
3030
* @task: Flutter task being scheduled
3131
* @target_time_nanos: absolute time in nanoseconds
3232
*
3333
* Posts a Flutter task to be executed on main thread. This function is thread
3434
* safe and may be called from any thread.
3535
*/
36-
void fl_task_runner_post_task(FlTaskRunner* task_runner,
37-
FlutterTask task,
38-
uint64_t target_time_nanos);
36+
void fl_task_runner_post_flutter_task(FlTaskRunner* task_runner,
37+
FlutterTask task,
38+
uint64_t target_time_nanos);
39+
40+
/**
41+
* fl_task_runner_post_callback:
42+
* @task_runner: an #FlTaskRunner.
43+
* @callback: callback to be scheduled
44+
* @data: data to be passed to the callback
45+
*
46+
* Schedules arbitrary callback to be executed on main thread.
47+
*/
48+
void fl_task_runner_post_callback(FlTaskRunner* task_runner,
49+
void (*callback)(gpointer data),
50+
gpointer data);
3951

4052
/**
4153
* fl_task_runner_block_main_thread:

engine/src/flutter/shell/platform/linux/fl_view.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ static void realize_cb(FlView* self) {
530530
fl_renderer_add_renderable(FL_RENDERER(self->renderer), self->view_id,
531531
FL_RENDERABLE(self));
532532

533+
// Flutter engine will need to make the context current from raster thread
534+
// during initialization.
535+
fl_renderer_clear_current(FL_RENDERER(self->renderer));
536+
533537
if (!fl_engine_start(self->engine, &error)) {
534538
g_warning("Failed to start Flutter engine: %s", error->message);
535539
return;

engine/src/flutter/shell/platform/linux/testing/mock_renderer.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ static void fl_mock_renderer_make_current(FlRenderer* renderer) {}
2929
// Implements FlRenderer::make_resource_current.
3030
static void fl_mock_renderer_make_resource_current(FlRenderer* renderer) {}
3131

32+
// Implements FlRenderer::schedule_on_main_thread.
33+
static gboolean fl_mock_renderer_schedule_on_main_thread(
34+
FlRenderer* renderer,
35+
void (*callback)(gpointer data),
36+
gpointer data) {
37+
callback(data);
38+
return TRUE;
39+
}
40+
3241
// Implements FlRenderer::clear_current.
3342
static void fl_mock_renderer_clear_current(FlRenderer* renderer) {}
3443

@@ -37,6 +46,8 @@ static void fl_mock_renderer_class_init(FlMockRendererClass* klass) {
3746
FL_RENDERER_CLASS(klass)->make_resource_current =
3847
fl_mock_renderer_make_resource_current;
3948
FL_RENDERER_CLASS(klass)->clear_current = fl_mock_renderer_clear_current;
49+
FL_RENDERER_CLASS(klass)->schedule_on_main_thread =
50+
fl_mock_renderer_schedule_on_main_thread;
4051
}
4152

4253
static void fl_mock_renderer_init(FlMockRenderer* self) {}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy