From 9e35937b935354f3ae833bede071f0804e8a230c Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 28 Jan 2020 20:13:29 -0800 Subject: [PATCH] Prevent GPU thread from trying to rasterizer more than one layer tree per vsync frame --- flow/layers/layer_tree.cc | 3 ++- flow/layers/layer_tree.h | 4 +++- fml/message_loop_impl.cc | 1 - shell/common/animator.cc | 4 +++- shell/common/animator.h | 1 + shell/common/pipeline.h | 17 ++++++++++++++--- shell/common/rasterizer.cc | 29 ++++++++++++++++++++++++++--- shell/common/rasterizer.h | 4 ++++ 8 files changed, 53 insertions(+), 10 deletions(-) diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index dd9e6b4f02b01..df7164b7efb2f 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -21,8 +21,9 @@ LayerTree::LayerTree(const SkISize& frame_size, checkerboard_raster_cache_images_(false), checkerboard_offscreen_layers_(false) {} -void LayerTree::RecordBuildTime(fml::TimePoint start) { +void LayerTree::RecordBuildTime(fml::TimePoint start, fml::TimePoint target) { build_start_ = start; + build_target_ = target; build_finish_ = fml::TimePoint::Now(); } diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 21ba509f09ae6..32569ac8a0ddb 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -53,8 +53,9 @@ class LayerTree { float frame_physical_depth() const { return frame_physical_depth_; } float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; } - void RecordBuildTime(fml::TimePoint begin_start); + void RecordBuildTime(fml::TimePoint begin_start, fml::TimePoint begin_target); fml::TimePoint build_start() const { return build_start_; } + fml::TimePoint build_target() const { return build_target_; } fml::TimePoint build_finish() const { return build_finish_; } fml::TimeDelta build_time() const { return build_finish_ - build_start_; } @@ -82,6 +83,7 @@ class LayerTree { private: std::shared_ptr root_layer_; fml::TimePoint build_start_; + fml::TimePoint build_target_; fml::TimePoint build_finish_; SkISize frame_size_ = SkISize::MakeEmpty(); // Physical pixels. float frame_physical_depth_; diff --git a/fml/message_loop_impl.cc b/fml/message_loop_impl.cc index d4c9331e35990..ad93b7e10953c 100644 --- a/fml/message_loop_impl.cc +++ b/fml/message_loop_impl.cc @@ -57,7 +57,6 @@ MessageLoopImpl::~MessageLoopImpl() { void MessageLoopImpl::PostTask(const fml::closure& task, fml::TimePoint target_time) { FML_DCHECK(task != nullptr); - FML_DCHECK(task != nullptr); if (terminated_) { // If the message loop has already been terminated, PostTask should destruct // |task| synchronously within this function. diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 5ae3862a93ad1..889a8a532df52 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -26,6 +26,7 @@ Animator::Animator(Delegate& delegate, task_runners_(std::move(task_runners)), waiter_(std::move(waiter)), last_begin_frame_time_(), + last_begin_target_time_(), dart_frame_deadline_(0), #if FLUTTER_SHELL_ENABLE_METAL layer_tree_pipeline_(fml::MakeRefCounted(2)), @@ -133,6 +134,7 @@ void Animator::BeginFrame(fml::TimePoint frame_start_time, FML_DCHECK(producer_continuation_); last_begin_frame_time_ = frame_start_time; + last_begin_target_time_ = frame_target_time; dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time); { TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame", @@ -178,7 +180,7 @@ void Animator::Render(std::unique_ptr layer_tree) { if (layer_tree) { // Note the frame time for instrumentation. - layer_tree->RecordBuildTime(last_begin_frame_time_); + layer_tree->RecordBuildTime(last_begin_frame_time_, last_begin_target_time_); } // Commit the pending continuation. diff --git a/shell/common/animator.h b/shell/common/animator.h index 0bb15bed72a54..890671af98b5d 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -97,6 +97,7 @@ class Animator final { std::shared_ptr waiter_; fml::TimePoint last_begin_frame_time_; + fml::TimePoint last_begin_target_time_; int64_t dart_frame_deadline_; fml::RefPtr layer_tree_pipeline_; fml::Semaphore pending_frame_semaphore_; diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index 2bf3b19c4b06f..f5cdf196bc61e 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -144,6 +144,9 @@ class Pipeline : public fml::RefCountedThreadSafe> { { std::scoped_lock lock(queue_mutex_); + if (queue_.size() == 0) { + return PipelineConsumeResult::NoneAvailable; + } std::tie(resource, trace_id) = std::move(queue_.front()); queue_.pop_front(); items_count = queue_.size(); @@ -175,6 +178,10 @@ class Pipeline : public fml::RefCountedThreadSafe> { void ProducerCommit(ResourcePtr resource, size_t trace_id) { { std::scoped_lock lock(queue_mutex_); + if (queue_.size() > 0) { + FML_LOG(INFO) << "queue was already stocked"; + queue_.clear(); + } queue_.emplace_back(std::move(resource), trace_id); } @@ -185,9 +192,13 @@ class Pipeline : public fml::RefCountedThreadSafe> { void ProducerCommitFront(ResourcePtr resource, size_t trace_id) { { std::scoped_lock lock(queue_mutex_); - queue_.emplace_front(std::move(resource), trace_id); - while (queue_.size() > depth_) { - queue_.pop_back(); + if (queue_.size() > 0) { + FML_LOG(INFO) << "ignoring CommitFront in favor of existing queue entry"; + } else { + queue_.emplace_front(std::move(resource), trace_id); + while (queue_.size() > depth_) { + queue_.pop_back(); + } } } diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 7d6a7a74e8a91..a017957a05030 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -138,12 +138,12 @@ void Rasterizer::Draw(fml::RefPtr> pipeline) { // between successive tries. switch (consume_result) { case PipelineConsumeResult::MoreAvailable: { - task_runners_.GetGPUTaskRunner()->PostTask( + task_runners_.GetGPUTaskRunner()->PostTaskForTime( [weak_this = weak_factory_.GetWeakPtr(), pipeline]() { if (weak_this) { weak_this->Draw(pipeline); } - }); + }, resubmitted_time_target_); break; } default: @@ -231,6 +231,19 @@ sk_sp Rasterizer::ConvertToRasterImage(sk_sp image) { }); } +fml::TimePoint Rasterizer::DetermineRasterizationTime(LayerTree& layer_tree) { + fml::TimePoint start = layer_tree.build_start(); + if (start < last_render_finish_) { + fml::TimePoint target = layer_tree.build_target(); + fml::TimePoint now = fml::TimePoint::Now(); + if (target > now) { + return target; + } + return now + (target - start); + } + return start; +} + RasterStatus Rasterizer::DoDraw( std::unique_ptr layer_tree) { FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()); @@ -239,6 +252,14 @@ RasterStatus Rasterizer::DoDraw( return RasterStatus::kFailed; } + fml::TimePoint when = DetermineRasterizationTime(*layer_tree); + if (when > layer_tree->build_start()) { + FML_LOG(INFO) << "Rescheduling"; + resubmitted_layer_tree_ = std::move(layer_tree); + resubmitted_time_target_ = when; + return RasterStatus::kResubmit; + } + FrameTiming timing; timing.Set(FrameTiming::kBuildStart, layer_tree->build_start()); timing.Set(FrameTiming::kBuildFinish, layer_tree->build_finish()); @@ -252,6 +273,7 @@ RasterStatus Rasterizer::DoDraw( last_layer_tree_ = std::move(layer_tree); } else if (raster_status == RasterStatus::kResubmit) { resubmitted_layer_tree_ = std::move(layer_tree); + resubmitted_time_target_ = fml::TimePoint::Now(); return raster_status; } @@ -265,7 +287,8 @@ RasterStatus Rasterizer::DoDraw( // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks. - timing.Set(FrameTiming::kRasterFinish, fml::TimePoint::Now()); + last_render_finish_ = fml::TimePoint::Now(); + timing.Set(FrameTiming::kRasterFinish, last_render_finish_); delegate_.OnFrameRasterized(timing); // Pipeline pressure is applied from a couple of places: diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index d2242648d522b..eee593e832aeb 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -412,10 +412,12 @@ class Rasterizer final : public SnapshotDelegate { std::unique_ptr compositor_context_; // This is the last successfully rasterized layer tree. std::unique_ptr last_layer_tree_; + fml::TimePoint last_render_finish_; // Set when we need attempt to rasterize the layer tree again. This layer_tree // has not successfully rasterized. This can happen due to the change in the // thread configuration. This will be inserted to the front of the pipeline. std::unique_ptr resubmitted_layer_tree_; + fml::TimePoint resubmitted_time_target_; fml::closure next_frame_callback_; bool user_override_resource_cache_bytes_; std::optional max_cache_bytes_; @@ -433,6 +435,8 @@ class Rasterizer final : public SnapshotDelegate { SkISize size, std::function draw_callback); + fml::TimePoint DetermineRasterizationTime(LayerTree& layer_tree); + RasterStatus DoDraw(std::unique_ptr layer_tree); RasterStatus DrawToSurface(flutter::LayerTree& layer_tree);