| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/test/animation_metrics_test_util.h" |
| |
| #include <memory> |
| |
| #include "ash/shell.h" |
| #include "base/functional/bind.h" |
| #include "base/run_loop.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/time/time.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/compositor/compositor.h" |
| #include "ui/compositor/compositor_animation_observer.h" |
| #include "ui/compositor/test/begin_main_frame_waiter.h" |
| #include "ui/compositor/test/draw_waiter_for_test.h" |
| |
| namespace ash::test { |
| namespace { |
| void GiveItSomeTime(base::TimeDelta delta) { |
| // Due to the |frames_to_terminate_tracker|=3 constant in |
| // FrameSequenceTracker::ReportSubmitFrame we need to continue generating |
| // frames to receive feedback. |
| base::RepeatingTimer begin_main_frame_scheduler( |
| FROM_HERE, base::Milliseconds(16), base::BindRepeating([]() { |
| auto* compositor = |
| Shell::GetPrimaryRootWindow()->GetHost()->compositor(); |
| compositor->ScheduleFullRedraw(); |
| })); |
| begin_main_frame_scheduler.Reset(); |
| |
| base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); |
| auto* compositor = Shell::GetPrimaryRootWindow()->GetHost()->compositor(); |
| compositor->ScheduleFullRedraw(); |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, run_loop.QuitClosure(), delta); |
| run_loop.Run(); |
| } |
| } // namespace |
| |
| TestAnimationObserver::TestAnimationObserver(ui::Compositor* compositor) |
| : compositor_(compositor) { |
| compositor_->AddAnimationObserver(this); |
| } |
| |
| TestAnimationObserver::~TestAnimationObserver() = default; |
| |
| void TestAnimationObserver::OnAnimationStep(base::TimeTicks timestamp) { |
| ++count_; |
| if (count_ < 3) { |
| compositor_->ScheduleFullRedraw(); |
| } else { |
| compositor_->RemoveAnimationObserver(this); |
| } |
| } |
| |
| void TestAnimationObserver::OnCompositingShuttingDown( |
| ui::Compositor* compositor) {} |
| |
| FirstNonAnimatedFrameStartedWaiter::FirstNonAnimatedFrameStartedWaiter( |
| ui::Compositor* compositor) |
| : compositor_(compositor) { |
| compositor->AddObserver(this); |
| } |
| |
| FirstNonAnimatedFrameStartedWaiter::~FirstNonAnimatedFrameStartedWaiter() { |
| compositor_->RemoveObserver(this); |
| } |
| |
| void FirstNonAnimatedFrameStartedWaiter::OnFirstNonAnimatedFrameStarted( |
| ui::Compositor* compositor) { |
| DCHECK_EQ(compositor_, compositor); |
| done_ = true; |
| if (run_loop_) { |
| run_loop_->Quit(); |
| } |
| } |
| |
| void FirstNonAnimatedFrameStartedWaiter::Wait() { |
| if (done_) { |
| return; |
| } |
| |
| run_loop_ = std::make_unique<base::RunLoop>( |
| base::RunLoop::Type::kNestableTasksAllowed); |
| run_loop_->Run(); |
| run_loop_.reset(); |
| } |
| |
| MetricsWaiter::MetricsWaiter(base::HistogramTester* histogram_tester, |
| std::string metrics_name) |
| : histogram_tester_(histogram_tester), metrics_name_(metrics_name) {} |
| |
| MetricsWaiter::~MetricsWaiter() = default; |
| |
| void MetricsWaiter::Wait() { |
| while (histogram_tester_->GetAllSamples(metrics_name_).empty()) { |
| GiveItSomeTime(base::Milliseconds(16)); |
| } |
| } |
| |
| void RunSimpleAnimation() { |
| ui::Compositor* compositor = |
| Shell::GetPrimaryRootWindow()->GetHost()->compositor(); |
| TestAnimationObserver observer(compositor); |
| ui::BeginMainFrameWaiter(compositor).Wait(); |
| FirstNonAnimatedFrameStartedWaiter(compositor).Wait(); |
| ui::DrawWaiterForTest::WaitForCompositingEnded(compositor); |
| } |
| |
| } // namespace ash::test |