Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "components/viz/client/frame_eviction_manager.h" |
| 6 | |
Peter Kasting | ccea0983 | 2025-01-27 18:38:22 | [diff] [blame] | 7 | #include <algorithm> |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 8 | #include <vector> |
| 9 | |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 10 | #include "base/memory/memory_pressure_listener.h" |
Ho Cheung | c4c27d8d | 2023-05-24 14:12:39 | [diff] [blame] | 11 | #include "base/memory/raw_ptr.h" |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 12 | #include "base/test/test_mock_time_task_runner.h" |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 13 | #include "testing/gtest/include/gtest/gtest.h" |
| 14 | |
| 15 | namespace viz { |
| 16 | |
| 17 | namespace { |
| 18 | |
| 19 | class TestFrameEvictionManagerClient : public FrameEvictionManagerClient { |
| 20 | public: |
| 21 | TestFrameEvictionManagerClient() = default; |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 22 | explicit TestFrameEvictionManagerClient(FrameEvictionManager* manager) |
| 23 | : manager_(manager) {} |
Peter Boström | 09c0182 | 2021-09-20 22:43:27 | [diff] [blame] | 24 | |
| 25 | TestFrameEvictionManagerClient(const TestFrameEvictionManagerClient&) = |
| 26 | delete; |
| 27 | TestFrameEvictionManagerClient& operator=( |
| 28 | const TestFrameEvictionManagerClient&) = delete; |
| 29 | |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 30 | ~TestFrameEvictionManagerClient() override { |
| 31 | if (has_frame_) |
| 32 | manager_->RemoveFrame(this); |
| 33 | } |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 34 | |
| 35 | // FrameEvictionManagerClient: |
| 36 | void EvictCurrentFrame() override { |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 37 | manager_->RemoveFrame(this); |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 38 | has_frame_ = false; |
| 39 | } |
| 40 | |
| 41 | bool has_frame() const { return has_frame_; } |
| 42 | |
| 43 | private: |
Ho Cheung | c4c27d8d | 2023-05-24 14:12:39 | [diff] [blame] | 44 | raw_ptr<FrameEvictionManager> manager_ = FrameEvictionManager::GetInstance(); |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 45 | bool has_frame_ = true; |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 46 | }; |
| 47 | |
| 48 | } // namespace |
| 49 | |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 50 | class FrameEvictionManagerTest : public testing::Test {}; |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 51 | |
| 52 | TEST_F(FrameEvictionManagerTest, ScopedPause) { |
| 53 | constexpr int kMaxSavedFrames = 1; |
| 54 | constexpr int kFrames = 2; |
| 55 | |
| 56 | FrameEvictionManager* manager = FrameEvictionManager::GetInstance(); |
| 57 | manager->set_max_number_of_saved_frames(kMaxSavedFrames); |
| 58 | |
| 59 | std::vector<TestFrameEvictionManagerClient> frames(kFrames); |
| 60 | { |
| 61 | FrameEvictionManager::ScopedPause scoped_pause; |
| 62 | |
| 63 | for (auto& frame : frames) |
| 64 | manager->AddFrame(&frame, /*locked=*/false); |
| 65 | |
| 66 | // All frames stays because |scoped_pause| holds off frame eviction. |
Peter Kasting | ccea0983 | 2025-01-27 18:38:22 | [diff] [blame] | 67 | EXPECT_EQ(kFrames, std::ranges::count_if( |
Peter Kasting | c6c2d0a | 2022-10-19 08:45:35 | [diff] [blame] | 68 | frames, &TestFrameEvictionManagerClient::has_frame)); |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | // Frame eviction happens when |scoped_pause| goes out of scope. |
| 72 | EXPECT_EQ(kMaxSavedFrames, |
Peter Kasting | ccea0983 | 2025-01-27 18:38:22 | [diff] [blame] | 73 | std::ranges::count_if(frames, |
| 74 | &TestFrameEvictionManagerClient::has_frame)); |
Xiyuan Xia | d7e4d94 | 2019-06-12 22:32:52 | [diff] [blame] | 75 | } |
| 76 | |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 77 | TEST_F(FrameEvictionManagerTest, PeriodicCulling) { |
Benoit Lize | 6325f04 | 2022-09-12 10:11:35 | [diff] [blame] | 78 | // Cannot use a TaskEnvironment as there is already one which is not using |
| 79 | // MOCK_TIME. |
| 80 | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); |
| 81 | FrameEvictionManager manager; |
| 82 | manager.set_max_number_of_saved_frames(5); |
| 83 | manager.SetOverridesForTesting(task_runner, task_runner->GetMockTickClock()); |
| 84 | |
| 85 | TestFrameEvictionManagerClient frame1{&manager}, frame2{&manager}, |
| 86 | frame3{&manager}; |
| 87 | manager.AddFrame(&frame1, false); |
| 88 | task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay / 10); |
| 89 | manager.AddFrame(&frame2, true); |
| 90 | manager.AddFrame(&frame3, false); |
| 91 | |
| 92 | task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay); |
| 93 | EXPECT_FALSE(frame1.has_frame()); |
| 94 | EXPECT_TRUE(frame2.has_frame()); |
| 95 | EXPECT_TRUE(frame3.has_frame()); // Too early for this one. |
| 96 | task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay); |
| 97 | EXPECT_FALSE(frame3.has_frame()); |
| 98 | |
| 99 | task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay / 2); |
| 100 | manager.UnlockFrame(&frame2); |
| 101 | EXPECT_TRUE(frame2.has_frame()); |
| 102 | |
| 103 | // Pause prevents eviction, but not rescheduling the task. Not using |
| 104 | // ScopedPause because it impacts the singleton. |
| 105 | manager.Pause(); |
|
|