OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/tile_manager.h" | 5 #include "cc/tile_manager.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
7 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "cc/tile.h" |
8 | 11 |
9 namespace cc { | 12 namespace cc { |
10 | 13 |
11 TileManager::TileManager(TileManagerClient* client) | 14 TileManager::TileManager(TileManagerClient* client) |
12 : client_(client) | 15 : client_(client) |
13 , manage_tiles_pending_(false) | 16 , manage_tiles_pending_(false) |
14 { | 17 { |
15 } | 18 } |
16 | 19 |
17 TileManager::~TileManager() { | 20 TileManager::~TileManager() { |
| 21 // Reset global state and manage. This should cause |
| 22 // our memory usage to drop to zero. |
| 23 global_state_ = GlobalStateThatImpactsTilePriority(); |
18 ManageTiles(); | 24 ManageTiles(); |
19 DCHECK(tile_versions_.size() == 0); | 25 DCHECK(tiles_.size() == 0); |
20 } | 26 } |
21 | 27 |
22 void TileManager::SetGlobalState(const GlobalStateThatImpactsTilePriority& globa
l_state) { | 28 void TileManager::SetGlobalState(const GlobalStateThatImpactsTilePriority& globa
l_state) { |
23 global_state_ = global_state; | 29 global_state_ = global_state; |
24 ScheduleManageTiles(); | 30 ScheduleManageTiles(); |
25 } | 31 } |
26 | 32 |
27 void TileManager::ManageTiles() { | 33 void TileManager::RegisterTile(Tile* tile) { |
28 // Figure out how much memory we would be willing to give out. | 34 tiles_.push_back(tile); |
29 | |
30 // Free up memory. | |
31 | |
32 // GC old versions. | |
33 } | |
34 | |
35 void TileManager::DidCreateTileVersion(TileVersion* version) { | |
36 tile_versions_.push_back(version); | |
37 ScheduleManageTiles(); | 35 ScheduleManageTiles(); |
38 } | 36 } |
39 | 37 |
40 void TileManager::DidDeleteTileVersion(TileVersion* version) { | 38 void TileManager::UnregisterTile(Tile* tile) { |
41 for (size_t i = 0; i < tile_versions_.size(); i++) { | 39 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); it++) { |
42 if (tile_versions_[i] == version) { | 40 if (*it == tile) { |
43 tile_versions_.erase(tile_versions_.begin() + i); | 41 tiles_.erase(it); |
44 return; | 42 return; |
45 } | 43 } |
46 } | 44 } |
47 DCHECK(false) << "Could not find tile version."; | 45 DCHECK(false) << "Could not find tile version."; |
48 } | 46 } |
49 | 47 |
50 void TileManager::WillModifyTileVersionPriority(TileVersion*, const TilePriority
& new_priority) { | 48 void TileManager::WillModifyTilePriority(Tile*, WhichTree tree, const TilePriori
ty& new_priority) { |
51 // TODO(nduca): Do something smarter if reprioritization turns out to be | 49 // TODO(nduca): Do something smarter if reprioritization turns out to be |
52 // costly. | 50 // costly. |
53 ScheduleManageTiles(); | 51 ScheduleManageTiles(); |
54 } | 52 } |
55 | 53 |
56 void TileManager::ScheduleManageTiles() { | 54 void TileManager::ScheduleManageTiles() { |
57 if (manage_tiles_pending_) | 55 if (manage_tiles_pending_) |
58 return; | 56 return; |
59 ScheduleManageTiles(); | 57 ScheduleManageTiles(); |
60 manage_tiles_pending_ = true; | 58 manage_tiles_pending_ = true; |
61 } | 59 } |
62 | 60 |
| 61 class BinComparator { |
| 62 public: |
| 63 bool operator() (const Tile* a, const Tile* b) const { |
| 64 const ManagedTileState& ams = a->managed_state(); |
| 65 const ManagedTileState& bms = b->managed_state(); |
| 66 if (ams.bin != bms.bin) |
| 67 return ams.bin < bms.bin; |
| 68 |
| 69 if (ams.resolution != bms.resolution) |
| 70 return ams.resolution < ams.resolution; |
| 71 |
| 72 return |
| 73 ams.time_to_needed_in_seconds < |
| 74 bms.time_to_needed_in_seconds; |
| 75 } |
| 76 }; |
| 77 |
| 78 void TileManager::ManageTiles() { |
| 79 // The amount of time for which we want to have prepainting coverage. |
| 80 const double prepainting_window_time_seconds = 1.0; |
| 81 const double backfling_guard_distance_pixels = 314.0; |
| 82 |
| 83 const bool smoothness_takes_priority = global_state_.smoothness_takes_priority
; |
| 84 |
| 85 // Bin into three categories of tiles: things we need now, things we need soon
, and eventually |
| 86 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 87 Tile* tile = *it; |
| 88 ManagedTileState& mts = tile->managed_state(); |
| 89 TilePriority prio; |
| 90 if (smoothness_takes_priority) |
| 91 prio = tile->priority(ACTIVE_TREE); |
| 92 else |
| 93 prio = tile->combined_priority(); |
| 94 |
| 95 mts.resolution = prio.resolution; |
| 96 mts.time_to_needed_in_seconds = prio.time_to_needed_in_seconds(); |
| 97 |
| 98 if (mts.time_to_needed_in_seconds == |
| 99 std::numeric_limits<float>::max()) { |
| 100 mts.bin = NEVER_BIN; |
| 101 continue; |
| 102 } |
| 103 |
| 104 if (mts.resolution == NON_IDEAL_RESOLUTION) { |
| 105 mts.bin = EVENTUALLY_BIN; |
| 106 continue; |
| 107 } |
| 108 |
| 109 if (mts.time_to_needed_in_seconds == 0 || |
| 110 prio.distance_to_visible_in_pixels < backfling_guard_distance_pixels) { |
| 111 mts.bin = NOW_BIN; |
| 112 continue; |
| 113 } |
| 114 |
| 115 if (prio.time_to_needed_in_seconds() < prepainting_window_time_seconds) { |
| 116 mts.bin = SOON_BIN; |
| 117 continue; |
| 118 } |
| 119 |
| 120 mts.bin = EVENTUALLY_BIN; |
| 121 } |
| 122 |
| 123 // Memory limit policy works by mapping some bin states to the NEVER bin. |
| 124 TileManagerBin bin_map[NUM_BINS]; |
| 125 if (global_state_.memory_limit_policy == ALLOW_NOTHING) { |
| 126 bin_map[NOW_BIN] = NEVER_BIN; |
| 127 bin_map[SOON_BIN] = NEVER_BIN; |
| 128 bin_map[EVENTUALLY_BIN] = NEVER_BIN; |
| 129 bin_map[NEVER_BIN] = NEVER_BIN; |
| 130 } else if (global_state_.memory_limit_policy == ALLOW_ABSOLUTE_MINIMUM) { |
| 131 bin_map[NOW_BIN] = NOW_BIN; |
| 132 bin_map[SOON_BIN] = NEVER_BIN; |
| 133 bin_map[EVENTUALLY_BIN] = NEVER_BIN; |
| 134 bin_map[NEVER_BIN] = NEVER_BIN; |
| 135 } else if (global_state_.memory_limit_policy == ALLOW_PREPAINT_ONLY) { |
| 136 bin_map[NOW_BIN] = NOW_BIN; |
| 137 bin_map[SOON_BIN] = SOON_BIN; |
| 138 bin_map[EVENTUALLY_BIN] = NEVER_BIN; |
| 139 bin_map[NEVER_BIN] = NEVER_BIN; |
| 140 } else { |
| 141 bin_map[NOW_BIN] = NOW_BIN; |
| 142 bin_map[SOON_BIN] = SOON_BIN; |
| 143 bin_map[EVENTUALLY_BIN] = NEVER_BIN; |
| 144 bin_map[NEVER_BIN] = NEVER_BIN; |
| 145 } |
| 146 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 147 Tile* tile = *it; |
| 148 TileManagerBin bin = bin_map[tile->managed_state().bin]; |
| 149 tile->managed_state().bin = bin; |
| 150 } |
| 151 |
| 152 // Sort by bin. |
| 153 std::sort(tiles_.begin(), tiles_.end(), BinComparator()); |
| 154 |
| 155 // Some memory cannot be released. Figure out which. |
| 156 size_t unreleasable_bytes = 0; |
| 157 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 158 Tile* tile = *it; |
| 159 if (tile->managed_state().resource_id_can_be_freed) |
| 160 unreleasable_bytes += tile->bytes_consumed_if_allocated(); |
| 161 } |
| 162 |
| 163 // Now give memory out to the tiles until we're out, and build |
| 164 // the needs-to-be-painted and needs-to-be-freed queues. |
| 165 tiles_that_need_to_be_painted_.erase( |
| 166 tiles_that_need_to_be_painted_.begin(), |
| 167 tiles_that_need_to_be_painted_.end()); |
| 168 |
| 169 size_t bytes_left = global_state_.memory_limit_in_bytes - unreleasable_bytes; |
| 170 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 171 Tile* tile = *it; |
| 172 size_t tile_bytes = tile->bytes_consumed_if_allocated(); |
| 173 ManagedTileState& managed_tile_state = tile->managed_state(); |
| 174 if (managed_tile_state.resource_id_can_be_freed) |
| 175 continue; |
| 176 if (tile_bytes > bytes_left) { |
| 177 managed_tile_state.can_use_gpu_memory = false; |
| 178 if (managed_tile_state.resource_id && managed_tile_state.resource_id_can_b
e_freed) |
| 179 FreeResourcesForTile(tile); |
| 180 continue; |
| 181 } |
| 182 bytes_left -= tile_bytes; |
| 183 managed_tile_state.can_use_gpu_memory = true; |
| 184 if (!managed_tile_state.resource_id) |
| 185 tiles_that_need_to_be_painted_.push_back(tile); |
| 186 } |
| 187 |
| 188 // Reverse two tiles_that_need_* vectors such that pop_back gets |
| 189 // the highest priority tile. |
| 190 std::reverse( |
| 191 tiles_that_need_to_be_painted_.begin(), |
| 192 tiles_that_need_to_be_painted_.end()); |
| 193 |
| 194 // Finally, kick the rasterizer. |
| 195 ScheduleMorePaintingJobs(); |
63 } | 196 } |
| 197 |
| 198 void TileManager::FreeResourcesForTile(Tile* tile) { |
| 199 DCHECK(!tile->managed_state().can_use_gpu_memory && |
| 200 tile->managed_state().resource_id_can_be_freed); |
| 201 // TODO(nduca): Do something intelligent here. |
| 202 } |
| 203 |
| 204 void TileManager::ScheduleMorePaintingJobs() { |
| 205 // TODO(nduca): The next big thing. |
| 206 } |
| 207 |
| 208 |
| 209 } |
OLD | NEW |