Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2012 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.
      4 
      5 #include "content/common/gpu/gpu_memory_manager.h"
      6 #include "content/common/gpu/gpu_memory_manager_client.h"
      7 #include "content/common/gpu/gpu_memory_tracking.h"
      8 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
      9 #include "ui/gfx/size_conversions.h"
     10 
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 using gpu::MemoryAllocation;
     14 
     15 #if defined(COMPILER_GCC)
     16 namespace BASE_HASH_NAMESPACE {
     17 template<>
     18 struct hash<content::GpuMemoryManagerClient*> {
     19   uint64 operator()(content::GpuMemoryManagerClient* ptr) const {
     20     return hash<uint64>()(reinterpret_cast<uint64>(ptr));
     21   }
     22 };
     23 }  // namespace BASE_HASH_NAMESPACE
     24 #endif  // COMPILER
     25 
     26 class FakeMemoryTracker : public gpu::gles2::MemoryTracker {
     27  public:
     28   virtual void TrackMemoryAllocatedChange(
     29       size_t /* old_size */,
     30       size_t /* new_size */,
     31       gpu::gles2::MemoryTracker::Pool /* pool */) OVERRIDE {
     32   }
     33   virtual bool EnsureGPUMemoryAvailable(size_t /* size_needed */) OVERRIDE {
     34     return true;
     35   }
     36  private:
     37   virtual ~FakeMemoryTracker() {
     38   }
     39 };
     40 
     41 namespace content {
     42 
     43 // This class is used to collect all stub assignments during a
     44 // Manage() call.
     45 class ClientAssignmentCollector {
     46  public:
     47   struct ClientMemoryStat {
     48     MemoryAllocation allocation;
     49   };
     50   typedef base::hash_map<GpuMemoryManagerClient*, ClientMemoryStat>
     51       ClientMemoryStatMap;
     52 
     53   static const ClientMemoryStatMap& GetClientStatsForLastManage() {
     54     return client_memory_stats_for_last_manage_;
     55   }
     56   static void ClearAllStats() {
     57     client_memory_stats_for_last_manage_.clear();
     58   }
     59   static void AddClientStat(GpuMemoryManagerClient* client,
     60                           const MemoryAllocation& allocation) {
     61     DCHECK(!client_memory_stats_for_last_manage_.count(client));
     62     client_memory_stats_for_last_manage_[client].allocation = allocation;
     63   }
     64 
     65  private:
     66   static ClientMemoryStatMap client_memory_stats_for_last_manage_;
     67 };
     68 
     69 ClientAssignmentCollector::ClientMemoryStatMap
     70     ClientAssignmentCollector::client_memory_stats_for_last_manage_;
     71 
     72 class FakeClient : public GpuMemoryManagerClient {
     73  public:
     74   GpuMemoryManager* memmgr_;
     75   bool suggest_have_frontbuffer_;
     76   MemoryAllocation allocation_;
     77   uint64 total_gpu_memory_;
     78   gfx::Size surface_size_;
     79   GpuMemoryManagerClient* share_group_;
     80   scoped_refptr<gpu::gles2::MemoryTracker> memory_tracker_;
     81   scoped_ptr<GpuMemoryTrackingGroup> tracking_group_;
     82   scoped_ptr<GpuMemoryManagerClientState> client_state_;
     83 
     84   // This will create a client with no surface
     85   FakeClient(GpuMemoryManager* memmgr, GpuMemoryManagerClient* share_group)
     86       : memmgr_(memmgr),
     87         suggest_have_frontbuffer_(false),
     88         total_gpu_memory_(0),
     89         share_group_(share_group),
     90         memory_tracker_(NULL) {
     91     if (!share_group_) {
     92       memory_tracker_ = new FakeMemoryTracker();
     93       tracking_group_.reset(
     94           memmgr_->CreateTrackingGroup(0, memory_tracker_.get()));
     95     }
     96     client_state_.reset(memmgr_->CreateClientState(this, false, true));
     97   }
     98 
     99   // This will create a client with a surface
    100   FakeClient(GpuMemoryManager* memmgr, int32 surface_id, bool visible)
    101       : memmgr_(memmgr),
    102         suggest_have_frontbuffer_(false),
    103         total_gpu_memory_(0),
    104         share_group_(NULL),
    105         memory_tracker_(NULL) {
    106     memory_tracker_ = new FakeMemoryTracker();
    107     tracking_group_.reset(
    108         memmgr_->CreateTrackingGroup(0, memory_tracker_.get()));
    109     client_state_.reset(
    110         memmgr_->CreateClientState(this, surface_id != 0, visible));
    111   }
    112 
    113   virtual ~FakeClient() {
    114     client_state_.reset();
    115     tracking_group_.reset();
    116     memory_tracker_ = NULL;
    117   }
    118 
    119   virtual void SetMemoryAllocation(const MemoryAllocation& alloc) OVERRIDE {
    120     allocation_ = alloc;
    121     ClientAssignmentCollector::AddClientStat(this, alloc);
    122   }
    123 
    124   virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE {
    125     suggest_have_frontbuffer_ = suggest_have_frontbuffer;
    126   }
    127 
    128   virtual bool GetTotalGpuMemory(uint64* bytes) OVERRIDE {
    129     if (total_gpu_memory_) {
    130       *bytes = total_gpu_memory_;
    131       return true;
    132     }
    133     return false;
    134   }
    135   void SetTotalGpuMemory(uint64 bytes) { total_gpu_memory_ = bytes; }
    136 
    137   virtual gpu::gles2::MemoryTracker* GetMemoryTracker() const OVERRIDE {
    138     if (share_group_)
    139       return share_group_->GetMemoryTracker();
    140     return memory_tracker_.get();
    141   }
    142 
    143   virtual gfx::Size GetSurfaceSize() const OVERRIDE {
    144     return surface_size_;
    145   }
    146   void SetSurfaceSize(gfx::Size size) { surface_size_ = size; }
    147 
    148   void SetVisible(bool visible) {
    149     client_state_->SetVisible(visible);
    150   }
    151 
    152   uint64 BytesWhenVisible() const {
    153     return allocation_.bytes_limit_when_visible;
    154   }
    155 };
    156 
    157 class GpuMemoryManagerTest : public testing::Test {
    158  protected:
    159   static const uint64 kFrontbufferLimitForTest = 3;
    160 
    161   GpuMemoryManagerTest()
    162       : memmgr_(0, kFrontbufferLimitForTest) {
    163     memmgr_.TestingDisableScheduleManage();
    164   }
    165 
    166   virtual void SetUp() {
    167   }
    168 
    169   static int32 GenerateUniqueSurfaceId() {
    170     static int32 surface_id_ = 1;
    171     return surface_id_++;
    172   }
    173 
    174   bool IsAllocationForegroundForSurfaceYes(
    175       const MemoryAllocation& alloc) {
    176     return true;
    177   }
    178   bool IsAllocationBackgroundForSurfaceYes(
    179       const MemoryAllocation& alloc) {
    180     return true;
    181   }
    182   bool IsAllocationHibernatedForSurfaceYes(
    183       const MemoryAllocation& alloc) {
    184     return true;
    185   }
    186   bool IsAllocationForegroundForSurfaceNo(
    187       const MemoryAllocation& alloc) {
    188     return alloc.bytes_limit_when_visible != 0;
    189   }
    190   bool IsAllocationBackgroundForSurfaceNo(
    191       const MemoryAllocation& alloc) {
    192     return alloc.bytes_limit_when_visible != 0;
    193   }
    194   bool IsAllocationHibernatedForSurfaceNo(
    195       const MemoryAllocation& alloc) {
    196     return alloc.bytes_limit_when_visible == 0;
    197   }
    198 
    199   void Manage() {
    200     ClientAssignmentCollector::ClearAllStats();
    201     memmgr_.Manage();
    202   }
    203 
    204   GpuMemoryManager memmgr_;
    205 };
    206 
    207 // Test GpuMemoryManager::Manage basic functionality.
    208 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer
    209 // according to visibility and last used time for stubs with surface.
    210 // Expect memory allocation to be shared according to share groups for stubs
    211 // without a surface.
    212 TEST_F(GpuMemoryManagerTest, TestManageBasicFunctionality) {
    213   // Test stubs with surface.
    214   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true),
    215              stub2(&memmgr_, GenerateUniqueSurfaceId(), false);
    216 
    217   Manage();
    218   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_));
    219   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    220 
    221   // Test stubs without surface, with share group of 1 stub.
    222   FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2);
    223 
    224   Manage();
    225   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_));
    226   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    227   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_));
    228   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_));
    229 
    230   // Test stub without surface, with share group of multiple stubs.
    231   FakeClient stub5(&memmgr_ , &stub2);
    232 
    233   Manage();
    234   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_));
    235 }
    236 
    237 // Test GpuMemoryManager::Manage functionality: changing visibility.
    238 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer
    239 // according to visibility and last used time for stubs with surface.
    240 // Expect memory allocation to be shared according to share groups for stubs
    241 // without a surface.
    242 TEST_F(GpuMemoryManagerTest, TestManageChangingVisibility) {
    243   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true),
    244              stub2(&memmgr_, GenerateUniqueSurfaceId(), false);
    245 
    246   FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2);
    247   FakeClient stub5(&memmgr_ , &stub2);
    248 
    249   Manage();
    250   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_));
    251   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    252   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_));
    253   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_));
    254   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_));
    255 
    256   stub1.SetVisible(false);
    257   stub2.SetVisible(true);
    258 
    259   Manage();
    260   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    261   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_));
    262   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_));
    263   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_));
    264   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_));
    265 }
    266 
    267 // Test GpuMemoryManager::Manage functionality: Test more than threshold number
    268 // of visible stubs.
    269 // Expect all allocations to continue to have frontbuffer.
    270 TEST_F(GpuMemoryManagerTest, TestManageManyVisibleStubs) {
    271   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true),
    272              stub2(&memmgr_, GenerateUniqueSurfaceId(), true),
    273              stub3(&memmgr_, GenerateUniqueSurfaceId(), true),
    274              stub4(&memmgr_, GenerateUniqueSurfaceId(), true);
    275 
    276   FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub2);
    277   FakeClient stub7(&memmgr_ , &stub2);
    278 
    279   Manage();
    280   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_));
    281   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_));
    282   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub3.allocation_));
    283   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub4.allocation_));
    284   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_));
    285   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub6.allocation_));
    286   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub7.allocation_));
    287 }
    288 
    289 // Test GpuMemoryManager::Manage functionality: Test more than threshold number
    290 // of not visible stubs.
    291 // Expect the stubs surpassing the threshold to not have a backbuffer.
    292 TEST_F(GpuMemoryManagerTest, TestManageManyNotVisibleStubs) {
    293   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true),
    294              stub2(&memmgr_, GenerateUniqueSurfaceId(), true),
    295              stub3(&memmgr_, GenerateUniqueSurfaceId(), true),
    296              stub4(&memmgr_, GenerateUniqueSurfaceId(), true);
    297   stub4.SetVisible(false);
    298   stub3.SetVisible(false);
    299   stub2.SetVisible(false);
    300   stub1.SetVisible(false);
    301 
    302   FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub4);
    303   FakeClient stub7(&memmgr_ , &stub1);
    304 
    305   Manage();
    306   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    307   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    308   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_));
    309   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_));
    310   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_));
    311   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_));
    312   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_));
    313 }
    314 
    315 // Test GpuMemoryManager::Manage functionality: Test changing the last used
    316 // time of stubs when doing so causes change in which stubs surpass threshold.
    317 // Expect frontbuffer to be dropped for the older stub.
    318 TEST_F(GpuMemoryManagerTest, TestManageChangingLastUsedTime) {
    319   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true),
    320              stub2(&memmgr_, GenerateUniqueSurfaceId(), true),
    321              stub3(&memmgr_, GenerateUniqueSurfaceId(), true),
    322              stub4(&memmgr_, GenerateUniqueSurfaceId(), true);
    323 
    324   FakeClient stub5(&memmgr_ , &stub3), stub6(&memmgr_ , &stub4);
    325   FakeClient stub7(&memmgr_ , &stub3);
    326 
    327   // Make stub4 be the least-recently-used client
    328   stub4.SetVisible(false);
    329   stub3.SetVisible(false);
    330   stub2.SetVisible(false);
    331   stub1.SetVisible(false);
    332 
    333   Manage();
    334   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    335   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    336   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_));
    337   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_));
    338   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_));
    339   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_));
    340   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_));
    341 
    342   // Make stub3 become the least-recently-used client.
    343   stub2.SetVisible(true);
    344   stub2.SetVisible(false);
    345   stub4.SetVisible(true);
    346   stub4.SetVisible(false);
    347 
    348   Manage();
    349   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    350   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    351   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub3.allocation_));
    352   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub4.allocation_));
    353   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub5.allocation_));
    354   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub6.allocation_));
    355   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub7.allocation_));
    356 }
    357 
    358 // Test GpuMemoryManager::Manage functionality: Test changing importance of
    359 // enough stubs so that every stub in share group crosses threshold.
    360 // Expect memory allocation of the stubs without surface to share memory
    361 // allocation with the most visible stub in share group.
    362 TEST_F(GpuMemoryManagerTest, TestManageChangingImportanceShareGroup) {
    363   FakeClient stub_ignore_a(&memmgr_, GenerateUniqueSurfaceId(), true),
    364              stub_ignore_b(&memmgr_, GenerateUniqueSurfaceId(), false),
    365              stub_ignore_c(&memmgr_, GenerateUniqueSurfaceId(), false);
    366   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), false),
    367              stub2(&memmgr_, GenerateUniqueSurfaceId(), false);
    368 
    369   FakeClient stub3(&memmgr_, &stub2), stub4(&memmgr_, &stub2);
    370 
    371   // stub1 and stub2 keep their non-hibernated state because they're
    372   // either visible or the 2 most recently used clients (through the
    373   // first three checks).
    374   stub1.SetVisible(true);
    375   stub2.SetVisible(true);
    376   Manage();
    377   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_));
    378   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_));
    379   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_));
    380   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_));
    381 
    382   stub1.SetVisible(false);
    383   Manage();
    384   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    385   EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_));
    386   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_));
    387   EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_));
    388 
    389   stub2.SetVisible(false);
    390   Manage();
    391   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_));
    392   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    393   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_));
    394   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_));
    395 
    396   // stub_ignore_b will cause stub1 to become hibernated (because
    397   // stub_ignore_a, stub_ignore_b, and stub2 are all non-hibernated and more
    398   // important).
    399   stub_ignore_b.SetVisible(true);
    400   stub_ignore_b.SetVisible(false);
    401   Manage();
    402   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_));
    403   EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_));
    404   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_));
    405   EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_));
    406 
    407   // stub_ignore_c will cause stub2 to become hibernated (because
    408   // stub_ignore_a, stub_ignore_b, and stub_ignore_c are all non-hibernated
    409   // and more important).
    410   stub_ignore_c.SetVisible(true);
    411   stub_ignore_c.SetVisible(false);
    412   Manage();
    413   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_));
    414   EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub2.allocation_));
    415   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub3.allocation_));
    416   EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub4.allocation_));
    417 }
    418 
    419 }  // namespace content
    420