Flutter UI构建渲染
简述
之前我们介绍了FlutterUI的核心元素,包括Widget,Element,RenderObject,Layer。而这一节我们就来介绍一下Flutter是怎么构建这些元素,并且调用组件定义的布局绘制方法,最终渲染合成上屏的。
简单来说就是会根据Widget树来构建Element树,他们之间的元素是一对一的,而Element在mount的时候,如果是RenderObjectElement,拥有绘制能力的Element就会构建RenderObject,相当于同时构建了RenderObject树,还会构建RenderView,之后滴哦啊用RenderView.render就会将构建的LayerTree放到任务队列中。通过scheduleFrame注册VSync回调,回调时候就会从任务队列取出LayerTree然后进行渲染合成。
WidgetsFlutterBinding.binding
之前我们已经介绍了Android Activity启动之后,Flutter是怎么启动dart的流程的,同时上一节也介绍了Flutter UI的几个关键要素,这一节就从dart入口开始看。
1.1 main
入口函数调用了runApp
void main() {
runApp(const MyApp());
}
1.2 runApp
WidgetsFlutterBinding调用ensureInitialized来进行初始化
void runApp(Widget app) {
// 详见1.3
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
// 详见2.1
_runWidget(binding.wrapWithDefaultView(app), binding, 'runApp');
}
1.3 WidgetsFlutterBinding.ensureInitialized
构建一个WidgetsFlutterBinding进行初始化
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding._instance == null) {
// 详见1.4
WidgetsFlutterBinding();
}
return WidgetsBinding.instance;
}
1.4 WidgetsFlutterBinding
dart的关键词with:
with后面跟着的是mixin关键词声明的类,这个语法类似于C语言的include,其实就相当于把mixin声明类的内容写在了当前这个类中。
所以这里初始化执行了所有Binding,这里的所有XXXBinding都继承了BindingBase,而BindingBase构造函数都调用了initInstances和initServiceExtensions,所以这里都每个XXXBinding的initInstances和initServiceExtensions都被调用了。
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding
_runWidget
我们紧跟着1.2节的_runWidget
2.1 _runWidget
scheduleAttachRootWidget会构建节点,scheduleWarmUpFrame触发渲染帧,我们先跟scheduleAttachRootWidget。
其实这里scheduleAttachRootWidget后续调用的scheduleFrame会注册下一个VSync信号,然后等待下一个VSync信号来之后做合成处理,它依赖于scheduleWarmUpFrame来构建更新LayerTree,所以实际上这里scheduleWarmUpFrame是先执行的,而scheduleAttachRootWidget中合成是下一个VSync执行的,我们一会看到的时候会再提一下。
void _runWidget(Widget app, WidgetsBinding binding, String debugEntryPoint) {
assert(binding.debugCheckZone(debugEntryPoint));
binding
// 详见2.2
..scheduleAttachRootWidget(app)
// 详见3.1
..scheduleWarmUpFrame();
}
2.2 scheduleAttachRootWidget
调用attachRootWidget
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
// 详见2.3
attachRootWidget(rootWidget);
});
}
2.3 attachRootWidget
调用attachToBuildOwner
void attachRootWidget(Widget rootWidget) {
// 详见2.4,这里Widget外层封装了RootWidget
attachToBuildOwner(RootWidget(
debugShortDescription: '[root]',
child: rootWidget,
));
}
2.4 attachToBuildOwner
调用RootWidget.attach
void attachToBuildOwner(RootWidget widget) {
final bool isBootstrapFrame = rootElement == null;
_readyToProduceFrames = true;
// 详见2.4.1
_rootElement = widget.attach(buildOwner!, rootElement as RootElement?);
if (isBootstrapFrame) {
// 详见2.5
SchedulerBinding.instance.ensureVisualUpdate();
}
}
2.4.1 RootWidget.attach
调用createElement创建Element,然后调用element.mount挂载节点
RootElement attach(BuildOwner owner, [ RootElement? element ]) {
if (element == null) {
owner.lockState(() {
// 构建RootElement
element = createElement();
assert(element != null);
element!.assignOwner(owner);
});
owner.buildScope(element!, () {
// 详见2.4.2,
element!.mount(/* parent */ null, /* slot */ null);
});
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element!;
}
2.4.2 RootElement.mount
调用super.mount,这里是Elemnt.mount
这里顺带提一下,不同的Element是会有自己的mount实现的,比如RenderObjectElement会在mount的时候调用RenderObjectWidget的createRenderObject来构建RenderObject,而且还会调用_attachView构建renderView。
void mount(Element? parent, Object? newSlot) {
assert(parent == null); // We are the root!
// 关联记录父节点
super.mount(parent, newSlot);
// 详见2.4.3
_rebuild();
assert(_child != null);
super.performRebuild(); // clears the "dirty" flag
}
2.4.3 RootElement._rebuild
使用过Flutter开发App的就会知道,Flutter提供Widget来给应用开发者来定义UI,一般的Widget只有一个child,而MultiChildRenderObjectWidget是有一个children,支持多个字节点。
void _rebuild() {
try {
// 详见2.4.4,更新子节点
_child = updateChild(_child, (widget as RootWidget).child, /* slot */ null);
} catch (exception, stack) {
// ...
}
}
2.4.4 updateChild
Flutter的UI是业务开发通过Widget构建了树之后,然后根据Widget构建的树生成/维护一个Element的树,所以这里需要根据Widget树更新Element树,这里的入参child是未更新的Element,而Widget是RootWidget的child,也就是业务写的Widget
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
// 入参child是之前的子节点,而newWidget是从当前Element对应的Widget中获取的
// 如果Widget不为空,而child也不为空,则说明当前child需要更新
if (newWidget == null) {
if (child != null) {
deactivateChild(child);
}
return null;
}
final Element newChild;
// 如果已经有child,则需要检查一下child能不能复用,否则就直接调用inflateWidget构建一个新的Element
if (child != null) {
bool hasSameSuperclass = true;
// 如果之前的widget和现在的widget是同一个,则调用updateSlotForChild更新
if (hasSameSuperclass && child.widget == newWidget) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
newChild = child;
// 如果新旧的widget类型相同,也可以复用
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
// 关联组件
child.update(newWidget);
// ...
newChild = child;
} else {
deactivateChild(child);
assert(child._parent == null);
// 调用inflateWidget构建新的Element,详见2.4.5
newChild = inflateWidget(newWidget, newSlot);
}
} else {
// 调用inflateWidget构建新的Element,详见2.4.5
newChild = inflateWidget(newWidget, newSlot);
}
// ...
return newChild;
}
2.4.5 inflateWidget
通过Widget构建Element,先根据key查找是否有可以复用的Element
如果没有则调用对应Widget的createElement构建Element
Element inflateWidget(Widget newWidget, Object? newSlot) {
final bool isTimelineTracked = !kReleaseMode && _isProfileBuildsEnabledFor(newWidget);
// ...
try {
final Key? key = newWidget.key;
if (key is GlobalKey) {
// 尝试能否复用已经存在的Element
final Element? newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
// ...
try {
newChild._activateWithParent(this, newSlot);
} catch (_) {
// ...
}
// 继续调用子节点的updateChild
final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
assert(newChild == updatedChild);
return updatedChild!;
}
}
// 构建当前新建的Widget的Element,调用Widget.createElement
final Element newChild = newWidget.createElement();
// ...
// 挂载,即关联父节点
newChild.mount(this, newSlot);
return newChild;
} finally {
// ...
}
}
2.5 ensureVisualUpdate
到这里Element的树和RenderObject的树就构建好了,应该进行进一步的处理。
这里调用scheduleFrame是来注册下一个VSync的回调的。
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
// 详见2.6
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
2.6 scheduleFrame
配置了platformDispatcher.onBeginFrame和platformDispatcher.onDrawFrame,后面会调用。
调用platformDispatcher.scheduleFrame
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled) {
return;
}
// ...配置platformDispatcher.onBeginFrame和platformDispatcher.onDrawFrame
// 后面会调用到
ensureFrameCallbacksRegistered();
// 详见2.7
platformDispatcher.scheduleFrame();
_hasScheduledFrame = true;
}
2.7 platformDispatcher.scheduleFrame
scheduleFrame映射native层,调用到C++层。
void scheduleFrame() => _scheduleFrame();
// 详见2.8
@Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::ScheduleFrame')
external static void _scheduleFrame();
2.8 PlatformConfigurationNativeApi::ScheduleFrame
调用RuntimeController的ScheduleFrame
void PlatformConfigurationNativeApi::ScheduleFrame() {
UIDartState::ThrowIfUIOperationsProhibited();
// 详见2.9
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}
2.9 RuntimeController::ScheduleFrame
这里的client_是engine,调用ScheduleFrame
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
2.10 Engine::ScheduleFrame
调用Animator.RequestFrame
void Engine::ScheduleFrame(bool regenerate_layer_trees) {
// 详见2.11
animator_->RequestFrame(regenerate_layer_trees);
}
2.11 Animator::RequestFrame
调用了AwaitVSync
void Animator::RequestFrame(bool regenerate_layer_trees) {
// ...
task_runners_.GetUITaskRunner()->PostTask(
[self = weak_factory_.GetWeakPtr()]() {
if (!self) {
return;
}
// 调用AwaitVSync,详见2.12
self->AwaitVSync();
});
frame_scheduled_ = true;
}
2.12 Animator::AwaitVSync()
等待下一次的VSync,下一次VSync来之后回调这里的函数,里面主要是调用BeginFrame和EndFrame,我们先把这里看完再回过头去看LayerTree的构造。
void Animator::AwaitVSync() {
waiter_->AsyncWaitForVsync(
[self = weak_factory_.GetWeakPtr()](
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
if (self) {
// 复用之前的layerTree
if (self->CanReuseLastLayerTrees()) {
self->DrawLastLayerTrees(std::move(frame_timings_recorder));
} else {
// 这里是处理帧的具体逻辑,详见2.12。1
self->BeginFrame(std::move(frame_timings_recorder));
// 详见2.13
self->EndFrame();
}
}
});
if (has_rendered_) {
delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}
}
2.12.1 Animator::BeginFrame
layer_tree_pipeline_是一个Pipeline,而Produce会返回一个封装了ProducerCommit的对象,而ProducerCommit会将任务插入队列。
void Animator::BeginFrame(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
// ...trace相关
if (!producer_continuation_) {
// 构造producer_continuation_
// layer_tree_pipeline_是一个FramePipeline,实际就是一个Pipeline<FrameItem>
// Produce会封装Pipeline::ProducerCommit,ProducerCommit会将任务插入队列
producer_continuation_ = layer_tree_pipeline_->Produce();
if (!producer_continuation_) {
// 重新调用RequestFrame进入下一帧
TRACE_EVENT0("flutter", "PipelineFull");
RequestFrame();
return;
}
}
// ...
delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
}
2.13 Animator::EndFrame
layer_trees_tasks_是构建的LayerTree生成的,里面包含了业务渲染的各个图层,我们这里主要是要把里面的内容合成,LayerTree构建流程我们一会再来看。
这里会将layer_trees_tasks_里的LayerTreeTask封装成FrameItem,然后调用producer_continuation_.Complete
producer_continuation_.Complete会回调之前封装好的ProducerCommit,而ProducerCommit会将FrameItem放到队列中
然后会调用Shell::OnAnimatorDraw进一步处理任务。
void Animator::EndFrame() {
if (frame_timings_recorder_ == nullptr) {
return;
}
// layer_trees_tasks_记录了需要处理的LayerTreeTask
if (!layer_trees_tasks_.empty()) {
frame_timings_recorder_->RecordBuildEnd(fml::TimePoint::Now());
delegate_.OnAnimatorUpdateLatestFrameTargetTime(
frame_timings_recorder_->GetVsyncTargetTime());
// Commit the pending continuation.
std::vector<std::unique_ptr<LayerTreeTask>> layer_tree_task_list;
layer_tree_task_list.reserve(layer_trees_tasks_.size());
for (auto& [view_id, layer_tree_task] : layer_trees_tasks_) {
layer_tree_task_list.push_back(std::move(layer_tree_task));
}
layer_trees_tasks_.clear();
// 这里实际上会调用之前封装的ProducerCommit,将FrameItem放到任务队列中
PipelineProduceResult result = producer_continuation_.Complete(
std::make_unique<FrameItem>(std::move(layer_tree_task_list),
std::move(frame_timings_recorder_)));
if (!result.success) {
FML_DLOG(INFO) << "Failed to commit to the pipeline";
} else if (!result.is_first_item) {
// ...
} else {
// 详见2.14
delegate_.OnAnimatorDraw(layer_tree_pipeline_);
}
}
frame_timings_recorder_ = nullptr;
// ...
}
2.14 Shell::OnAnimatorDraw
调用了rasterizer draw,这里的FramePipeline就是之前的FrameItem队列
void Shell::OnAnimatorDraw(std::shared_ptr<FramePipeline> pipeline) {
FML_DCHECK(is_set_up_);
task_runners_.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
[&waiting_for_first_frame = waiting_for_first_frame_,
&waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
rasterizer = rasterizer_->GetWeakPtr(),
weak_pipeline = std::weak_ptr<FramePipeline>(pipeline)]() mutable {
if (rasterizer) {
std::shared_ptr<FramePipeline> pipeline = weak_pipeline.lock();
if (pipeline) {
// 详见2.15
rasterizer->Draw(pipeline);
}
// ...
}
}));
}
2.15 Rasterizer::Draw
通过pipeline->Consume调用DoDraw回调处理FrameItem
然后回调Java层FlutterView.onEndFrame
后面检查管道中是否还有其他任务,如果有继续调用Draw
DrawStatus Rasterizer::Draw(const std::shared_ptr<FramePipeline>& pipeline) {
// ...
DoDrawResult draw_result;
FramePipeline::Consumer consumer = [&draw_result,
this](std::unique_ptr<FrameItem> item) {
// 详见2.16
draw_result = DoDraw(std::move(item->frame_timings_recorder),
std::move(item->layer_tree_tasks));
};
PipelineConsumeResult consume_result = pipeline->Consume(consumer);
if (consume_result == PipelineConsumeResult::NoneAvailable) {
return DrawStatus::kPipelineEmpty;
}
// ...
// 回调Java层FlutterView.onEndFrame
if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) {
external_view_embedder_->SetUsedThisFrame(false);
external_view_embedder_->EndFrame(should_resubmit_frame,
raster_thread_merger_);
}
// ... 检查管道中是否还有任务,如果有继续执行Draw
return ToDrawStatus(draw_result.status);
}
2.16 Rasterizer::DoDraw
调用DrawToSurfaces
Rasterizer::DoDrawResult Rasterizer::DoDraw(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
// ...
// 调用DrawToSurfaces,详见2.17
DoDrawResult result =
DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
// ...
return result;
}
2.17 Rasterizer::DrawToSurfaces
调用DrawToSurfacesUnsafe
Rasterizer::DoDrawResult Rasterizer::DrawToSurfaces(
FrameTimingsRecorder& frame_timings_recorder,
std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
// ...
// 调用DrawToSurfacesUnsafe,详见2.18
if (surface_->AllowsDrawingWhenGpuDisabled()) {
result.resubmitted_item =
DrawToSurfacesUnsafe(frame_timings_recorder, std::move(tasks));
} else {
delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
fml::SyncSwitch::Handlers()
.SetIfTrue([&] {
result.status = DoDrawStatus::kGpuUnavailable;
frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
frame_timings_recorder.RecordRasterEnd();
})
.SetIfFalse([&] {
result.resubmitted_item = DrawToSurfacesUnsafe(
frame_timings_recorder, std::move(tasks));
}));
}
frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kRasterEnd);
return result;
}
2.18 Rasterizer::DrawToSurfacesUnsafe
遍历所有Tasks,针对每一个task调用DrawToSurfaceUnsafe
std::unique_ptr<FrameItem> Rasterizer::DrawToSurfacesUnsafe(
FrameTimingsRecorder& frame_timings_recorder,
std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
compositor_context_->ui_time().SetLapTime(
frame_timings_recorder.GetBuildDuration());
// ...
frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
// 遍历所有Task,依次调用DrawToSurfaceUnsafe执行
std::vector<std::unique_ptr<LayerTreeTask>> resubmitted_tasks;
for (std::unique_ptr<LayerTreeTask>& task : tasks) {
int64_t view_id = task->view_id;
// 获取task中的layer_tree
std::unique_ptr<LayerTree> layer_tree = std::move(task->layer_tree);
float device_pixel_ratio = task->device_pixel_ratio;
// 调用DrawToSurfaceUnsafe,详见2.19
DrawSurfaceStatus status = DrawToSurfaceUnsafe(
view_id, *layer_tree, device_pixel_ratio, presentation_time);
FML_DCHECK(status != DrawSurfaceStatus::kDiscarded);
auto& view_record = EnsureViewRecord(task->view_id);
view_record.last_draw_status = status;
if (status == DrawSurfaceStatus::kSuccess) {
view_record.last_successful_task = std::make_unique<LayerTreeTask>(
view_id, std::move(layer_tree), device_pixel_ratio);
} else if (status == DrawSurfaceStatus::kRetry) {
resubmitted_tasks.push_back(std::make_unique<LayerTreeTask>(
view_id, std::move(layer_tree), device_pixel_ratio));
}
}
// ...
}
2.19 Rasterizer::DrawToSurfaceUnsafe
这里的Frame和Canvas是将底层的渲染引擎抽象出来,上层使用的就是这里的接口,底层可能使用各种渲染引擎来实现,新版本的Flutter一般就是Impeller。
我们就不深入研究对渲染引擎封装了,这里就是通过他们将LayerTree中的图层进行渲染合成,然后调用commit提交结果,commit里面就是调用渲染引擎上屏的接口,例如swapBuffer之类的。
DrawSurfaceStatus Rasterizer::DrawToSurfaceUnsafe(
int64_t view_id,
flutter::LayerTree& layer_tree,
float device_pixel_ratio,
std::optional<fml::TimePoint> presentation_time) {
FML_DCHECK(surface_);
DlCanvas* embedder_root_canvas = nullptr;
if (external_view_embedder_) {
external_view_embedder_->PrepareFlutterView(layer_tree.frame_size(),
device_pixel_ratio);
// TODO(dkwingsmt): Add view ID here.
embedder_root_canvas = external_view_embedder_->GetRootCanvas();
}
// 这里会获取Native窗口,用于处理底层接口
auto frame = surface_->AcquireFrame(layer_tree.frame_size());
if (frame == nullptr) {
return DrawSurfaceStatus::kFailed;
}
SkMatrix root_surface_transformation =
embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation();
// 获取canvas,这里的canvas底层是通过渲染引擎实现绘制的
auto root_surface_canvas =
embedder_root_canvas ? embedder_root_canvas : frame->Canvas();
auto compositor_frame = compositor_context_->AcquireFrame(
surface_->GetContext(), // skia GrContext
root_surface_canvas, // root surface canvas
external_view_embedder_.get(), // external view embedder
root_surface_transformation, // root surface transformation
true, // instrumentation enabled
frame->framebuffer_info()
.supports_readback, // surface supports pixel reads
raster_thread_merger_, // thread merger
surface_->GetAiksContext().get() // aiks context
);
if (compositor_frame) {
// ...渲染范围计算
bool ignore_raster_cache = true;
if (surface_->EnableRasterCache()) {
ignore_raster_cache = false;
}
// 根据layer_tree进行合成,详见2.20
RasterStatus frame_status =
compositor_frame->Raster(layer_tree, // layer tree
ignore_raster_cache, // ignore raster cache
damage.get() // frame damage
);
if (frame_status == RasterStatus::kSkipAndRetry) {
return DrawSurfaceStatus::kRetry;
}
SurfaceFrame::SubmitInfo submit_info;
submit_info.presentation_time = presentation_time;
if (damage) {
submit_info.frame_damage = damage->GetFrameDamage();
submit_info.buffer_damage = damage->GetBufferDamage();
}
frame->set_submit_info(submit_info);
// 提交渲染结果,一般就是调用渲染引擎的接口SwapBuffer之类的
if (external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
FML_DCHECK(!frame->IsSubmitted());
external_view_embedder_->SubmitFlutterView(
view_id, surface_->GetContext(), surface_->GetAiksContext(),
std::move(frame));
} else {
frame->Submit();
}
// ...
if (frame_status == RasterStatus::kResubmit) {
return DrawSurfaceStatus::kRetry;
} else {
FML_CHECK(frame_status == RasterStatus::kSuccess);
return DrawSurfaceStatus::kSuccess;
}
}
return DrawSurfaceStatus::kFailed;
}
2.20 CompositorContext::ScopedFrame::Raster
调用PaintLayerTreeImpeller进行渲染
RasterStatus CompositorContext::ScopedFrame::Raster(
flutter::LayerTree& layer_tree,
bool ignore_raster_cache,
FrameDamage* frame_damage) {
// ...
// 根据不同的引擎渲染
if (aiks_context_) {
// 详见2.21
PaintLayerTreeImpeller(layer_tree, clip_rect, ignore_raster_cache);
} else {
PaintLayerTreeSkia(layer_tree, clip_rect, needs_save_layer,
ignore_raster_cache);
}
return RasterStatus::kSuccess;
}
2.21 CompositorContext::ScopedFrame::PaintLayerTreeImpeller
调用layerTree.Paint,对LayerTree进行渲染,调用Paint,而LayerTree会调用所有的Layer节点的Paint,Layer有不同的子类,而不同的子类中的Paint会通过CompositorContext调用渲染引擎来渲染合成
void CompositorContext::ScopedFrame::PaintLayerTreeImpeller(
flutter::LayerTree& layer_tree,
std::optional<SkRect> clip_rect,
bool ignore_raster_cache) {
if (canvas() && clip_rect) {
canvas()->Translate(-clip_rect->x(), -clip_rect->y());
}
// Layer有不同的子类,而不同的子类中的Paint会通过CompositorContext调用渲染引擎
layer_tree.Paint(*this, ignore_raster_cache);
}
到这里我们已经看了两部分逻辑,一部分是Widget->Element->RenderObject树构建,另一部分是下一个VSync信号回调使用LayerTree进行渲染合成的流程。
构建LayerTree
前面渲染流程中,我们提到渲染流程中,底层渲染是依赖于LayerTree来渲染,调用LayerTree每个Layer的Paint,我们这里紧接着2.1节来看一下scheduleWarmUpFrame,看一下LayerTree的构建流程
3.1 scheduleWarmUpFrame
最终会调用handleDrawFrame
void scheduleWarmUpFrame() {
// ...
final bool hadScheduledFrame = _hasScheduledFrame;
PlatformDispatcher.instance.scheduleWarmUpFrame(
beginFrame: () {
assert(_warmUpFrame);
handleBeginFrame(null);
},
drawFrame: () {
assert(_warmUpFrame);
// 最终会调用这里,详见3.2
handleDrawFrame();
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame) {
scheduleFrame();
}
},
);
// ...
}
3.2 handleDrawFrame
这里主要回调了FrameCallback,关于渲染的FrameCallback是在WidgetsFlutterBinding初始化的时候添加上的,我们看一下WidgetsFlutterBinding with的mixin之一RendererBinding
void handleDrawFrame() {
// ...
try {
// 这里调用了callback,这里的Callback是1.4构建WidgetsFlutterBinding时注册的
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in List<FrameCallback>.of(_persistentCallbacks)) {
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
}
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.of(_postFrameCallbacks);
_postFrameCallbacks.clear();
// ...
try {
for (final FrameCallback callback in localPostFrameCallbacks) {
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
}
} finally {
// ...
}
} finally {
// ...
}
}
3.2.1 RendererBinding.initInstances
这里通过addPersistentFrameCallback添加了回调_handlePersistentFrameCallback,3.1就会调用这里。
void initInstances() {
super.initInstances();
_instance = this;
_rootPipelineOwner = createRootPipelineOwner();
platformDispatcher
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged;
// 调用addPersistentFrameCallback注册_handlePersistentFrameCallback
// 而这里添加的PersistentFrameCallback就是上面3.2时会回调的
// _handlePersistentFrameCallback详见3.3
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
if (kIsWeb) {
addPostFrameCallback(_handleWebFirstFrame, debugLabel: 'RendererBinding.webFirstFrame');
}
rootPipelineOwner.attach(_manifold);
}
3.3 _handlePersistentFrameCallback
调用了drawFrame
void _handlePersistentFrameCallback(Duration timeStamp) {
// 详见3.4
drawFrame();
_scheduleMouseTrackerUpdate();
}
3.4 drawFrame
void drawFrame() {
// 详见3.5
rootPipelineOwner.flushLayout();
// 标记renderNode是否需要合成,
rootPipelineOwner.flushCompositingBits();
// 详见3.6
rootPipelineOwner.flushPaint();
if (sendFramesToEngine) {
for (final RenderView renderView in renderViews) {
// 详见3.10
renderView.compositeFrame(); // this sends the bits to the GPU
}
rootPipelineOwner.flushSemantics(); // this sends the semantics to the OS.
_firstFrameSent = true;
}
}
3.5 flushLayout
_nodesNeedingLayout是通过reassemble或者markNeedsLayout标记了需要重新布局的节点,这里会调用所有需要Layout的节点的_layoutWithoutResize方法
而_layoutWithoutResize会调用节点的performLayout,各个节点的子类会复写performLayout来实现各自的layout逻辑,这个和Android 自定义View onLayout有一些类似。
void flushLayout() {
// ... trace相关
try {
// 这里的_nodesNeedingLayout是通过reassemble或者markNeedsLayout标记了需要重新布局的节点
// 一般比如setState修改状态时就会标记
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = <RenderObject>[];
dirtyNodes.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
for (int i = 0; i < dirtyNodes.length; i++) {
if (_shouldMergeDirtyNodes) {
_shouldMergeDirtyNodes = false;
if (_nodesNeedingLayout.isNotEmpty) {
_nodesNeedingLayout.addAll(dirtyNodes.getRange(i, dirtyNodes.length));
break;
}
}
final RenderObject node = dirtyNodes[i];
if (node._needsLayout && node.owner == this) {
// 这里会调用节点的performLayout
node._layoutWithoutResize();
}
}
_shouldMergeDirtyNodes = false;
}
// ...递归调用子PipelineOwner的flushLayout
for (final PipelineOwner child in _children) {
child.flushLayout();
}
} finally {
// ...
}
}
3.6 flushPaint
这个方法流程和flushLayout很像,只是这里调用的是paint,而Layer的构建就是在paint中,在RenderObject的paint方法中通过PaintingContext来进行渲染,接下来我们举个例子。
void flushPaint() {
// trace相关
try {
// ...
final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
_nodesNeedingPaint = <RenderObject>[];
// Sort the dirty nodes in reverse order (deepest first).
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
assert(node._layerHandle.layer != null);
if ((node._needsPaint || node._needsCompositedLayerUpdate) && node.owner == this) {
if (node._layerHandle.layer!.attached) {
assert(node.isRepaintBoundary);
if (node._needsPaint) {
// 这里最终会调用每个RendorNode的paint,我们就不依次看了。
PaintingContext.repaintCompositedChild(node);
} else {
PaintingContext.updateLayerProperties(node);
}
} else {
node._skippedPaintingOnLayer();
}
}
}
for (final PipelineOwner child in _children) {
child.flushPaint();
}
assert(_nodesNeedingPaint.isEmpty, 'Child PipelineOwners must not dirty nodes in their parent.');
} finally {
// ...
}
}
3.7 RenderDots.paint
我们随便找了一个组件看的paint方法。
我们会从PaintingContext中拿到canvas,然后通过canvas的接口进行绘制。
void paint(PaintingContext context, Offset offset) {
// 从PaintingContext拿到canvas,然后直接调用canvas的接口开始绘制
// 我们来看一下这个canvas的构造,详见3.8
final Canvas canvas = context.canvas;
canvas.drawRect(offset & size, Paint()..color = const Color(0xFF0000FF));
final Paint paint = Paint()..color = const Color(0xFF00FF00);
for (final Offset point in _dots.values) {
canvas.drawCircle(point, 50.0, paint);
}
super.paint(context, offset);
}
3.8 PaintingContext.canvas
首次会通过_startRecording来初始化canvas
Canvas get canvas {
if (_canvas == null) {
// 详见3.9
_startRecording();
}
assert(_currentLayer != null);
return _canvas!;
}
3.9 _startRecording
这里构建了一个PictureLayer,我们之前提过layer有好多种,这里PictureLayer就是其中的一种,pictureLayer是可以提供绘制能力的。
这里调用createPictureRecorder构建了一个_recorder,然后使用这个_recorder构建Canvas,从这里的命名可以看出来,canvas就是把绘制指令记录下来,后面才会进行渲染。
最终将构建出来的Layer添加到_containerLayer构建LayerTree。
这个Layer在C++层后续也会构建一套一样的映射,这个一会就会看到。
void _startRecording() {
assert(!_isRecording);
_currentLayer = PictureLayer(estimatedBounds);
_recorder = RendererBinding.instance.createPictureRecorder();
_canvas = RendererBinding.instance.createCanvas(_recorder!);
_containerLayer.append(_currentLayer!);
}
3.10 RenderView.compositeFrame
我们回到3.4 drawFrame开始看renderView.compositeFrame
void compositeFrame() {
try {
// ...
// 构建SceneBuilder
final ui.SceneBuilder builder = RendererBinding.instance.createSceneBuilder();
// 调用buildScene,将layer信息封装到Scene中
final ui.Scene scene = layer!.buildScene(builder);
if (automaticSystemUiAdjustment) {
_updateSystemChrome();
}
// 调用render,详见3.11
_view.render(scene, size: configuration.toPhysicalSize(size));
scene.dispose();
// ...
} finally {
// ...
}
}
3.11 render
最终回调用到C++层PlatformConfigurationNativeApi::Render
void render(Scene scene, {Size? size}) {
_render(viewId, scene as _NativeScene, size?.width ?? physicalSize.width, size?.height ?? physicalSize.height);
}
@Native<Void Function(Int64, Pointer<Void>, Double, Double)>(symbol: 'PlatformConfigurationNativeApi::Render')
external static void _render(int viewId, _NativeScene scene, double width, double height);
3.12 PlatformConfigurationNativeApi::Render
这里的流程和之前ScheduleFrame类似,
void PlatformConfigurationNativeApi::Render(int64_t view_id,
Scene* scene,
double width,
double height) {
UIDartState::ThrowIfUIOperationsProhibited();
// 详见3.13
UIDartState::Current()->platform_configuration()->client()->Render(
view_id, scene, width, height);
}
3.13 RuntimeController::Render
这里把scene里面存储的LayerTree信息取出来,然后调用engine.Render
void RuntimeController::Render(int64_t view_id,
Scene* scene,
double width,
double height) {
const ViewportMetrics* view_metrics =
UIDartState::Current()->platform_configuration()->GetMetrics(view_id);
if (view_metrics == nullptr) {
return;
}
client_.Render(view_id, scene->takeLayerTree(width, height),
view_metrics->device_pixel_ratio);
rendered_views_during_frame_.insert(view_id);
CheckIfAllViewsRendered();
}
3.14 Engine::Render
调用animator Render。
void Engine::Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) {
if (!layer_tree) {
return;
}
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() || device_pixel_ratio <= 0.0f) {
return;
}
// 详见3.15
animator_->Render(view_id, std::move(layer_tree), device_pixel_ratio);
}
3.15 Animator::Render
这里会把要处理的LayerTree存到layer_trees_tasks_中,到这里任务就完成了,我们在2.13节的时候,就会从layer_trees_tasks_中取LayerTree封装成FrameItem进行渲染合成。
void Animator::Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) {
has_rendered_ = true;
// ... 将要处理的LayerTree存到layer_trees_tasks_
layer_trees_tasks_.try_emplace(
view_id, std::make_unique<LayerTreeTask>(view_id, std::move(layer_tree),
device_pixel_ratio));
}