After
I will firstly present the modified animator logic here. In the next sections, I will then discuss why these are necessary and what problems it solves.
Code
The changes are marked as // CHANGE: ... below.
Animator::Animator()
    : layer_tree_pipeline_(std::make_shared<LayerTreePipeline>(2)) {}
void Animator::BeginFrame() {
  if (!producer_continuation_) {
    producer_continuation_ = layer_tree_pipeline_->Produce();
    if (!producer_continuation_) {
      TRACE_EVENT0("flutter", "PipelineFull");
      // CHANGE: do not return even if pipeline full
      // RequestFrame(); return;
    }
  }
  
  // CHANGE: remove this (since we do not early return if pipeline full)
  // FML_DCHECK(producer_continuation_);
  delegate_.OnAnimatorBeginFrame();
}
void Animator::Render(std::shared_ptr<flutter::LayerTree> layer_tree) {
  // CHANGE: add these several lines (if no continuation, trigger creating one if possible)
  if (!producer_continuation_) {
    producer_continuation_ = layer_tree_pipeline_->Produce();
  }
  
  // Commit the pending continuation.
  PipelineProduceResult result = producer_continuation_.Complete(layer_tree);
  if (!result.success) {
    FML_DLOG(INFO) << "No pending continuation to commit";
    return;
  }
  ... notify rasterizer ...
}
Summary
To summarize, there are two changes:
- When 
Render, originally we early-return if there is no occupied seat (the continuation). However, we now produce one. (Notice theProducemay fail if there is really no room in pipeline.) - When 
BeginFrame, originally we early-return as long as the pipeline is full at that time. However, we are more optimistic and continue computing a frame even if it is full now.