Flutter UI 渲染浅析(二)VSync 注册
在 Flutter App 启动过程或者 State 刷新过程中,会请求注册 VSync 信号。
本篇文章主要分析下 VSync 信号注册以及回调过程。
基于 Android 平台,Flutter v1.20.4。
调用时序图
1、Flutter App 启动
Flutter App 启动过程中调用 runApp()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void runApp(Widget app) { WidgetsFlutterBinding.ensureInitialized() ..scheduleAttachRootWidget(app) ..scheduleWarmUpFrame(); } class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { static WidgetsBinding ensureInitialized() { if (WidgetsBinding.instance == null) WidgetsFlutterBinding(); return WidgetsBinding.instance; } }
|
runApp()
过程中初始化 WidgetsFlutterBinding
,它是 Dart Framework 和 C++ Engine 之间的胶水层,并且混入了 7 个Binding 类,用于初始化 7 个 Binding 类。
上文中我们提到,Window
是 dart:ui
包中最重要的类,通过 Window
建立起了建立 Dart Framework 和 C++ Engine 的通讯连接,Window
在 Flutter Framework 和 C++ Engine 中分别存在,并通过 ffi
互相调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Window { VoidCallback? get onMetricsChanged => _onMetricsChanged; VoidCallback? get onLocaleChanged => _onLocaleChanged; VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged; FrameCallback get onBeginFrame => _onBeginFrame; VoidCallback get onDrawFrame => _onDrawFrame; TimingsCallback? get onReportTimings => _onReportTimings; PointerDataPacketCallback get onPointerDataPacket => _onPointerDataPacket; void scheduleFrame() native 'Window_scheduleFrame'; void render(Scene scene) native 'Window_render'; void sendPlatformMessage(String name, ByteData data, PlatformMessageResponseCallback callback) ; PlatformMessageCallback get onPlatformMessage => _onPlatformMessage; ... }
|
在 Window
中存在一些回调方法,由 C++ Engine 触发回调方法,触发 Flutter Framework 执行相应动作。
这些回调方法分散注册在 7 个 Binding 类中。
- SchedulerBinding,渲染任务调度器,注册
onBeginFrame
、 onDrawFrame
、onReportTimings
等回调,用于调度渲染流程、计算绘制耗时
- WidgetsBinding,是视图层和 Flutter Engine 之间的胶水层,用于管理三棵树的构建和更新操作;注册
window.onLocaleChanged
、onBuildScheduled
回调;持有 BuilderOwner 对象
- RendererBinding,是绘制树 (Render Tree) 和 Flutter Engine 之间的胶水层,用于布局和绘制,核心方法
drawFrame()
;注册 window.onMetricsChanged
、window.onTextScaleFactorChanged
等回调;持有 PipelineOwner 对象
- PaintingBinding,绑定绘制库,主要用于处理图片缓存
- ServicesBinding,注册
window.onPlatformMessage
回调, 用于绑定平台消息通道(message channel),处理原生和 Flutter 通信
- GestureBinding,注册
window.onPointerDataPacket
回调,绑定Framework手势子系统,是Framework事件模型与底层事件的绑定入口
- SemanticsBinding,语义化层与Flutter engine的桥梁,主要是辅助功能的底层支持
重点关注 SchedulerBinding
、WidgetsBinding
、RendererBinding
及他们注册的回调方法。
2、scheduleFrame
1 2 3 4 5 6
| void runApp(Widget app) { WidgetsFlutterBinding.ensureInitialized() ..scheduleAttachRootWidget(app) ..scheduleWarmUpFrame(); }
|
在 runApp()
启动方法中
scheduleAttachRootWidget(app)
首先构建三棵树,并且通过 BuildOwner
调用 scheduleFrame()
触发注册 VSync 信号
scheduleWarmUpFrame()
准备第一帧的绘制工作,触发 beginFrame()
和 drawFrame()
执行方法,这样就不用等待 VSync 信号回调,可以尽快的绘制第一帧
同样的,在 State.setState()
方法中也会触发 ScheduleFrame()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| abstract class State<T extends StatefulWidget> with Diagnosticable { void setState(VoidCallback fn) { ... final dynamic result = fn() as dynamic; ... _element.markNeedsBuild(); } } abstract class Element extends DiagnosticableTree implements BuildContext { void markNeedsBuild() { ... if (dirty) return; _dirty = true; owner.scheduleBuildFor(this); } } class BuildOwner { void scheduleBuildFor(Element element) { ... if (!_scheduledFlushDirtyElements && onBuildScheduled != null) { _scheduledFlushDirtyElements = true; onBuildScheduled(); } _dirtyElements.add(element); element._inDirtyList = true; }
|
最终会调用到 BuildOwner.onBuildScheduled()
,这个回调方法是在 WidgetsBinding.initInstances()
初始化过程中中注册的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { @override void initInstances() { super.initInstances(); _instance = this; _buildOwner = BuildOwner(); buildOwner.onBuildScheduled = _handleBuildScheduled; window.onLocaleChanged = handleLocaleChanged; window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation); FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator); } void _handleBuildScheduled() { ... ensureVisualUpdate(); } }
|
交给 SchedulerBinding
调度处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void ensureVisualUpdate() { switch (schedulerPhase) { case SchedulerPhase.idle: case SchedulerPhase.postFrameCallbacks: scheduleFrame(); return; case SchedulerPhase.transientCallbacks: case SchedulerPhase.midFrameMicrotasks: case SchedulerPhase.persistentCallbacks: return; } } void scheduleFrame() { if (_hasScheduledFrame || !framesEnabled) return; ensureFrameCallbacksRegistered(); window.scheduleFrame(); } void ensureFrameCallbacksRegistered() { window.onBeginFrame ??= _handleBeginFrame; window.onDrawFrame ??= _handleDrawFrame; }
|
通过 window
调用Engine Window ::scheduleFrame()
Native 方法,并注册 onBeginFrame
、onDrawFrame
回调方法。
看下 SchedulerBinding
的状态机,这里是和 C++ Engine 中的回调过程一一对应的,后面会看到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| enum SchedulerPhase { idle, transientCallbacks, midFrameMicrotasks, persistentCallbacks, postFrameCallbacks, }
|
3、dart:ffi
在 Flutter 中,可以使用 dart:ffi
实现 Dart 方法和 Native 方法的互相调用绑定,类似于 Java 的 JNI
。
在 Engine Window
类中,通过 dart:ffi
注册 Native
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void Window::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({ {"Window_defaultRouteName", DefaultRouteName, 1, true}, {"Window_scheduleFrame", ScheduleFrame, 1, true}, {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true}, {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true}, {"Window_render", Render, 2, true}, {"Window_updateSemantics", UpdateSemantics, 2, true}, {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true}, {"Window_reportUnhandledException", ReportUnhandledException, 2, true}, {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true}, ... }); }
|
列表中的参数:
- 第一个参数是 Dart 方法id
- 第二个参数是 Engine 中
Native
方法的指针,一般以 _
开头的方法是 Dart 注册的回调方法或者需要回调的方法
- 第三个参数是方法参数个数
- 第四个参数为是否自动注册
在 DartVM
启动过程中,将 Native 方法注册到 dart:ffi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| using tonic::ToDart; namespace flutter { namespace { static tonic::DartLibraryNatives* g_natives; Dart_NativeFunction GetNativeFunction(Dart_Handle name, int argument_count, bool* auto_setup_scope) { return g_natives->GetNativeFunction(name, argument_count, auto_setup_scope); } const uint8_t* GetSymbol(Dart_NativeFunction native_function) { return g_natives->GetSymbol(native_function); } } void DartUI::InitForGlobal() { if (!g_natives) { g_natives = new tonic::DartLibraryNatives(); Canvas::RegisterNatives(g_natives); CanvasGradient::RegisterNatives(g_natives); CanvasImage::RegisterNatives(g_natives); CanvasPath::RegisterNatives(g_natives); CanvasPathMeasure::RegisterNatives(g_natives); Codec::RegisterNatives(g_natives); ColorFilter::RegisterNatives(g_natives); DartRuntimeHooks::RegisterNatives(g_natives); EngineLayer::RegisterNatives(g_natives); FontCollection::RegisterNatives(g_natives); FrameInfo::RegisterNatives(g_natives); ImageFilter::RegisterNatives(g_natives); ImageShader::RegisterNatives(g_natives); IsolateNameServerNatives::RegisterNatives(g_natives); Paragraph::RegisterNatives(g_natives); ParagraphBuilder::RegisterNatives(g_natives); Picture::RegisterNatives(g_natives); PictureRecorder::RegisterNatives(g_natives); Scene::RegisterNatives(g_natives); SceneBuilder::RegisterNatives(g_natives); SemanticsUpdate::RegisterNatives(g_natives); SemanticsUpdateBuilder::RegisterNatives(g_natives); Vertices::RegisterNatives(g_natives); Window::RegisterNatives(g_natives); #if defined(LEGACY_FUCHSIA_EMBEDDER) SceneHost::RegisterNatives(g_natives); #endif } } void DartUI::InitForIsolate() { FML_DCHECK(g_natives); Dart_Handle result = Dart_SetNativeResolver( Dart_LookupLibrary(ToDart("dart:ui")), GetNativeFunction, GetSymbol); if (Dart_IsError(result)) { Dart_PropagateError(result); } }
|
DartVM 初始化过程中会调用 DartUI::InitForIsolate()
进行方法注册。
上面的类都是 dart:ui
包下的类,通过 dart:ffi
将 Dart 方法和 Native 方法进行绑定。
dart:ffi
的详细介绍见 Binding to native code using dart:ffi
4、注册 VSync
继续调用 Window::ScheduleFrame()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| void ScheduleFrame(Dart_NativeArguments args) { UIDartState::ThrowIfUIOperationsProhibited(); UIDartState::Current()->window()->client()->ScheduleFrame(); } void RuntimeController::ScheduleFrame() { client_.ScheduleFrame(); } void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } void Animator::RequestFrame(bool regenerate_layer_tree) { if (regenerate_layer_tree) { regenerate_layer_tree_ = true; } if (paused_ && !dimension_change_pending_) { return; } if (!pending_frame_semaphore_.TryWait()) { return; } task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(), frame_number = frame_number_]() { if (!self.get()) { return; } TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number); self->AwaitVSync(); }); frame_scheduled_ = true; }
|
- 这里方法的参数
regenerate_layer_tree
默认值是 true,当为 false 时不需要重绘
- 通过
pending_frame_semaphore_
信号量控制 Animator::ScheduleFrame
只需注册一次 VSync 信号,初始值为1,为0 时,这里 pending_frame_semaphore_
-1,Animator::beginFrame()
被调用后 pending_frame_semaphore_
+ 1
- 在 UIThread 执行 VSync 注册回调
4.1、Animator::AwaitVSync()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void Animator::AwaitVSync() { waiter_->AsyncWaitForVsync( [self = weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time, fml::TimePoint frame_target_time) { if (self) { if (self->CanReuseLastLayerTree()) { self->DrawLastLayerTree(); } else { self->BeginFrame(frame_start_time, frame_target_time); } } }); delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_); }
|
- 注册VSync 信号的回调
frame_start_time
为接受到 VSync 信号时间点, frame_target_time
为这一帧渲染目标时间,超过这个时间点即为掉帧,下一帧就不会注册 VSync 信号回调
- regenerate_layer_tree 为false,复用上一次生成的LayerTree,直接光栅化合成;为 false 继续触发渲染管线启动
waiter_
为 VsyncWaiter
对象,在引擎启动过程中,初始化 Shell
时被创建,根据不同 Platform,构建出不同的对象,这里以 Android 为例,它是 VsyncWaiterAndroid
类的对象
4.2、VsyncWaiter::AsyncWaitForVsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) { ... TRACE_EVENT0("flutter", "AsyncWaitForVsync"); { std::scoped_lock lock(callback_mutex_); ... callback_ = std::move(callback); ... } AwaitVSync(); } void VsyncWaiterAndroid::AwaitVSync() { auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this()); jlong java_baton = reinterpret_cast<jlong>(weak_this); task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { JNIEnv* env = fml::jni::AttachCurrentThread(); env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), g_async_wait_for_vsync_method_, java_baton ); }); } bool VsyncWaiterAndroid::Register(JNIEnv* env) { static const JNINativeMethod methods[] = {{ .name = "nativeOnVsync", .signature = "(JJJ)V", .fnPtr = reinterpret_cast<void*>(&OnNativeVsync), }}; jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI"); g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz); g_async_wait_for_vsync_method_ = env->GetStaticMethodID( g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V"); return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0; }
|
在引擎启动过程中,已经通过 Java JNI 绑定了 C++ 和 Java 代码的映射,这里通过 JNI 调用 Android Java 代码
- JNIEnv 代表了 Java 在本线程的执行环境(在这里就是 Android 主线程),它的结构是一个函数表
- 注册 VSync 信号回调
nativeOnVsync
Native 方法 OnNativeVsync
- 运行在 PlatformThread,即 Android 主线程
g_vsync_waiter_class
与 io/flutter/embedding/engine/FlutterJNI
Java 类绑定
g_async_wait_for_vsync_method_
是 io/flutter/embedding/engine/FlutterJNI.asyncWaitForVsync()
Java 方法的指针
最终在 Android 主线程调用 io/flutter/embedding/engine/FlutterJNI.asyncWaitForVsync()
方法。
4.3、Choreographer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| private static void asyncWaitForVsync(final long cookie) { asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie); ... } public class VsyncWaiter { private static VsyncWaiter instance; @NonNull public static VsyncWaiter getInstance(@NonNull WindowManager windowManager) { if (instance == null) { instance = new VsyncWaiter(windowManager); } return instance; } @NonNull private final WindowManager windowManager; private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate() { @Override public void asyncWaitForVsync(long cookie) { Choreographer.getInstance() .postFrameCallback( new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { float fps = windowManager.getDefaultDisplay().getRefreshRate(); long refreshPeriodNanos = (long) (1000000000.0 / fps); FlutterJNI.nativeOnVsync( frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie); } }); } }; private VsyncWaiter(@NonNull WindowManager windowManager) { this.windowManager = windowManager; } public void init() { FlutterJNI.setAsyncWaitForVsyncDelegate(asyncWaitForVsyncDelegate); float fps = windowManager.getDefaultDisplay().getRefreshRate(); FlutterJNI.setRefreshRateFPS(fps); } }
|
- 在 App 启动过程中,
FlutterLoader.startInitialization()
方法中初始化 VsyncWaiter
单例,设置 FlutterJNI delegate
- 通过
Choreographer..postFrameCallback()
注册 VSync 信号回调,只会回调一次,每用一次注册一次
- 根据屏幕刷新频率,计算
frame_start_time
和 frame_target_time
- 收到 VSync 信号回调后,通过 JNI 回调 Native 方法
Choreographer 通过 SurfaceFlinger
注册 VSync 信号回调 FrameDisplayEventReceiver
,一旦 VSync 信号到来,SurfaceFlinger
通知 FrameDisplayEventReceiver 回调 doFrame()
方法.
注意只会回调一次,每用一次注册一次。所以当屏幕静止未刷新时,FPS 会一为未 0。
4.4、OnNativeVsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameTimeNanos, jlong frameTargetTimeNanos, jlong java_baton) { auto frame_time = fml::TimePoint::FromEpochDelta( fml::TimeDelta::FromNanoseconds(frameTimeNanos)); auto target_time = fml::TimePoint::FromEpochDelta( fml::TimeDelta::FromNanoseconds(frameTargetTimeNanos)); ConsumePendingCallback(java_baton, frame_time, target_time); } void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time) { Callback callback; fml::closure secondary_callback; { std::scoped_lock lock(callback_mutex_); callback = std::move(callback_); } if (callback) { auto flow_identifier = fml::tracing::TraceNonce(); TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier); task_runners_.GetUITaskRunner()->PostTaskForTime( [callback, flow_identifier, frame_start_time, frame_target_time]() { callback(frame_start_time, frame_target_time); TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier); }, frame_start_time); } }
|
执行注册的回调方法,运行在 UIThread,回到 #4.1
5、BeginFrame
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| void Animator::BeginFrame(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time) { frame_scheduled_ = false; notify_idle_task_id_++; regenerate_layer_tree_ = false; pending_frame_semaphore_.Signal(); if (!producer_continuation_) { producer_continuation_ = layer_tree_pipeline_->Produce(); if (!producer_continuation_) { RequestFrame(); return; } } last_frame_begin_time_ = frame_start_time; last_frame_target_time_ = frame_target_time; dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time); { delegate_.OnAnimatorBeginFrame(frame_target_time); } if (!frame_scheduled_) { task_runners_.GetUITaskRunner()->PostDelayedTask( [self = weak_factory_.GetWeakPtr(), notify_idle_task_id = notify_idle_task_id_]() { if (!self.get()) { return; } if (notify_idle_task_id == self->notify_idle_task_id_ && !self->frame_scheduled_) { self->delegate_.OnAnimatorNotifyIdle(Dart_TimelineGetMicros() + 100000); } }, kNotifyIdleTaskWaitTime); } }
|
- 信号量 pending_framesemaphore +1,可以继续接收 RequestFrame 请求
- regenerate_layertree 赋值 false,在一些情况下调用 RequestFrame 可以复用这次生成的
flutter::LayerTree
producer_continuation_
是 ProducerContinuation
类的对象,持有生产对象,并通过信号量控制管线任务
layer_tree_pipeline_
是 LayerTreePipeline
类的对象,在 Animator 初始化过程中被创建,LayerTreePipeline
是一个线程安全的生产者消费者队列, UIThread 负责生产 flutter::LayerTree
和 RasterThread 负责消费 flutter::LayerTree
,flutter::LayerTree
持有 Dart Framework 生成的Layer Tree映射到 Engine 的 flow::Layer
的根节点
- 执行
delegate_.OnAnimatorBeginFrame(frame_target_time)
, delagate_ 的实现在 Shell
类
5.1、LayerTreePipeline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| // shell/common/animator.h using LayerTreePipeline = Pipeline<flutter::LayerTree>; ... // shell/common/animator.cc Animator::Animator(Delegate& delegate, TaskRunners task_runners, std::unique_ptr<VsyncWaiter> waiter) : delegate_(delegate), task_runners_(std::move(task_runners)), waiter_(std::move(waiter)), last_frame_begin_time_(), last_frame_target_time_(), dart_frame_deadline_(0), #if FLUTTER_SHELL_ENABLE_METAL // 支持 Metal 深度为2 layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(2)), #else // 这里在一些情况下有bug,后续版本会写死深度为2 layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>( task_runners.GetPlatformTaskRunner() == task_runners.GetRasterTaskRunner() ? 1 : 2)), #endif // FLUTTER_SHELL_ENABLE_METAL // pending_frame_semaphore_ 初始化为1,可以接受一个 RequestFrame 请求 pending_frame_semaphore_(1), ... // shell/common/pipeline.h explicit Pipeline(uint32_t depth) : depth_(depth), empty_(depth), available_(0), inflight_(0) {} fml::Semaphore empty_; // 默认为2 fml::Semaphore available_ // 默认为0
|
构建深度为 2 的 Pipeline
对象,可以持有 flutter::LayerTree
对象。
Pipeline 持有两个信号量 empty_
和 available_
,用来控制管线任务调度。
当调用 layer_tree_pipeline_->Produce()
方法时
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ProducerContinuation Produce() { if (!empty_.TryWait()) { return {}; } ++inflight_; return ProducerContinuation{ std::bind(&Pipeline::ProducerCommit, this, std::placeholders::_1, std::placeholders::_2), GetNextPipelineTraceID()}; }
|
生成一个 ProducerContinuation
类的对象 producer_continuation_
,continuation_
对象持有 Pipeline::ProducerCommit()
方法引用。
当 UIThread 在 Dart Framework 生成 Layer Tree,并通过 SceneBuilder
构建出 Scene
对象,持有 flutter:LayerTree
,调用 window.render()
方法开启光栅化合成之前,会调用Pipeline::ProducerCommit()
方法,并将 flutter:LayerTree
绑定到 producer_continuation_
对象
1 2 3 4 5 6 7 8 9 10 11
| bool ProducerCommit(ResourcePtr resource, size_t trace_id) { { std::scoped_lock lock(queue_mutex_); queue_.emplace_back(std::move(resource), trace_id); } available_.Signal(); return true; }
|
整个 Pipeline 管线的流程为:
Animator::RequestFrame()
方法触发绘制开始_empty
-1,开始生成 flutter::LayerTree
,运行在 UIThread
当 UIThread 准备好 Engine flutter::LayerTree
, available_
+1
当 available_
> 0 时,触发 Raster Thread 工作,拿到 flutter:LayerTree
进行光栅化合成
当 RasterThread 处理完成, _empty
+ 1,下次 Animator::RequestFrame()
可以正常开始处理生成 flutter::LayerTree
工作
当 _empty
为 0 时,管线任务已满,忽略本次 Animator::RequestFrame()
请求,直到下一次 VSync 信号到来
通过两个信号量来管理管线的调度,这种调度机制可以确保 RasterThread 不至于过载(2个任务),同时也可以避免 UIThread 不必要的资源消耗。
所以不论在 UIThread 还是在 RasterThread 耗时太久,都可能会导致 Flutter 应用卡顿,因为会导致延迟接受 VSync 信号,导致掉帧。
5.2、OnAnimatorBeginFrame
继续调用 delegate_.OnAnimatorBeginFrame(frame_target_time)
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time) { FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); { std::scoped_lock time_recorder_lock(time_recorder_mutex_); latest_frame_target_time_.emplace(frame_target_time); } if (engine_) { engine_->BeginFrame(frame_target_time); } } void Engine::BeginFrame(fml::TimePoint frame_time) { TRACE_EVENT0("flutter", "Engine::BeginFrame"); runtime_controller_->BeginFrame(frame_time); } bool RuntimeController::BeginFrame(fml::TimePoint frame_time) { if (auto* window = GetWindowIfAvailable()) { window->BeginFrame(frame_time); return true; } return false; } void Window::DidCreateIsolate() { library_.Set(tonic::DartState::Current(), Dart_LookupLibrary(tonic::ToDart("dart:ui"))); } void Window::BeginFrame(fml::TimePoint frameTime) { tonic::DartState::Scope scope(dart_state); int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds(); tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame", { Dart_NewInteger(microseconds), })); UIDartState::Current()->FlushMicrotasksNow(); tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {})); }
|
通过 Shell::OnAnimatorBeginFrame -> Engine::BeginFrame -> RuntimeController::BeginFrame -> Window::BeginFrame 层层调用,通过 ffi 回调 Dart Framework 继续绘制流程。
做三件事情:
- 执行 Dart Framework
dart:ui
包下的 _beginFrame()
- 执行 microtasks 任务
- 执行 Dart Framework
dart:ui
包下的 _drawFrame()
这个流程和文章开头提到的 SchedulerBinding
的状态机 SchedulerPhase
中声明的状态一一对应,接下来回调到 Dart Framework 后,由 SchedulerBinding
进行绘制调度。
到这里,VSync 注册流程结束,接下来回到 Dart Framework 中继续进行。
参考
14.4 Flutter运行机制-从启动到显示
Flutter渲染机制—UI线程
本文链接: http://w4lle.com/2020/11/11/flutter-ui-vsync/
版权声明:本文为 w4lle 原创文章,可以随意转载,但必须在明确位置注明出处!
本文链接: http://w4lle.com/2020/11/11/flutter-ui-vsync/