Skip to content

Commit afbbeac

Browse files
authored
Implement smooth resizing for Linux (flutter#25884)
1 parent edbbb12 commit afbbeac

File tree

9 files changed

+395
-63
lines changed

9 files changed

+395
-63
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec.cc
14801480
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc
14811481
FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc
14821482
FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc
1483+
FILE: ../../../flutter/shell/platform/linux/fl_task_runner.cc
1484+
FILE: ../../../flutter/shell/platform/linux/fl_task_runner.h
14831485
FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.cc
14841486
FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h
14851487
FILE: ../../../flutter/shell/platform/linux/fl_value.cc

shell/platform/linux/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ source_set("flutter_linux_sources") {
114114
"fl_standard_message_codec.cc",
115115
"fl_standard_method_codec.cc",
116116
"fl_string_codec.cc",
117+
"fl_task_runner.cc",
118+
"fl_task_runner.h",
117119
"fl_text_input_plugin.cc",
118120
"fl_value.cc",
119121
"fl_view.cc",

shell/platform/linux/fl_engine.cc

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
#include "flutter/shell/platform/linux/fl_settings_plugin.h"
1818
#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h"
1919

20-
static constexpr int kMicrosecondsPerNanosecond = 1000;
21-
2220
// Unique number associated with platform tasks.
2321
static constexpr size_t kPlatformTaskRunnerIdentifier = 1;
2422

@@ -32,6 +30,7 @@ struct _FlEngine {
3230
FlRenderer* renderer;
3331
FlBinaryMessenger* binary_messenger;
3432
FlSettingsPlugin* settings_plugin;
33+
FlTaskRunner* task_runner;
3534
FlutterEngineAOTData aot_data;
3635
FLUTTER_API_SYMBOL(FlutterEngine) engine;
3736
FlutterEngineProcTable embedder_api;
@@ -59,13 +58,6 @@ G_DEFINE_TYPE_WITH_CODE(
5958
G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(),
6059
fl_engine_plugin_registry_iface_init))
6160

62-
// Subclass of GSource that integrates Flutter tasks into the GLib main loop.
63-
typedef struct {
64-
GSource parent;
65-
FlEngine* engine;
66-
FlutterTask task;
67-
} FlutterSource;
68-
6961
// Parse a locale into its components.
7062
static void parse_locale(const gchar* locale,
7163
gchar** language,
@@ -143,40 +135,6 @@ static void setup_locales(FlEngine* self) {
143135
}
144136
}
145137

146-
// Callback to run a Flutter task in the GLib main loop.
147-
static gboolean flutter_source_dispatch(GSource* source,
148-
GSourceFunc callback,
149-
gpointer user_data) {
150-
FlutterSource* fl_source = reinterpret_cast<FlutterSource*>(source);
151-
FlEngine* self = fl_source->engine;
152-
153-
FlutterEngineResult result =
154-
self->embedder_api.RunTask(self->engine, &fl_source->task);
155-
if (result != kSuccess) {
156-
g_warning("Failed to run Flutter task\n");
157-
}
158-
159-
return G_SOURCE_REMOVE;
160-
}
161-
162-
// Called when the engine is disposed.
163-
static void engine_weak_notify_cb(gpointer user_data,
164-
GObject* where_the_object_was) {
165-
FlutterSource* source = reinterpret_cast<FlutterSource*>(user_data);
166-
source->engine = nullptr;
167-
g_source_destroy(reinterpret_cast<GSource*>(source));
168-
}
169-
170-
// Called when a flutter source completes.
171-
static void flutter_source_finalize(GSource* source) {
172-
FlutterSource* fl_source = reinterpret_cast<FlutterSource*>(source);
173-
if (fl_source->engine != nullptr) {
174-
g_object_weak_unref(G_OBJECT(fl_source->engine), engine_weak_notify_cb,
175-
fl_source);
176-
fl_source->engine = nullptr;
177-
}
178-
}
179-
180138
// Called when engine needs a backing store for a specific #FlutterLayer.
181139
static bool compositor_create_backing_store_callback(
182140
const FlutterBackingStoreConfig* config,
@@ -204,16 +162,6 @@ static bool compositor_present_layers_callback(const FlutterLayer** layers,
204162
layers_count);
205163
}
206164

207-
// Table of functions for Flutter GLib main loop integration.
208-
static GSourceFuncs flutter_source_funcs = {
209-
nullptr, // prepare
210-
nullptr, // check
211-
flutter_source_dispatch, // dispatch
212-
flutter_source_finalize, // finalize
213-
nullptr,
214-
nullptr // Internal usage
215-
};
216-
217165
// Flutter engine rendering callbacks.
218166

219167
static void* fl_engine_gl_proc_resolver(void* user_data, const char* name) {
@@ -278,15 +226,7 @@ static void fl_engine_post_task(FlutterTask task,
278226
void* user_data) {
279227
FlEngine* self = static_cast<FlEngine*>(user_data);
280228

281-
g_autoptr(GSource) source =
282-
g_source_new(&flutter_source_funcs, sizeof(FlutterSource));
283-
FlutterSource* fl_source = reinterpret_cast<FlutterSource*>(source);
284-
fl_source->engine = self;
285-
g_object_weak_ref(G_OBJECT(self), engine_weak_notify_cb, fl_source);
286-
fl_source->task = task;
287-
g_source_set_ready_time(source,
288-
target_time_nanos / kMicrosecondsPerNanosecond);
289-
g_source_attach(source, nullptr);
229+
fl_task_runner_post_task(self->task_runner, task, target_time_nanos);
290230
}
291231

292232
// Called when a platform message is received from the engine.
@@ -361,6 +301,7 @@ static void fl_engine_dispose(GObject* object) {
361301
g_clear_object(&self->renderer);
362302
g_clear_object(&self->binary_messenger);
363303
g_clear_object(&self->settings_plugin);
304+
g_clear_object(&self->task_runner);
364305

365306
if (self->platform_message_handler_destroy_notify) {
366307
self->platform_message_handler_destroy_notify(
@@ -410,6 +351,8 @@ G_MODULE_EXPORT FlEngine* fl_engine_new_headless(FlDartProject* project) {
410351
gboolean fl_engine_start(FlEngine* self, GError** error) {
411352
g_return_val_if_fail(FL_IS_ENGINE(self), FALSE);
412353

354+
self->task_runner = fl_task_runner_new(self);
355+
413356
FlutterRendererConfig config = {};
414357
config.type = kOpenGL;
415358
config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig);
@@ -722,3 +665,13 @@ G_MODULE_EXPORT FlBinaryMessenger* fl_engine_get_binary_messenger(
722665
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
723666
return self->binary_messenger;
724667
}
668+
669+
FlTaskRunner* fl_engine_get_task_runner(FlEngine* self) {
670+
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
671+
return self->task_runner;
672+
}
673+
674+
void fl_engine_execute_task(FlEngine* self, FlutterTask* task) {
675+
g_return_if_fail(FL_IS_ENGINE(self));
676+
self->embedder_api.RunTask(self->engine, task);
677+
}

shell/platform/linux/fl_engine_private.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "flutter/shell/platform/embedder/embedder.h"
1111
#include "flutter/shell/platform/linux/fl_renderer.h"
12+
#include "flutter/shell/platform/linux/fl_task_runner.h"
1213
#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
1314
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
1415

@@ -226,6 +227,24 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine,
226227
GAsyncResult* result,
227228
GError** error);
228229

230+
/**
231+
* fl_engine_get_task_runner:
232+
* @engine: an #FlEngine.
233+
* @result: a #FlTaskRunner.
234+
*
235+
* Returns: task runner responsible for scheduling Flutter tasks.
236+
*/
237+
FlTaskRunner* fl_engine_get_task_runner(FlEngine* engine);
238+
239+
/**
240+
* fl_engine_execute_task:
241+
* @engine: an #FlEngine.
242+
* @task: a #FlutterTask to execute.
243+
*
244+
* Executes given Flutter task.
245+
*/
246+
void fl_engine_execute_task(FlEngine* engine, FlutterTask* task);
247+
229248
G_END_DECLS
230249

231250
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_

shell/platform/linux/fl_renderer.cc

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,50 @@
99

1010
#include "flutter/shell/platform/embedder/embedder.h"
1111
#include "flutter/shell/platform/linux/fl_backing_store_provider.h"
12+
#include "flutter/shell/platform/linux/fl_engine_private.h"
1213

1314
G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error)
1415

1516
typedef struct {
1617
FlView* view;
1718

19+
// target dimension for resizing
20+
int target_width;
21+
int target_height;
22+
23+
// whether the renderer waits for frame render
24+
bool blocking_main_thread;
25+
26+
// true if frame was completed; resizing is not synchronized until first frame
27+
// was rendered
28+
bool had_first_frame;
29+
1830
GdkGLContext* main_context;
1931
GdkGLContext* resource_context;
2032
} FlRendererPrivate;
2133

2234
G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
2335

24-
static void fl_renderer_class_init(FlRendererClass* klass) {}
36+
static void fl_renderer_unblock_main_thread(FlRenderer* self) {
37+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
38+
fl_renderer_get_instance_private(self));
39+
if (priv->blocking_main_thread) {
40+
priv->blocking_main_thread = false;
41+
42+
FlTaskRunner* runner =
43+
fl_engine_get_task_runner(fl_view_get_engine(priv->view));
44+
fl_task_runner_release_main_thread(runner);
45+
}
46+
}
47+
48+
static void fl_renderer_dispose(GObject* self) {
49+
fl_renderer_unblock_main_thread(FL_RENDERER(self));
50+
G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(self);
51+
}
52+
53+
static void fl_renderer_class_init(FlRendererClass* klass) {
54+
G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose;
55+
}
2556

2657
static void fl_renderer_init(FlRenderer* self) {}
2758

@@ -109,9 +140,42 @@ gboolean fl_renderer_collect_backing_store(
109140
backing_store);
110141
}
111142

143+
void fl_renderer_wait_for_frame(FlRenderer* self,
144+
int target_width,
145+
int target_height) {
146+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
147+
fl_renderer_get_instance_private(self));
148+
149+
priv->target_width = target_width;
150+
priv->target_height = target_height;
151+
152+
if (priv->had_first_frame && !priv->blocking_main_thread) {
153+
priv->blocking_main_thread = true;
154+
FlTaskRunner* runner =
155+
fl_engine_get_task_runner(fl_view_get_engine(priv->view));
156+
fl_task_runner_block_main_thread(runner);
157+
}
158+
}
159+
112160
gboolean fl_renderer_present_layers(FlRenderer* self,
113161
const FlutterLayer** layers,
114162
size_t layers_count) {
163+
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
164+
fl_renderer_get_instance_private(self));
165+
166+
// ignore incoming frame with wrong dimensions in trivial case with just one
167+
// layer
168+
if (priv->blocking_main_thread && layers_count == 1 &&
169+
layers[0]->offset.x == 0 && layers[0]->offset.y == 0 &&
170+
(layers[0]->size.width != priv->target_width ||
171+
layers[0]->size.height != priv->target_height)) {
172+
return true;
173+
}
174+
175+
priv->had_first_frame = true;
176+
177+
fl_renderer_unblock_main_thread(self);
178+
115179
return FL_RENDERER_GET_CLASS(self)->present_layers(self, layers,
116180
layers_count);
117181
}

shell/platform/linux/fl_renderer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,20 @@ gboolean fl_renderer_present_layers(FlRenderer* renderer,
242242
const FlutterLayer** layers,
243243
size_t layers_count);
244244

245+
/**
246+
* fl_renderer_wait_for_frame:
247+
* @renderer: an #FlRenderer.
248+
* @target_width: width of frame being waited for
249+
* @target_height: height of frame being waited for
250+
*
251+
* Holds the thread until frame with requested dimensions is presented.
252+
* While waiting for frame Flutter platform and raster tasks are being
253+
* processed.
254+
*/
255+
void fl_renderer_wait_for_frame(FlRenderer* renderer,
256+
int target_width,
257+
int target_height);
258+
245259
G_END_DECLS
246260

247261
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_H_

0 commit comments

Comments
 (0)