Flutter UI构建渲染(4)

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));
}
相关推荐
Python图像识别-15 小时前
基于yolov8、yolov5的番茄成熟度检测识别系统(含UI界面、训练好的模型、Python代码、数据集)
python·yolo·ui
Xam_d_LM6 小时前
【Qt】在 Qt Creator 中使用图片资源方法(含素材网站推荐)
开发语言·c++·qt·ui·贴图·qt5
顾北川_野6 小时前
Android 进入浏览器下载应用,下载的是bin文件无法安装,应为apk文件
android
CYRUS STUDIO6 小时前
Android 下内联汇编,Android Studio 汇编开发
android·汇编·arm开发·android studio·arm
右手吉他6 小时前
Android ANR分析总结
android
jhonjson8 小时前
Flutter开发之flutter_local_notifications
flutter·macos·cocoa
PenguinLetsGo8 小时前
关于 Android15 GKI2407R40 导致梆梆加固软件崩溃
android·linux
iFlyCai9 小时前
23种设计模式的Flutter实现第一篇创建型模式(一)
flutter·设计模式·dart
恋猫de小郭10 小时前
Flutter 小技巧之 OverlayPortal 实现自限性和可共享的页面图层
flutter
杨武博10 小时前
音频格式转换
android·音视频