| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |