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 |