1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/software_frame_manager.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/sys_info.h"
12 #include "content/common/host_shared_bitmap_manager.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 class FakeSoftwareFrameManagerClient
: public SoftwareFrameManagerClient
{
19 FakeSoftwareFrameManagerClient()
20 : evicted_count_(0), weak_ptr_factory_(this) {
21 software_frame_manager_
.reset(new SoftwareFrameManager(
22 weak_ptr_factory_
.GetWeakPtr()));
24 virtual ~FakeSoftwareFrameManagerClient() {
25 HostSharedBitmapManager::current()->ProcessRemoved(
26 base::GetCurrentProcessHandle());
28 void SoftwareFrameWasFreed(uint32 output_surface_id
,
29 unsigned frame_id
) override
{
30 freed_frames_
.push_back(std::make_pair(output_surface_id
, frame_id
));
32 void ReleaseReferencesToSoftwareFrame() override
{ ++evicted_count_
; }
34 bool SwapToNewFrame(uint32 output_surface
, unsigned frame_id
) {
35 cc::SoftwareFrameData frame
;
37 frame
.size
= gfx::Size(1, 1);
38 frame
.damage_rect
= gfx::Rect(frame
.size
);
39 frame
.bitmap_id
= cc::SharedBitmap::GenerateId();
40 scoped_ptr
<base::SharedMemory
> memory
=
41 make_scoped_ptr(new base::SharedMemory
);
42 memory
->CreateAnonymous(4);
43 HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
44 4, memory
->handle(), base::GetCurrentProcessHandle(), frame
.bitmap_id
);
45 allocated_memory_
.push_back(memory
.release());
46 return software_frame_manager_
->SwapToNewFrame(
47 output_surface
, &frame
, 1.0, base::GetCurrentProcessHandle());
50 SoftwareFrameManager
* software_frame_manager() {
51 return software_frame_manager_
.get();
53 size_t freed_frame_count() const { return freed_frames_
.size(); }
54 size_t evicted_frame_count() const { return evicted_count_
; }
57 std::vector
<std::pair
<uint32
,unsigned> > freed_frames_
;
58 size_t evicted_count_
;
59 ScopedVector
<base::SharedMemory
> allocated_memory_
;
61 scoped_ptr
<SoftwareFrameManager
> software_frame_manager_
;
62 base::WeakPtrFactory
<FakeSoftwareFrameManagerClient
>
65 DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFrameManagerClient
);
68 class SoftwareFrameManagerTest
: public testing::Test
{
70 SoftwareFrameManagerTest() {}
71 void AllocateClients(size_t num_clients
) {
72 for (size_t i
= 0; i
< num_clients
; ++i
)
73 clients_
.push_back(new FakeSoftwareFrameManagerClient
);
76 for (size_t i
= 0; i
< clients_
.size(); ++i
)
80 size_t MaxNumberOfSavedFrames() const {
82 RendererFrameManager::GetInstance()->max_number_of_saved_frames();
87 std::vector
<FakeSoftwareFrameManagerClient
*> clients_
;
90 DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManagerTest
);
93 TEST_F(SoftwareFrameManagerTest
, DoNotEvictVisible
) {
94 // Create twice as many frames as are allowed.
95 AllocateClients(2 * MaxNumberOfSavedFrames());
97 // Swap a visible frame to all clients_. Because they are all visible,
98 // the should not be evicted.
99 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
100 bool swap_result
= clients_
[i
]->SwapToNewFrame(
101 static_cast<uint32
>(i
), 0);
102 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
103 EXPECT_TRUE(swap_result
);
104 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
105 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
107 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
108 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
109 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
112 // Swap another frame and make sure the original was freed (but not evicted).
113 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
114 bool swap_result
= clients_
[i
]->SwapToNewFrame(
115 static_cast<uint32
>(i
), 1);
116 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
117 EXPECT_TRUE(swap_result
);
118 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
119 EXPECT_EQ(1u, clients_
[i
]->freed_frame_count());
121 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
122 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
123 EXPECT_EQ(1u, clients_
[i
]->freed_frame_count());
126 // Mark the frames as nonvisible and make sure they start getting evicted.
127 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
128 clients_
[i
]->software_frame_manager()->SetVisibility(false);
129 if (clients_
.size() - i
> MaxNumberOfSavedFrames()) {
130 EXPECT_EQ(1u, clients_
[i
]->evicted_frame_count());
131 EXPECT_EQ(2u, clients_
[i
]->freed_frame_count());
133 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
134 EXPECT_EQ(1u, clients_
[i
]->freed_frame_count());
142 TEST_F(SoftwareFrameManagerTest
, DoNotEvictDuringSwap
) {
143 // Create twice as many frames as are allowed.
144 AllocateClients(2 * MaxNumberOfSavedFrames());
146 // Swap a visible frame to all clients_. Because they are all visible,
147 // the should not be evicted.
148 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
149 bool swap_result
= clients_
[i
]->SwapToNewFrame(static_cast<uint32
>(i
), 0);
150 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
151 EXPECT_TRUE(swap_result
);
152 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
153 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
155 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
156 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
157 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
160 // Now create a test non-visible client, and swap a non-visible frame in.
161 scoped_ptr
<FakeSoftwareFrameManagerClient
> test_client(
162 new FakeSoftwareFrameManagerClient
);
163 test_client
->software_frame_manager()->SetVisibility(false);
165 bool swap_result
= test_client
->SwapToNewFrame(
166 static_cast<uint32
>(500), 0);
167 EXPECT_TRUE(swap_result
);
168 EXPECT_EQ(0u, test_client
->evicted_frame_count());
169 EXPECT_EQ(0u, test_client
->freed_frame_count());
170 test_client
->software_frame_manager()->SwapToNewFrameComplete(false);
171 EXPECT_EQ(1u, test_client
->evicted_frame_count());
172 EXPECT_EQ(1u, test_client
->freed_frame_count());
179 TEST_F(SoftwareFrameManagerTest
, Cleanup
) {
180 // Create twice as many frames as are allowed.
181 AllocateClients(2 * MaxNumberOfSavedFrames());
183 // Swap a visible frame to all clients_. Because they are all visible,
184 // the should not be evicted.
185 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
186 bool swap_result
= clients_
[i
]->SwapToNewFrame(static_cast<uint32
>(i
), 0);
187 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
188 EXPECT_TRUE(swap_result
);
189 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
190 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
196 // Create the maximum number of frames, all non-visible. They should not
197 // be evicted, because the previous frames were cleaned up at destruction.
198 AllocateClients(MaxNumberOfSavedFrames());
199 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
200 cc::SoftwareFrameData frame
;
201 bool swap_result
= clients_
[i
]->SwapToNewFrame(static_cast<uint32
>(i
), 0);
202 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
203 EXPECT_TRUE(swap_result
);
204 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
205 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
207 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
208 EXPECT_EQ(0u, clients_
[i
]->evicted_frame_count());
209 EXPECT_EQ(0u, clients_
[i
]->freed_frame_count());
216 TEST_F(SoftwareFrameManagerTest
, EvictVersusFree
) {
217 // Create twice as many frames as are allowed and swap a visible frame to all
218 // clients_. Because they are all visible, the should not be evicted.
219 AllocateClients(2 * MaxNumberOfSavedFrames());
220 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
221 clients_
[i
]->SwapToNewFrame(static_cast<uint32
>(i
), 0);
222 clients_
[i
]->software_frame_manager()->SwapToNewFrameComplete(true);
225 // Create a test client with a frame that is not evicted.
226 scoped_ptr
<FakeSoftwareFrameManagerClient
> test_client(
227 new FakeSoftwareFrameManagerClient
);
228 bool swap_result
= test_client
->SwapToNewFrame(static_cast<uint32
>(500), 0);
229 EXPECT_TRUE(swap_result
);
230 test_client
->software_frame_manager()->SwapToNewFrameComplete(true);
231 EXPECT_EQ(0u, test_client
->evicted_frame_count());
232 EXPECT_EQ(0u, test_client
->freed_frame_count());
234 // Take out a reference on the current frame and make the memory manager
235 // evict it. The frame will not be freed until this reference is released.
236 cc::TextureMailbox mailbox
;
237 scoped_ptr
<cc::SingleReleaseCallback
> callback
;
238 test_client
->software_frame_manager()->GetCurrentFrameMailbox(
239 &mailbox
, &callback
);
240 test_client
->software_frame_manager()->SetVisibility(false);
241 EXPECT_EQ(1u, test_client
->evicted_frame_count());
242 EXPECT_EQ(0u, test_client
->freed_frame_count());
244 // Swap a few frames. The frames will be freed as they are swapped out.
245 for (size_t frame
= 0; frame
< 10; ++frame
) {
246 bool swap_result
= test_client
->SwapToNewFrame(
247 static_cast<uint32
>(500), 1 + static_cast<int>(frame
));
248 EXPECT_TRUE(swap_result
);
249 test_client
->software_frame_manager()->SwapToNewFrameComplete(true);
250 EXPECT_EQ(frame
, test_client
->freed_frame_count());
251 EXPECT_EQ(1u, test_client
->evicted_frame_count());
254 // The reference to the frame that we didn't free is in the callback
255 // object. It will go away when the callback is destroyed.
256 EXPECT_EQ(9u, test_client
->freed_frame_count());
257 EXPECT_EQ(1u, test_client
->evicted_frame_count());
258 callback
->Run(0, false);
260 EXPECT_EQ(10u, test_client
->freed_frame_count());
261 EXPECT_EQ(1u, test_client
->evicted_frame_count());
266 } // namespace content