blob: 3187c8290471c25666ca467cdb728801c86e77a7 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2019 The Chromium Authors
Xiyuan Xiad7e4d942019-06-12 22:32:522// 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
7#include <algorithm>
8#include <vector>
9
Benoit Lize6325f042022-09-12 10:11:3510#include "base/memory/memory_pressure_listener.h"
11#include "base/test/scoped_feature_list.h"
12#include "base/test/test_mock_time_task_runner.h"
13#include "components/viz/common/features.h"
Xiyuan Xiad7e4d942019-06-12 22:32:5214#include "testing/gtest/include/gtest/gtest.h"
15
16namespace viz {
17
18namespace {
19
20class TestFrameEvictionManagerClient : public FrameEvictionManagerClient {
21 public:
22 TestFrameEvictionManagerClient() = default;
Benoit Lize6325f042022-09-12 10:11:3523 explicit TestFrameEvictionManagerClient(FrameEvictionManager* manager)
24 : manager_(manager) {}
Peter Boström09c01822021-09-20 22:43:2725
26 TestFrameEvictionManagerClient(const TestFrameEvictionManagerClient&) =
27 delete;
28 TestFrameEvictionManagerClient& operator=(
29 const TestFrameEvictionManagerClient&) = delete;
30
Benoit Lize6325f042022-09-12 10:11:3531 ~TestFrameEvictionManagerClient() override {
32 if (has_frame_)
33 manager_->RemoveFrame(this);
34 }
Xiyuan Xiad7e4d942019-06-12 22:32:5235
36 // FrameEvictionManagerClient:
37 void EvictCurrentFrame() override {
Benoit Lize6325f042022-09-12 10:11:3538 manager_->RemoveFrame(this);
Xiyuan Xiad7e4d942019-06-12 22:32:5239 has_frame_ = false;
40 }
41
42 bool has_frame() const { return has_frame_; }
43
44 private:
Benoit Lize6325f042022-09-12 10:11:3545 FrameEvictionManager* manager_ = FrameEvictionManager::GetInstance();
Xiyuan Xiad7e4d942019-06-12 22:32:5246 bool has_frame_ = true;
Xiyuan Xiad7e4d942019-06-12 22:32:5247};
48
49} // namespace
50
Benoit Lize6325f042022-09-12 10:11:3551class FrameEvictionManagerTest : public testing::Test {};
Xiyuan Xiad7e4d942019-06-12 22:32:5252
53TEST_F(FrameEvictionManagerTest, ScopedPause) {
54 constexpr int kMaxSavedFrames = 1;
55 constexpr int kFrames = 2;
56
57 FrameEvictionManager* manager = FrameEvictionManager::GetInstance();
58 manager->set_max_number_of_saved_frames(kMaxSavedFrames);
59
60 std::vector<TestFrameEvictionManagerClient> frames(kFrames);
61 {
62 FrameEvictionManager::ScopedPause scoped_pause;
63
64 for (auto& frame : frames)
65 manager->AddFrame(&frame, /*locked=*/false);
66
67 // All frames stays because |scoped_pause| holds off frame eviction.
68 EXPECT_EQ(kFrames,
69 std::count_if(frames.begin(), frames.end(),
70 [](const TestFrameEvictionManagerClient& frame) {
71 return frame.has_frame();
72 }));
73 }
74
75 // Frame eviction happens when |scoped_pause| goes out of scope.
76 EXPECT_EQ(kMaxSavedFrames,
77 std::count_if(frames.begin(), frames.end(),
78 [](const TestFrameEvictionManagerClient& frame) {
79 return frame.has_frame();
80 }));
81}
82
Benoit Lize6325f042022-09-12 10:11:3583TEST_F(FrameEvictionManagerTest, PeriodicCulling) {
84 base::test::ScopedFeatureList feature_list{features::kAggressiveFrameCulling};
85 // Cannot use a TaskEnvironment as there is already one which is not using
86 // MOCK_TIME.
87 auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
88 FrameEvictionManager manager;
89 manager.set_max_number_of_saved_frames(5);
90 manager.SetOverridesForTesting(task_runner, task_runner->GetMockTickClock());
91
92 TestFrameEvictionManagerClient frame1{&manager}, frame2{&manager},
93 frame3{&manager};
94 manager.AddFrame(&frame1, false);
95 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay / 10);
96 manager.AddFrame(&frame2, true);
97 manager.AddFrame(&frame3, false);
98
99 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay);
100 EXPECT_FALSE(frame1.has_frame());
101 EXPECT_TRUE(frame2.has_frame());
102 EXPECT_TRUE(frame3.has_frame()); // Too early for this one.
103 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay);
104 EXPECT_FALSE(frame3.has_frame());
105
106 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay / 2);
107 manager.UnlockFrame(&frame2);
108 EXPECT_TRUE(frame2.has_frame());
109
110 // Pause prevents eviction, but not rescheduling the task. Not using
111 // ScopedPause because it impacts the singleton.
112 manager.Pause();
113 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay / 2);
114 EXPECT_TRUE(frame2.has_frame());
115 manager.Unpause();
116
117 task_runner->FastForwardBy(FrameEvictionManager::kPeriodicCullingDelay);
118 EXPECT_FALSE(frame2.has_frame());
119}
120
121TEST_F(FrameEvictionManagerTest, MemoryPressure) {
122 FrameEvictionManager* manager = FrameEvictionManager::GetInstance();
123
124 manager->set_max_number_of_saved_frames(5);
125 TestFrameEvictionManagerClient frame1, frame2;
126 manager->AddFrame(&frame1, false);
127 manager->AddFrame(&frame2, false);
128
129 // We keep one frame around, no matter how many times we get a memory pressure
130 // notification.
131 manager->OnMemoryPressure(
132 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
133 EXPECT_FALSE(frame1.has_frame());
134 EXPECT_TRUE(frame2.has_frame());
135
136 manager->OnMemoryPressure(
137 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
138 EXPECT_FALSE(frame1.has_frame());
139 EXPECT_TRUE(frame2.has_frame());
140
141 // Unless aggressive frame culling is enabled.
142 base::test::ScopedFeatureList feature_list{features::kAggressiveFrameCulling};
143 manager->OnMemoryPressure(
144 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
145 EXPECT_FALSE(frame1.has_frame());
146 EXPECT_FALSE(frame2.has_frame());
147}
148
Xiyuan Xiad7e4d942019-06-12 22:32:52149} // namespace viz