@@ -62,6 +62,10 @@ void Animator::BeginFrame(
6262 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
6363 TRACE_EVENT_ASYNC_END0 (" flutter" , " Frame Request Pending" ,
6464 frame_request_number_);
65+ // Clear layer trees rendered out of a frame. Only Animator::Render called
66+ // within a frame is used.
67+ layer_trees_tasks_.clear ();
68+
6569 frame_request_number_++;
6670
6771 frame_timings_recorder_ = std::move (frame_timings_recorder);
@@ -112,6 +116,33 @@ void Animator::BeginFrame(
112116 dart_frame_deadline_ = frame_target_time.ToEpochDelta ();
113117 uint64_t frame_number = frame_timings_recorder_->GetFrameNumber ();
114118 delegate_.OnAnimatorBeginFrame (frame_target_time, frame_number);
119+ }
120+
121+ void Animator::EndFrame () {
122+ FML_DCHECK (frame_timings_recorder_ != nullptr );
123+ if (!layer_trees_tasks_.empty ()) {
124+ // The build is completed in OnAnimatorBeginFrame.
125+ frame_timings_recorder_->RecordBuildEnd (fml::TimePoint::Now ());
126+
127+ delegate_.OnAnimatorUpdateLatestFrameTargetTime (
128+ frame_timings_recorder_->GetVsyncTargetTime ());
129+
130+ // Commit the pending continuation.
131+ PipelineProduceResult result =
132+ producer_continuation_.Complete (std::make_unique<FrameItem>(
133+ std::move (layer_trees_tasks_), std::move (frame_timings_recorder_)));
134+
135+ if (!result.success ) {
136+ FML_DLOG (INFO) << " Failed to commit to the pipeline" ;
137+ } else if (!result.is_first_item ) {
138+ // Do nothing. It has been successfully pushed to the pipeline but not as
139+ // the first item. Eventually the 'Rasterizer' will consume it, so we
140+ // don't need to notify the delegate.
141+ } else {
142+ delegate_.OnAnimatorDraw (layer_tree_pipeline_);
143+ }
144+ }
145+ frame_timings_recorder_ = nullptr ;
115146
116147 if (!frame_scheduled_ && has_rendered_) {
117148 // Wait a tad more than 3 60hz frames before reporting a big idle period.
@@ -139,14 +170,18 @@ void Animator::BeginFrame(
139170 },
140171 kNotifyIdleTaskWaitTime );
141172 }
173+ FML_DCHECK (layer_trees_tasks_.empty ());
174+ FML_DCHECK (frame_timings_recorder_ == nullptr );
142175}
143176
144- void Animator::Render (std::unique_ptr<flutter::LayerTree> layer_tree,
177+ void Animator::Render (int64_t view_id,
178+ std::unique_ptr<flutter::LayerTree> layer_tree,
145179 float device_pixel_ratio) {
146180 has_rendered_ = true ;
147181
148182 if (!frame_timings_recorder_) {
149- // Framework can directly call render with a built scene.
183+ // Framework can directly call render with a built scene. A major reason is
184+ // to render warm up frames.
150185 frame_timings_recorder_ = std::make_unique<FrameTimingsRecorder>();
151186 const fml::TimePoint placeholder_time = fml::TimePoint::Now ();
152187 frame_timings_recorder_->RecordVsync (placeholder_time, placeholder_time);
@@ -156,35 +191,9 @@ void Animator::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
156191 TRACE_EVENT_WITH_FRAME_NUMBER (frame_timings_recorder_, " flutter" ,
157192 " Animator::Render" , /* flow_id_count=*/ 0 ,
158193 /* flow_ids=*/ nullptr );
159- frame_timings_recorder_->RecordBuildEnd (fml::TimePoint::Now ());
160-
161- delegate_.OnAnimatorUpdateLatestFrameTargetTime (
162- frame_timings_recorder_->GetVsyncTargetTime ());
163194
164- // TODO(dkwingsmt): Currently only supports a single window.
165- // See https://github.com/flutter/flutter/issues/135530, item 2.
166- int64_t view_id = kFlutterImplicitViewId ;
167- std::vector<std::unique_ptr<LayerTreeTask>> layer_trees_tasks;
168- layer_trees_tasks.push_back (std::make_unique<LayerTreeTask>(
195+ layer_trees_tasks_.push_back (std::make_unique<LayerTreeTask>(
169196 view_id, std::move (layer_tree), device_pixel_ratio));
170- // Commit the pending continuation.
171- PipelineProduceResult result =
172- producer_continuation_.Complete (std::make_unique<FrameItem>(
173- std::move (layer_trees_tasks), std::move (frame_timings_recorder_)));
174-
175- if (!result.success ) {
176- FML_DLOG (INFO) << " No pending continuation to commit" ;
177- return ;
178- }
179-
180- if (!result.is_first_item ) {
181- // It has been successfully pushed to the pipeline but not as the first
182- // item. Eventually the 'Rasterizer' will consume it, so we don't need to
183- // notify the delegate.
184- return ;
185- }
186-
187- delegate_.OnAnimatorDraw (layer_tree_pipeline_);
188197}
189198
190199const std::weak_ptr<VsyncWaiter> Animator::GetVsyncWaiter () const {
@@ -256,6 +265,7 @@ void Animator::AwaitVSync() {
256265 self->DrawLastLayerTrees (std::move (frame_timings_recorder));
257266 } else {
258267 self->BeginFrame (std::move (frame_timings_recorder));
268+ self->EndFrame ();
259269 }
260270 }
261271 });
@@ -265,9 +275,9 @@ void Animator::AwaitVSync() {
265275}
266276
267277void Animator::EndWarmUpFrame () {
268- // Do nothing. The warm up frame does not need any additional work to end the
269- // frame for now. This will change once the pipeline supports multi-view.
270- // https://github.com/flutter/flutter/issues/142851
278+ if (!layer_trees_tasks_. empty ()) {
279+ EndFrame ();
280+ }
271281}
272282
273283void Animator::ScheduleSecondaryVsyncCallback (uintptr_t id,
0 commit comments