Chromium Code Reviews| 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) { | |
|
reveman
2012/11/16 03:05:06
nit: space between "for" and "("
| |
| 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) { | |
|
reveman
2012/11/16 03:05:06
here too
| |
| 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) { | |
|
reveman
2012/11/16 03:05:06
here too
| |
| 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) { | |
|
reveman
2012/11/16 03:05:06
and here
| |
| 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 |