1 // Copyright 2014 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 "android_webview/browser/global_tile_manager.h" 6 #include "android_webview/browser/global_tile_manager_client.h" 7 #include "base/lazy_instance.h" 8 9 using content::SynchronousCompositorMemoryPolicy; 10 11 namespace android_webview { 12 13 namespace { 14 15 base::LazyInstance<GlobalTileManager>::Leaky g_tile_manager = 16 LAZY_INSTANCE_INITIALIZER; 17 18 // The soft limit of the number of file descriptors per process is 1024 on 19 // Android and gralloc buffers may not be the only thing that uses file 20 // descriptors. For each tile, there is a gralloc buffer backing it, which 21 // uses 2 FDs. 22 const size_t kNumTilesLimit = 450; 23 24 } // namespace 25 26 // static 27 GlobalTileManager* GlobalTileManager::GetInstance() { 28 return g_tile_manager.Pointer(); 29 } 30 31 void GlobalTileManager::Remove(Key key) { 32 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 33 DCHECK(mru_list_.end() != key); 34 35 total_allocated_tiles_ -= (*key)->GetMemoryPolicy().num_resources_limit; 36 mru_list_.erase(key); 37 DCHECK(IsConsistent()); 38 } 39 40 size_t GlobalTileManager::Evict(size_t desired_num_tiles, Key key) { 41 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 42 size_t total_evicted_tiles = 0; 43 44 // Evicts from the least recent drawn view, until the disired number of tiles 45 // can be reclaimed, or until we've evicted all inactive views. 46 ListType::reverse_iterator it; 47 for (it = mru_list_.rbegin(); it != mru_list_.rend(); it++) { 48 // key represents the view that requested the eviction, so we don't need to 49 // evict the requester itself. And we only evict the inactive views, 50 // which are all the views after the requester. 51 if (*it == *key) 52 break; 53 54 size_t evicted_tiles = (*it)->GetMemoryPolicy().num_resources_limit; 55 SynchronousCompositorMemoryPolicy zero_policy; 56 (*it)->SetMemoryPolicy(zero_policy, true); 57 58 total_evicted_tiles += evicted_tiles; 59 if (total_evicted_tiles >= desired_num_tiles) 60 break; 61 } 62 63 return total_evicted_tiles; 64 } 65 66 void GlobalTileManager::SetTileLimit(size_t num_tiles_limit) { 67 num_tiles_limit_ = num_tiles_limit; 68 } 69 70 void GlobalTileManager::RequestTiles( 71 SynchronousCompositorMemoryPolicy new_policy, 72 Key key) { 73 DCHECK(IsConsistent()); 74 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 75 size_t new_num_of_tiles = new_policy.num_resources_limit; 76 size_t old_num_of_tiles = (*key)->GetMemoryPolicy().num_resources_limit; 77 size_t num_of_active_views = std::distance(mru_list_.begin(), key) + 1; 78 size_t tiles_per_view_limit; 79 if (num_of_active_views == 0) 80 tiles_per_view_limit = num_tiles_limit_; 81 else 82 tiles_per_view_limit = num_tiles_limit_ / num_of_active_views; 83 new_num_of_tiles = std::min(new_num_of_tiles, tiles_per_view_limit); 84 size_t new_total_allocated_tiles = 85 total_allocated_tiles_ - old_num_of_tiles + new_num_of_tiles; 86 // Has enough tiles to satisfy the request. 87 if (new_total_allocated_tiles <= num_tiles_limit_) { 88 total_allocated_tiles_ = new_total_allocated_tiles; 89 new_policy.num_resources_limit = new_num_of_tiles; 90 (*key)->SetMemoryPolicy(new_policy, false); 91 return; 92 } 93 94 // Does not have enough tiles. Now evict other clients' tiles. 95 size_t tiles_left = num_tiles_limit_ - total_allocated_tiles_; 96 97 size_t evicted_tiles = 98 Evict(new_total_allocated_tiles - num_tiles_limit_, key); 99 if (evicted_tiles >= new_total_allocated_tiles - num_tiles_limit_) { 100 new_total_allocated_tiles -= evicted_tiles; 101 total_allocated_tiles_ = new_total_allocated_tiles; 102 new_policy.num_resources_limit = new_num_of_tiles; 103 (*key)->SetMemoryPolicy(new_policy, false); 104 return; 105 } else { 106 total_allocated_tiles_ = num_tiles_limit_; 107 new_policy.num_resources_limit = 108 tiles_left + old_num_of_tiles + evicted_tiles; 109 (*key)->SetMemoryPolicy(new_policy, false); 110 return; 111 } 112 } 113 114 GlobalTileManager::Key GlobalTileManager::PushBack( 115 GlobalTileManagerClient* client) { 116 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 117 DCHECK(mru_list_.end() == 118 std::find(mru_list_.begin(), mru_list_.end(), client)); 119 mru_list_.push_back(client); 120 Key back = mru_list_.end(); 121 back--; 122 return back; 123 } 124 125 void GlobalTileManager::DidUse(Key key) { 126 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 127 DCHECK(mru_list_.end() != key); 128 129 mru_list_.splice(mru_list_.begin(), mru_list_, key); 130 } 131 132 GlobalTileManager::GlobalTileManager() 133 : num_tiles_limit_(kNumTilesLimit), total_allocated_tiles_(0) { 134 } 135 136 GlobalTileManager::~GlobalTileManager() { 137 } 138 139 bool GlobalTileManager::IsConsistent() const { 140 size_t total_tiles = 0; 141 ListType::const_iterator it; 142 for (it = mru_list_.begin(); it != mru_list_.end(); it++) { 143 total_tiles += (*it)->GetMemoryPolicy().num_resources_limit; 144 } 145 146 bool is_consistent = (total_tiles <= num_tiles_limit_ && 147 total_tiles == total_allocated_tiles_); 148 149 return is_consistent; 150 } 151 152 } // namespace webview 153