Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1038)

Side by Side Diff: cc/surfaces/surface_manager.cc

Issue 2642123004: Fix surface reference assumptions in SurfaceManager. (Closed)
Patch Set: Rebase + fix test. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/surfaces/surface_manager.h ('k') | cc/surfaces/surface_manager_ref_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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/surfaces/surface_manager.h" 5 #include "cc/surfaces/surface_manager.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <queue> 10 #include <queue>
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 DCHECK(surface); 85 DCHECK(surface);
86 DCHECK(!surface_map_.count(surface->surface_id())); 86 DCHECK(!surface_map_.count(surface->surface_id()));
87 surface_map_[surface->surface_id()] = surface; 87 surface_map_[surface->surface_id()] = surface;
88 } 88 }
89 89
90 void SurfaceManager::DeregisterSurface(const SurfaceId& surface_id) { 90 void SurfaceManager::DeregisterSurface(const SurfaceId& surface_id) {
91 DCHECK(thread_checker_.CalledOnValidThread()); 91 DCHECK(thread_checker_.CalledOnValidThread());
92 SurfaceMap::iterator it = surface_map_.find(surface_id); 92 SurfaceMap::iterator it = surface_map_.find(surface_id);
93 DCHECK(it != surface_map_.end()); 93 DCHECK(it != surface_map_.end());
94 surface_map_.erase(it); 94 surface_map_.erase(it);
95 child_to_parent_refs_.erase(surface_id); 95 RemoveAllSurfaceReferences(surface_id);
96 parent_to_child_refs_.erase(surface_id);
97 } 96 }
98 97
99 void SurfaceManager::Destroy(std::unique_ptr<Surface> surface) { 98 void SurfaceManager::Destroy(std::unique_ptr<Surface> surface) {
100 DCHECK(thread_checker_.CalledOnValidThread()); 99 DCHECK(thread_checker_.CalledOnValidThread());
101 surface->set_destroyed(true); 100 surface->set_destroyed(true);
102 surfaces_to_destroy_.push_back(std::move(surface)); 101 surfaces_to_destroy_.push_back(std::move(surface));
103 GarbageCollectSurfaces(); 102 GarbageCollectSurfaces();
104 } 103 }
105 104
106 void SurfaceManager::RequireSequence(const SurfaceId& surface_id, 105 void SurfaceManager::RequireSequence(const SurfaceId& surface_id,
(...skipping 23 matching lines...) Expand all
130 GarbageCollectSurfaces(); 129 GarbageCollectSurfaces();
131 } 130 }
132 131
133 const SurfaceId& SurfaceManager::GetRootSurfaceId() const { 132 const SurfaceId& SurfaceManager::GetRootSurfaceId() const {
134 return root_surface_id_; 133 return root_surface_id_;
135 } 134 }
136 135
137 void SurfaceManager::AddSurfaceReference(const SurfaceId& parent_id, 136 void SurfaceManager::AddSurfaceReference(const SurfaceId& parent_id,
138 const SurfaceId& child_id) { 137 const SurfaceId& child_id) {
139 DCHECK(thread_checker_.CalledOnValidThread()); 138 DCHECK(thread_checker_.CalledOnValidThread());
139 DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
140 140
141 // Check some conditions that should never happen. We don't want to crash on 141 // Check some conditions that should never happen. We don't want to crash on
142 // bad input from a compromised client so just return early. 142 // bad input from a compromised client so just return early.
143 if (parent_id == child_id) { 143 if (parent_id.frame_sink_id() == child_id.frame_sink_id()) {
144 DLOG(ERROR) << "Cannot add self reference for " << parent_id.ToString(); 144 DLOG(ERROR) << "Cannot add self reference from " << parent_id << " to "
145 << child_id;
145 return; 146 return;
146 } 147 }
147 if (parent_id != root_surface_id_ && surface_map_.count(parent_id) == 0) { 148
148 DLOG(ERROR) << "No surface in map for " << parent_id.ToString(); 149 // We trust that |parent_id| either exists or is about to exist, since is not
149 return; 150 // sent over IPC. We don't trust |child_id|, since it is sent over IPC.
150 }
151 if (surface_map_.count(child_id) == 0) { 151 if (surface_map_.count(child_id) == 0) {
152 DLOG(ERROR) << "No surface in map for " << child_id.ToString(); 152 DLOG(ERROR) << "No surface in map for " << child_id.ToString();
153 return; 153 return;
154 } 154 }
155 155
156 // There could be a temporary reference to |child_id| which we should now 156 // There could be a temporary reference to |child_id| which we should now
157 // remove because a real reference is being added to it. To find out whether 157 // remove because a real reference is being added to it. To find out whether
158 // or not a temporary reference exists, we need to first look up the 158 // or not a temporary reference exists, we need to first look up the
159 // FrameSinkId of |child_id| in |temp_references_|, which returns a vector of 159 // FrameSinkId of |child_id| in |temp_references_|, which returns a vector of
160 // LocalFrameIds, and then search for the LocalFrameId of |child_id| in the 160 // LocalFrameIds, and then search for the LocalFrameId of |child_id| in the
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 // Remove markers for temporary references up to |child_id|, as the temporary 194 // Remove markers for temporary references up to |child_id|, as the temporary
195 // references they correspond to were removed above. If |temp_ref_iter| points 195 // references they correspond to were removed above. If |temp_ref_iter| points
196 // at the last element in |refs| then we are removing all temporary references 196 // at the last element in |refs| then we are removing all temporary references
197 // for the FrameSinkId and can remove the map entry entirely. 197 // for the FrameSinkId and can remove the map entry entirely.
198 if (++temp_ref_iter == refs.end()) 198 if (++temp_ref_iter == refs.end())
199 temp_references_.erase(child_id.frame_sink_id()); 199 temp_references_.erase(child_id.frame_sink_id());
200 else 200 else
201 refs.erase(refs.begin(), temp_ref_iter); 201 refs.erase(refs.begin(), temp_ref_iter);
202 } 202 }
203 203
204 void SurfaceManager::AddSurfaceReferenceImpl(const SurfaceId& parent_id,
205 const SurfaceId& child_id) {
206 parent_to_child_refs_[parent_id].insert(child_id);
207 child_to_parent_refs_[child_id].insert(parent_id);
208 }
209
210 void SurfaceManager::RemoveSurfaceReference(const SurfaceId& parent_id, 204 void SurfaceManager::RemoveSurfaceReference(const SurfaceId& parent_id,
211 const SurfaceId& child_id) { 205 const SurfaceId& child_id) {
212 DCHECK(thread_checker_.CalledOnValidThread()); 206 DCHECK(thread_checker_.CalledOnValidThread());
207 DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
213 208
214 // Check if we have the reference that is requested to be removed. We don't 209 // Check if we have the reference that is requested to be removed. We don't
215 // want to crash on bad input from a compromised client so just return early. 210 // want to crash on bad input from a compromised client so just return early.
216 if (parent_to_child_refs_.count(parent_id) == 0 || 211 if (parent_to_child_refs_.count(parent_id) == 0 ||
217 parent_to_child_refs_[parent_id].count(child_id) == 0) { 212 parent_to_child_refs_[parent_id].count(child_id) == 0) {
218 DLOG(ERROR) << "No reference from " << parent_id.ToString() << " to " 213 DLOG(ERROR) << "No reference from " << parent_id.ToString() << " to "
219 << child_id.ToString(); 214 << child_id.ToString();
220 return; 215 return;
221 } 216 }
222 217
(...skipping 10 matching lines...) Expand all
233 } 228 }
234 229
235 size_t SurfaceManager::GetReferencedSurfaceCount( 230 size_t SurfaceManager::GetReferencedSurfaceCount(
236 const SurfaceId& surface_id) const { 231 const SurfaceId& surface_id) const {
237 auto iter = parent_to_child_refs_.find(surface_id); 232 auto iter = parent_to_child_refs_.find(surface_id);
238 if (iter == parent_to_child_refs_.end()) 233 if (iter == parent_to_child_refs_.end())
239 return 0; 234 return 0;
240 return iter->second.size(); 235 return iter->second.size();
241 } 236 }
242 237
243 void SurfaceManager::GarbageCollectSurfacesFromRoot() { 238 void SurfaceManager::GarbageCollectSurfaces() {
244 DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
245
246 if (surfaces_to_destroy_.empty()) 239 if (surfaces_to_destroy_.empty())
247 return; 240 return;
248 241
249 SurfaceIdSet reachable_surfaces; 242 SurfaceIdSet reachable_surfaces = lifetime_type_ == LifetimeType::REFERENCES
250 243 ? GetLiveSurfacesForReferences()
251 // Walk down from the root and mark each SurfaceId we encounter as reachable. 244 : GetLiveSurfacesForSequences();
252 std::queue<SurfaceId> surface_queue;
253 surface_queue.push(root_surface_id_);
254 while (!surface_queue.empty()) {
255 const SurfaceId& surface_id = surface_queue.front();
256 auto iter = parent_to_child_refs_.find(surface_id);
257 if (iter != parent_to_child_refs_.end()) {
258 for (const SurfaceId& child_id : iter->second) {
259 // Check for cycles when inserting into |reachable_surfaces|.
260 if (reachable_surfaces.insert(child_id).second)
261 surface_queue.push(child_id);
262 }
263 }
264 surface_queue.pop();
265 }
266 245
267 std::vector<std::unique_ptr<Surface>> surfaces_to_delete; 246 std::vector<std::unique_ptr<Surface>> surfaces_to_delete;
268 247
269 // Delete all destroyed and unreachable surfaces. 248 // Delete all destroyed and unreachable surfaces.
270 for (auto iter = surfaces_to_destroy_.begin(); 249 for (auto iter = surfaces_to_destroy_.begin();
271 iter != surfaces_to_destroy_.end();) { 250 iter != surfaces_to_destroy_.end();) {
272 SurfaceId surface_id = (*iter)->surface_id(); 251 SurfaceId surface_id = (*iter)->surface_id();
273 if (reachable_surfaces.count(surface_id) == 0) { 252 if (reachable_surfaces.count(surface_id) == 0) {
274 DeregisterSurface(surface_id); 253 DeregisterSurface(surface_id);
275 surfaces_to_delete.push_back(std::move(*iter)); 254 surfaces_to_delete.push_back(std::move(*iter));
276 iter = surfaces_to_destroy_.erase(iter); 255 iter = surfaces_to_destroy_.erase(iter);
277 } else { 256 } else {
278 ++iter; 257 ++iter;
279 } 258 }
280 } 259 }
281 260
282 // ~Surface() draw callback could modify |surfaces_to_destroy_|. 261 // ~Surface() draw callback could modify |surfaces_to_destroy_|.
283 surfaces_to_delete.clear(); 262 surfaces_to_delete.clear();
284 } 263 }
285 264
286 void SurfaceManager::GarbageCollectSurfaces() { 265 SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForReferences() {
287 if (lifetime_type_ == LifetimeType::REFERENCES) { 266 DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
288 GarbageCollectSurfacesFromRoot(); 267
289 return; 268 SurfaceIdSet reachable_surfaces;
269
270 // Walk down from the root and mark each SurfaceId we encounter as reachable.
271 std::queue<SurfaceId> surface_queue;
272 surface_queue.push(root_surface_id_);
273 while (!surface_queue.empty()) {
274 const SurfaceId& surface_id = surface_queue.front();
275 auto iter = parent_to_child_refs_.find(surface_id);
276 if (iter != parent_to_child_refs_.end()) {
277 for (const SurfaceId& child_id : iter->second) {
278 // Check for cycles when inserting into |reachable_surfaces|.
279 if (reachable_surfaces.insert(child_id).second)
280 surface_queue.push(child_id);
281 }
282 }
283 surface_queue.pop();
290 } 284 }
291 285
286 return reachable_surfaces;
287 }
288
289 SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForSequences() {
290 DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
291
292 // Simple mark and sweep GC. 292 // Simple mark and sweep GC.
293 // TODO(jbauman): Reduce the amount of work when nothing needs to be 293 // TODO(jbauman): Reduce the amount of work when nothing needs to be
294 // destroyed. 294 // destroyed.
295 std::vector<SurfaceId> live_surfaces; 295 std::vector<SurfaceId> live_surfaces;
296 std::unordered_set<SurfaceId, SurfaceIdHash> live_surfaces_set; 296 std::unordered_set<SurfaceId, SurfaceIdHash> live_surfaces_set;
297 297
298 // GC roots are surfaces that have not been destroyed, or have not had all 298 // GC roots are surfaces that have not been destroyed, or have not had all
299 // their destruction dependencies satisfied. 299 // their destruction dependencies satisfied.
300 for (auto& map_entry : surface_map_) { 300 for (auto& map_entry : surface_map_) {
301 const SurfaceId& surface_id = map_entry.first; 301 const SurfaceId& surface_id = map_entry.first;
302 Surface* surface = map_entry.second; 302 Surface* surface = map_entry.second;
303 surface->SatisfyDestructionDependencies(&satisfied_sequences_, 303 surface->SatisfyDestructionDependencies(&satisfied_sequences_,
304 &valid_frame_sink_ids_); 304 &valid_frame_sink_ids_);
305 305
306 // Never use both sequences and references for the same Surface. 306 if (!surface->destroyed() || surface->GetDestructionDependencyCount() > 0) {
307 DCHECK(surface->GetDestructionDependencyCount() == 0 ||
308 GetSurfaceReferenceCount(surface_id) == 0);
309
310 if (!surface->destroyed() || surface->GetDestructionDependencyCount() > 0 ||
311 GetSurfaceReferenceCount(surface_id) > 0) {
312 live_surfaces_set.insert(surface_id); 307 live_surfaces_set.insert(surface_id);
313 live_surfaces.push_back(surface_id); 308 live_surfaces.push_back(surface_id);
314 } 309 }
315 } 310 }
316 311
317 // Mark all surfaces reachable from live surfaces by adding them to 312 // Mark all surfaces reachable from live surfaces by adding them to
318 // live_surfaces and live_surfaces_set. 313 // live_surfaces and live_surfaces_set.
319 for (size_t i = 0; i < live_surfaces.size(); i++) { 314 for (size_t i = 0; i < live_surfaces.size(); i++) {
320 Surface* surf = surface_map_[live_surfaces[i]]; 315 Surface* surf = surface_map_[live_surfaces[i]];
321 DCHECK(surf); 316 DCHECK(surf);
322 317
323 for (const SurfaceId& id : surf->referenced_surfaces()) { 318 for (const SurfaceId& id : surf->referenced_surfaces()) {
324 if (live_surfaces_set.count(id)) 319 if (live_surfaces_set.count(id))
325 continue; 320 continue;
326 321
327 Surface* surf2 = GetSurfaceForId(id); 322 Surface* surf2 = GetSurfaceForId(id);
328 if (surf2) { 323 if (surf2) {
329 live_surfaces.push_back(id); 324 live_surfaces.push_back(id);
330 live_surfaces_set.insert(id); 325 live_surfaces_set.insert(id);
331 } 326 }
332 } 327 }
333 } 328 }
334 329
335 std::vector<std::unique_ptr<Surface>> to_destroy; 330 return live_surfaces_set;
331 }
336 332
337 // Destroy all remaining unreachable surfaces. 333 void SurfaceManager::AddSurfaceReferenceImpl(const SurfaceId& parent_id,
338 for (auto iter = surfaces_to_destroy_.begin(); 334 const SurfaceId& child_id) {
339 iter != surfaces_to_destroy_.end();) { 335 parent_to_child_refs_[parent_id].insert(child_id);
340 SurfaceId surface_id = (*iter)->surface_id(); 336 child_to_parent_refs_[child_id].insert(parent_id);
341 if (!live_surfaces_set.count(surface_id)) {
342 DeregisterSurface(surface_id);
343 to_destroy.push_back(std::move(*iter));
344 iter = surfaces_to_destroy_.erase(iter);
345 } else {
346 ++iter;
347 }
348 }
349
350 to_destroy.clear();
351 } 337 }
352 338
353 void SurfaceManager::RemoveSurfaceReferenceImpl(const SurfaceId& parent_id, 339 void SurfaceManager::RemoveSurfaceReferenceImpl(const SurfaceId& parent_id,
354 const SurfaceId& child_id) { 340 const SurfaceId& child_id) {
355 // Remove the reference from parent to child. This doesn't change anything
356 // about the validity of the parent.
357 parent_to_child_refs_[parent_id].erase(child_id); 341 parent_to_child_refs_[parent_id].erase(child_id);
342 child_to_parent_refs_[child_id].erase(parent_id);
343 }
358 344
359 // Remove the reference from child to parent. This might drop the number of 345 void SurfaceManager::RemoveAllSurfaceReferences(const SurfaceId& surface_id) {
360 // references to the child to zero. 346 // Remove all references from |surface_id| to a child surface.
361 DCHECK_EQ(child_to_parent_refs_.count(child_id), 1u); 347 auto iter = parent_to_child_refs_.find(surface_id);
362 SurfaceIdSet& child_refs = child_to_parent_refs_[child_id]; 348 if (iter != parent_to_child_refs_.end()) {
363 DCHECK_EQ(child_refs.count(parent_id), 1u); 349 for (const SurfaceId& child_id : iter->second)
364 child_refs.erase(parent_id); 350 child_to_parent_refs_[child_id].erase(surface_id);
351 parent_to_child_refs_.erase(iter);
352 }
365 353
366 if (!child_refs.empty()) 354 // Remove all reference from parent surface to |surface_id|.
367 return; 355 iter = child_to_parent_refs_.find(surface_id);
368 356 if (iter != child_to_parent_refs_.end()) {
369 // Remove any references the child holds before it gets garbage collected. 357 for (const SurfaceId& parent_id : iter->second)
370 // Copy SurfaceIdSet to avoid iterator invalidation problems. 358 parent_to_child_refs_[parent_id].erase(surface_id);
371 SurfaceIdSet child_child_refs = parent_to_child_refs_[child_id]; 359 child_to_parent_refs_.erase(iter);
372 for (auto& child_child_id : child_child_refs) 360 }
373 RemoveSurfaceReferenceImpl(child_id, child_child_id);
374 DCHECK_EQ(GetReferencedSurfaceCount(child_id), 0u);
375 } 361 }
376 362
377 void SurfaceManager::RegisterSurfaceFactoryClient( 363 void SurfaceManager::RegisterSurfaceFactoryClient(
378 const FrameSinkId& frame_sink_id, 364 const FrameSinkId& frame_sink_id,
379 SurfaceFactoryClient* client) { 365 SurfaceFactoryClient* client) {
380 DCHECK(client); 366 DCHECK(client);
381 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u); 367 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u);
382 368
383 // Will create a new FrameSinkSourceMapping for |frame_sink_id| if necessary. 369 // Will create a new FrameSinkSourceMapping for |frame_sink_id| if necessary.
384 FrameSinkSourceMapping& frame_sink_source = 370 FrameSinkSourceMapping& frame_sink_source =
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 std::vector<SurfaceId> children(iter->second.begin(), iter->second.end()); 612 std::vector<SurfaceId> children(iter->second.begin(), iter->second.end());
627 std::sort(children.begin(), children.end()); 613 std::sort(children.begin(), children.end());
628 614
629 for (const SurfaceId& child_id : children) 615 for (const SurfaceId& child_id : children)
630 SurfaceReferencesToStringImpl(child_id, indent + " ", str); 616 SurfaceReferencesToStringImpl(child_id, indent + " ", str);
631 } 617 }
632 } 618 }
633 #endif // DCHECK_IS_ON() 619 #endif // DCHECK_IS_ON()
634 620
635 } // namespace cc 621 } // namespace cc
OLDNEW
« no previous file with comments | « cc/surfaces/surface_manager.h ('k') | cc/surfaces/surface_manager_ref_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698