@@ -62,6 +62,10 @@ void Animator::BeginFrame(
62
62
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
63
63
TRACE_EVENT_ASYNC_END0 (" flutter" , " Frame Request Pending" ,
64
64
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
+
65
69
frame_request_number_++;
66
70
67
71
frame_timings_recorder_ = std::move (frame_timings_recorder);
@@ -112,6 +116,33 @@ void Animator::BeginFrame(
112
116
dart_frame_deadline_ = frame_target_time.ToEpochDelta ();
113
117
uint64_t frame_number = frame_timings_recorder_->GetFrameNumber ();
114
118
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 ;
115
146
116
147
if (!frame_scheduled_ && has_rendered_) {
117
148
// Wait a tad more than 3 60hz frames before reporting a big idle period.
@@ -139,14 +170,18 @@ void Animator::BeginFrame(
139
170
},
140
171
kNotifyIdleTaskWaitTime );
141
172
}
173
+ FML_DCHECK (layer_trees_tasks_.empty ());
174
+ FML_DCHECK (frame_timings_recorder_ == nullptr );
142
175
}
143
176
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,
145
179
float device_pixel_ratio) {
146
180
has_rendered_ = true ;
147
181
148
182
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.
150
185
frame_timings_recorder_ = std::make_unique<FrameTimingsRecorder>();
151
186
const fml::TimePoint placeholder_time = fml::TimePoint::Now ();
152
187
frame_timings_recorder_->RecordVsync (placeholder_time, placeholder_time);
@@ -156,35 +191,9 @@ void Animator::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
156
191
TRACE_EVENT_WITH_FRAME_NUMBER (frame_timings_recorder_, " flutter" ,
157
192
" Animator::Render" , /* flow_id_count=*/ 0 ,
158
193
/* flow_ids=*/ nullptr );
159
- frame_timings_recorder_->RecordBuildEnd (fml::TimePoint::Now ());
160
-
161
- delegate_.OnAnimatorUpdateLatestFrameTargetTime (
162
- frame_timings_recorder_->GetVsyncTargetTime ());
163
194
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>(
169
196
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_);
188
197
}
189
198
190
199
const std::weak_ptr<VsyncWaiter> Animator::GetVsyncWaiter () const {
@@ -256,6 +265,7 @@ void Animator::AwaitVSync() {
256
265
self->DrawLastLayerTrees (std::move (frame_timings_recorder));
257
266
} else {
258
267
self->BeginFrame (std::move (frame_timings_recorder));
268
+ self->EndFrame ();
259
269
}
260
270
}
261
271
});
@@ -265,9 +275,9 @@ void Animator::AwaitVSync() {
265
275
}
266
276
267
277
void 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
+ }
271
281
}
272
282
273
283
void Animator::ScheduleSecondaryVsyncCallback (uintptr_t id,
0 commit comments