#include "ash/wm/overview/overview_ui_task_pool.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
namespace ash {
namespace {
constexpr base::TimeDelta kMinTimeRequiredPerTask = base::Milliseconds(4);
constexpr base::TimeDelta kExpectedBeginFramePropagationDelay =
base::Milliseconds(1);
}
OverviewUiTaskPool::OverviewUiTaskPool(ui::Compositor* compositor,
base::TimeDelta initial_blackout_period)
: compositor_(compositor),
initial_blackout_period_(initial_blackout_period),
construction_time_(base::TimeTicks::Now()) {
CHECK(compositor_);
compositor_observation_.Observe(compositor_);
}
OverviewUiTaskPool::~OverviewUiTaskPool() {
StopObservingBeginFrames();
}
void OverviewUiTaskPool::AddTask(base::OnceClosure task) {
pending_tasks_.push_back(std::move(task));
StartObservingBeginFrames();
}
void OverviewUiTaskPool::Flush() {
CancelScheduledTask();
while (!pending_tasks_.empty()) {
RunNextTask(true);
}
}
void OverviewUiTaskPool::OnBeginFrame(
base::TimeTicks frame_begin_time,
base::TimeDelta frame_interval,
std::optional<base::TimeTicks> first_coalesced_frame_begin_time) {
if (base::TimeTicks::Now() - construction_time_ <= initial_blackout_period_) {
return;
}
CancelScheduledTask();
next_expected_begin_frame_time_ = frame_begin_time + frame_interval;
}
void OverviewUiTaskPool::OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) {
if (!IsCurrentCompositorFrameATaskCandidate()) {
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&OverviewUiTaskPool::RunNextTask,
weak_ptr_factory_.GetWeakPtr(),
false));
}
void OverviewUiTaskPool::OnCompositingShuttingDown(ui::Compositor* compositor) {
compositor_observation_.Reset();
StopObservingBeginFrames();
compositor_ = nullptr;
CancelScheduledTask();
}
void OverviewUiTaskPool::RunNextTask(bool force_task_to_run) {
if (pending_tasks_.empty()) {
return;
}
if (!force_task_to_run) {
const base::TimeDelta time_available_for_task_to_run =
(next_expected_begin_frame_time_ - base::TimeTicks::Now()) +
kExpectedBeginFramePropagationDelay;
DVLOG(4) << __func__ << " time_available_for_task_to_run="
<< time_available_for_task_to_run;
if (time_available_for_task_to_run < kMinTimeRequiredPerTask) {
return;
}
}
auto next_task = std::move(pending_tasks_.front());
pending_tasks_.pop_front();
if (pending_tasks_.empty()) {
StopObservingBeginFrames();
}
std::move(next_task).Run();
}
void OverviewUiTaskPool::StartObservingBeginFrames() {
if (is_observing_begin_frames_ || HasCompositingShutDown()) {
return;
}
compositor_->AddSimpleBeginFrameObserver(this);
is_observing_begin_frames_ = true;
}
void OverviewUiTaskPool::StopObservingBeginFrames() {
if (!is_observing_begin_frames_) {
return;
}
CHECK(!HasCompositingShutDown());
compositor_->RemoveSimpleBeginFrameObserver(this);
is_observing_begin_frames_ = false;
}
bool OverviewUiTaskPool::HasCompositingShutDown() const {
return !compositor_;
}
void OverviewUiTaskPool::CancelScheduledTask() {
weak_ptr_factory_.InvalidateWeakPtrs();
}
bool OverviewUiTaskPool::IsCurrentCompositorFrameATaskCandidate() const {
return !next_expected_begin_frame_time_.is_null();
}
}