Chromium Code Reviews| Index: content/browser/renderer_host/software_frame_manager_unittest.cc |
| diff --git a/content/browser/renderer_host/software_frame_manager_unittest.cc b/content/browser/renderer_host/software_frame_manager_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..964c2b977b6ce463b6951cbb8c1b85e6223d9434 |
| --- /dev/null |
| +++ b/content/browser/renderer_host/software_frame_manager_unittest.cc |
| @@ -0,0 +1,246 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/renderer_host/software_frame_manager.h" |
| + |
| +#include <vector> |
| + |
| +#include "base/sys_info.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace { |
| + |
| +size_t MaxNumberOfSavedFrames() { |
| + static size_t max_number_of_saved_frames = std::min( |
| + 5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256)); |
| + return max_number_of_saved_frames; |
| +} |
|
piman
2013/10/23 23:41:40
Ok, so, rather than duplicate the logic, which is
ccameron
2013/10/24 17:56:41
I'd duplicated this in preference to putting Softw
|
| + |
| +} // namespace |
| + |
| +namespace content { |
| + |
| +class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient { |
| + public: |
| + FakeSoftwareFrameManagerClient() |
| + : evicted_count_(0), weak_ptr_factory_(this) { |
| + software_frame_manager_.reset(new SoftwareFrameManager( |
| + weak_ptr_factory_.GetWeakPtr())); |
| + } |
| + virtual ~FakeSoftwareFrameManagerClient() {} |
| + virtual void SoftwareFrameWasFreed( |
| + uint32 output_surface_id, unsigned frame_id) OVERRIDE { |
| + freed_frames_.push_back(std::make_pair(output_surface_id, frame_id)); |
| + } |
| + virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE { |
| + ++evicted_count_; |
| + } |
| + |
| + bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) { |
| + cc::SoftwareFrameData frame; |
| + frame.id = frame_id; |
| + frame.size = gfx::Size(1, 1); |
| + frame.damage_rect = gfx::Rect(frame.size); |
| + frame.handle = base::SharedMemory::NULLHandle(); |
| + return software_frame_manager_->SwapToNewFrame( |
| + output_surface, &frame, 1.0, base::GetCurrentProcessHandle()); |
| + } |
| + |
| + std::vector<std::pair<uint32,unsigned> > freed_frames_; |
|
piman
2013/10/23 23:41:40
nit: private + accessors
ccameron
2013/10/24 17:56:41
Done.
|
| + size_t evicted_count_; |
| + |
| + scoped_ptr<SoftwareFrameManager> software_frame_manager_; |
| + base::WeakPtrFactory<FakeSoftwareFrameManagerClient> |
| + weak_ptr_factory_; |
|
piman
2013/10/23 23:41:40
nit: DISALLOW_COPY_AND_ASSIGN
ccameron
2013/10/24 17:56:41
Done.
|
| +}; |
| + |
| +class SoftwareFrameManagerTest : public testing::Test { |
| + public: |
| + void AllocateClients(size_t num_clients) { |
| + for (size_t i = 0; i < num_clients; ++i) |
| + clients_.push_back(new FakeSoftwareFrameManagerClient); |
| + } |
| + void FreeClients() { |
| + for (size_t i = 0; i < clients_.size(); ++i) |
| + delete clients_[i]; |
| + clients_.clear(); |
| + } |
| + |
| + std::vector<FakeSoftwareFrameManagerClient*> clients_; |
|
piman
2013/10/23 23:41:40
nit: private+accessors, DISALLOW_COPY_AND_ASSIGN
ccameron
2013/10/24 17:56:41
Made this protected instead (since all tests acces
|
| +}; |
| + |
| +TEST_F(SoftwareFrameManagerTest, DoNotEvictVisible) { |
| + // Create twice as many frames as are allowed. |
| + AllocateClients(2 * MaxNumberOfSavedFrames()); |
| + |
| + // Swap a visible frame to all clients_. Because they are all visible, |
| + // the should not be evicted. |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + bool swap_result = clients_[i]->SwapToNewFrame( |
| + static_cast<uint32>(i), 0); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + |
| + // Swap another frame and make sure the original was freed (but not evicted). |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + bool swap_result = clients_[i]->SwapToNewFrame( |
| + static_cast<uint32>(i), 1); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(1u, clients_[i]->freed_frames_.size()); |
| + } |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(1u, clients_[i]->freed_frames_.size()); |
| + } |
| + |
| + // Mark the frames as nonvisible and make sure they start getting evicted. |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + clients_[i]->software_frame_manager_->SetVisibility(false); |
| + if (clients_.size() - i > MaxNumberOfSavedFrames()) { |
| + EXPECT_EQ(1u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(2u, clients_[i]->freed_frames_.size()); |
| + } else { |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(1u, clients_[i]->freed_frames_.size()); |
| + } |
| + } |
| + |
| + // Clean up. |
| + FreeClients(); |
| +} |
| + |
| +TEST_F(SoftwareFrameManagerTest, DoNotEvictDuringSwap) { |
| + // Create twice as many frames as are allowed. |
| + AllocateClients(2 * MaxNumberOfSavedFrames()); |
| + |
| + // Swap a visible frame to all clients_. Because they are all visible, |
| + // the should not be evicted. |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + |
| + // Now create a test non-visible client, and swap a non-visible frame in. |
| + scoped_ptr<FakeSoftwareFrameManagerClient> test_client( |
| + new FakeSoftwareFrameManagerClient); |
| + test_client->software_frame_manager_->SetVisibility(false); |
| + { |
| + bool swap_result = test_client->SwapToNewFrame( |
| + static_cast<uint32>(500), 0); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, test_client->evicted_count_); |
| + EXPECT_EQ(0u, test_client->freed_frames_.size()); |
| + test_client->software_frame_manager_->SwapToNewFrameComplete(false); |
| + EXPECT_EQ(1u, test_client->evicted_count_); |
| + EXPECT_EQ(1u, test_client->freed_frames_.size()); |
| + } |
| + |
| + // Clean up. |
| + FreeClients(); |
| +} |
| + |
| +TEST_F(SoftwareFrameManagerTest, Cleanup) { |
| + // Create twice as many frames as are allowed. |
| + AllocateClients(2 * MaxNumberOfSavedFrames()); |
| + |
| + // Swap a visible frame to all clients_. Because they are all visible, |
| + // the should not be evicted. |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + |
| + // Destroy them. |
| + FreeClients(); |
| + |
| + // Create the maximum number of frames, all non-visible. They should not |
| + // be evicted, because the previous frames were cleaned up at destruction. |
| + AllocateClients(MaxNumberOfSavedFrames()); |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + cc::SoftwareFrameData frame; |
| + bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_TRUE(swap_result); |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + EXPECT_EQ(0u, clients_[i]->evicted_count_); |
| + EXPECT_EQ(0u, clients_[i]->freed_frames_.size()); |
| + } |
| + |
| + // Clean up. |
| + FreeClients(); |
| +} |
| + |
| +TEST_F(SoftwareFrameManagerTest, EvictVersusFree) { |
| + // Create twice as many frames as are allowed and swap a visible frame to all |
| + // clients_. Because they are all visible, the should not be evicted. |
| + AllocateClients(2 * MaxNumberOfSavedFrames()); |
| + for (size_t i = 0; i < clients_.size(); ++i) { |
| + clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0); |
| + clients_[i]->software_frame_manager_->SwapToNewFrameComplete(true); |
| + } |
| + |
| + // Create a test client with a frame that is not evicted. |
| + scoped_ptr<FakeSoftwareFrameManagerClient> test_client( |
| + new FakeSoftwareFrameManagerClient); |
| + bool swap_result = test_client->SwapToNewFrame(static_cast<uint32>(500), 0); |
| + EXPECT_TRUE(swap_result); |
| + test_client->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_EQ(0u, test_client->evicted_count_); |
| + EXPECT_EQ(0u, test_client->freed_frames_.size()); |
| + |
| + // Take out a reference on the current frame and make the memory manager |
| + // evict it. The frame will not be freed until this reference is released. |
| + cc::TextureMailbox mailbox; |
| + scoped_ptr<cc::SingleReleaseCallback> callback; |
| + test_client->software_frame_manager_->GetCurrentFrameMailbox( |
| + &mailbox, &callback); |
| + test_client->software_frame_manager_->SetVisibility(false); |
| + EXPECT_EQ(1u, test_client->evicted_count_); |
| + EXPECT_EQ(0u, test_client->freed_frames_.size()); |
| + |
| + // Swap a few frames. The frames will be freed as they are swapped out. |
| + for (size_t frame = 0; frame < 10; ++frame) { |
| + bool swap_result = test_client->SwapToNewFrame( |
| + static_cast<uint32>(500), 1 + static_cast<int>(frame)); |
| + EXPECT_TRUE(swap_result); |
| + test_client->software_frame_manager_->SwapToNewFrameComplete(true); |
| + EXPECT_EQ(frame, test_client->freed_frames_.size()); |
| + EXPECT_EQ(1u, test_client->evicted_count_); |
| + } |
| + |
| + // The reference to the frame that we didn't free is in the callback |
| + // object. It will go away when the callback is destroyed. |
| + EXPECT_EQ(9u, test_client->freed_frames_.size()); |
| + EXPECT_EQ(1u, test_client->evicted_count_); |
| + callback->Run(0, false); |
| + callback.reset(); |
| + EXPECT_EQ(10u, test_client->freed_frames_.size()); |
| + EXPECT_EQ(1u, test_client->evicted_count_); |
| + |
| + FreeClients(); |
| +} |
| + |
| +} // namespace content |