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

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

Issue 2455663003: Add cc::Surface ref counting. (Closed)
Patch Set: Address CL comments. Created 4 years, 1 month 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 <utility>
11
10 #include "base/logging.h" 12 #include "base/logging.h"
11 #include "cc/surfaces/surface.h" 13 #include "cc/surfaces/surface.h"
12 #include "cc/surfaces/surface_factory_client.h" 14 #include "cc/surfaces/surface_factory_client.h"
13 #include "cc/surfaces/surface_id_allocator.h" 15 #include "cc/surfaces/surface_id_allocator.h"
14 16
15 namespace cc { 17 namespace cc {
18 namespace {
19
20 // Copies contents of |set| so we can iterate over them while removing entries
21 // from |set| without worrying about iterator invalidation.
22 std::vector<SurfaceId> CopySurfaceIds(const SurfaceManager::SurfaceIdSet& set) {
23 return std::vector<SurfaceId>(set.begin(), set.end());
24 }
25
26 } // namespace
16 27
17 SurfaceManager::FrameSinkSourceMapping::FrameSinkSourceMapping() 28 SurfaceManager::FrameSinkSourceMapping::FrameSinkSourceMapping()
18 : client(nullptr), source(nullptr) {} 29 : client(nullptr), source(nullptr) {}
19 30
20 SurfaceManager::FrameSinkSourceMapping::FrameSinkSourceMapping( 31 SurfaceManager::FrameSinkSourceMapping::FrameSinkSourceMapping(
21 const FrameSinkSourceMapping& other) = default; 32 const FrameSinkSourceMapping& other) = default;
22 33
23 SurfaceManager::FrameSinkSourceMapping::~FrameSinkSourceMapping() { 34 SurfaceManager::FrameSinkSourceMapping::~FrameSinkSourceMapping() {
24 DCHECK(is_empty()) << "client: " << client 35 DCHECK(is_empty()) << "client: " << client
25 << ", children: " << children.size(); 36 << ", children: " << children.size();
(...skipping 23 matching lines...) Expand all
49 DCHECK(surface); 60 DCHECK(surface);
50 DCHECK(!surface_map_.count(surface->surface_id())); 61 DCHECK(!surface_map_.count(surface->surface_id()));
51 surface_map_[surface->surface_id()] = surface; 62 surface_map_[surface->surface_id()] = surface;
52 } 63 }
53 64
54 void SurfaceManager::DeregisterSurface(const SurfaceId& surface_id) { 65 void SurfaceManager::DeregisterSurface(const SurfaceId& surface_id) {
55 DCHECK(thread_checker_.CalledOnValidThread()); 66 DCHECK(thread_checker_.CalledOnValidThread());
56 SurfaceMap::iterator it = surface_map_.find(surface_id); 67 SurfaceMap::iterator it = surface_map_.find(surface_id);
57 DCHECK(it != surface_map_.end()); 68 DCHECK(it != surface_map_.end());
58 surface_map_.erase(it); 69 surface_map_.erase(it);
70 child_to_parent_refs_.erase(surface_id);
71 parent_to_child_refs_.erase(surface_id);
59 } 72 }
60 73
61 void SurfaceManager::Destroy(std::unique_ptr<Surface> surface) { 74 void SurfaceManager::Destroy(std::unique_ptr<Surface> surface) {
62 DCHECK(thread_checker_.CalledOnValidThread()); 75 DCHECK(thread_checker_.CalledOnValidThread());
63 surface->set_destroyed(true); 76 surface->set_destroyed(true);
64 surfaces_to_destroy_.push_back(std::move(surface)); 77 surfaces_to_destroy_.push_back(std::move(surface));
65 GarbageCollectSurfaces(); 78 GarbageCollectSurfaces();
66 } 79 }
67 80
68 void SurfaceManager::DidSatisfySequences(const FrameSinkId& frame_sink_id, 81 void SurfaceManager::DidSatisfySequences(const FrameSinkId& frame_sink_id,
69 std::vector<uint32_t>* sequence) { 82 std::vector<uint32_t>* sequence) {
70 DCHECK(thread_checker_.CalledOnValidThread()); 83 DCHECK(thread_checker_.CalledOnValidThread());
71 for (std::vector<uint32_t>::iterator it = sequence->begin(); 84 for (uint32_t value : *sequence) {
72 it != sequence->end(); 85 satisfied_sequences_.insert(SurfaceSequence(frame_sink_id, value));
73 ++it) {
74 satisfied_sequences_.insert(SurfaceSequence(frame_sink_id, *it));
75 } 86 }
76 sequence->clear(); 87 sequence->clear();
77 GarbageCollectSurfaces(); 88 GarbageCollectSurfaces();
78 } 89 }
79 90
80 void SurfaceManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id) { 91 void SurfaceManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id) {
81 bool inserted = valid_frame_sink_ids_.insert(frame_sink_id).second; 92 bool inserted = valid_frame_sink_ids_.insert(frame_sink_id).second;
82 DCHECK(inserted); 93 DCHECK(inserted);
83 } 94 }
84 95
85 void SurfaceManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) { 96 void SurfaceManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) {
86 valid_frame_sink_ids_.erase(frame_sink_id); 97 valid_frame_sink_ids_.erase(frame_sink_id);
87 GarbageCollectSurfaces(); 98 GarbageCollectSurfaces();
88 } 99 }
89 100
101 void SurfaceManager::AddSurfaceIdReference(const SurfaceId& parent_id,
102 const SurfaceId& child_id) {
103 DCHECK(thread_checker_.CalledOnValidThread());
104
105 // This should never happen but we don't want to DHCECK if we get bad input
106 // from a compromised client.
107 if (parent_id == child_id) {
108 LOG(ERROR) << "Cannot add self reference for " << parent_id.ToString();
109 return;
110 }
111
112 parent_to_child_refs_[parent_id].insert(child_id);
113 child_to_parent_refs_[child_id].insert(parent_id);
114
115 DCHECK_EQ(parent_to_child_refs_[parent_id].count(child_id), 1u);
116 DCHECK_EQ(child_to_parent_refs_[child_id].count(parent_id), 1u);
117 }
118
119 void SurfaceManager::RemoveSurfaceIdReference(const SurfaceId& parent_id,
120 const SurfaceId& child_id,
121 bool should_run_gc) {
122 DCHECK(thread_checker_.CalledOnValidThread());
123
124 // If the GPU process crashes a client could try to free an invalid surface.
125 if (parent_to_child_refs_.count(parent_id) == 0 ||
126 parent_to_child_refs_[parent_id].count(child_id) == 0) {
127 LOG(ERROR) << "No reference from " << parent_id.ToString() << " to "
128 << child_id.ToString();
129 return;
130 }
131
132 // Remove the reference from parent to child. This doesn't change anything
133 // about the validity of the parent.
134 parent_to_child_refs_[parent_id].erase(child_id);
135
136 // Remove the reference from child to parent. This might drop the number of
137 // references to the child to zero.
138 DCHECK_EQ(child_to_parent_refs_.count(child_id), 1u);
139 SurfaceIdSet& child_refs = child_to_parent_refs_[child_id];
140 DCHECK_EQ(child_refs.count(parent_id), 1u);
141 child_refs.erase(parent_id);
142
143 if (!child_refs.empty())
144 return;
145
146 // Remove any references the child holds before it gets garbage collected.
147 for (auto& surface_id : CopySurfaceIds(parent_to_child_refs_[child_id]))
148 RemoveSurfaceIdReference(child_id, surface_id, false);
149 DCHECK_EQ(GetSurfaceRefereeCount(child_id), 0u);
150
151 if (should_run_gc)
Fady Samuel 2016/11/02 03:10:36 nit: add a comment as to when you'd run gc?
152 GarbageCollectSurfaces();
153 }
154
155 void SurfaceManager::RemoveAllReferencesForFrameSink(
156 const FrameSinkId& frame_sink_id) {
157 // Find set of surfaces that belong to the FrameSink.
158 SurfaceIdSet frame_sink_surfaces;
159 for (auto& map_entry : parent_to_child_refs_) {
160 const SurfaceId& surface_id = map_entry.first;
161 if (surface_id.frame_sink_id() == frame_sink_id)
162 frame_sink_surfaces.insert(surface_id);
163 }
164 for (auto& map_entry : child_to_parent_refs_) {
165 const SurfaceId& surface_id = map_entry.first;
166 if (surface_id.frame_sink_id() == frame_sink_id)
167 frame_sink_surfaces.insert(surface_id);
168 }
169
170 // Clear all surface references belonging to FrameSink |frame_sink_id|.
171 for (const SurfaceId& surface_id : frame_sink_surfaces)
172 RemoveAllReferencesForSurfaceId(surface_id);
173 }
174
175 void SurfaceManager::RemoveAllReferencesForSurfaceId(
176 const SurfaceId& surface_id) {
177 // Remove any references from parents to this surface, since this surface
178 // no longer exists. This surface will have zero references when finished.
179 if (child_to_parent_refs_.count(surface_id) > 0) {
180 for (auto& parent_id : CopySurfaceIds(child_to_parent_refs_[surface_id]))
181 RemoveSurfaceIdReference(parent_id, surface_id);
182 }
183 DCHECK_EQ(GetSurfaceReferenceCount(surface_id), 0u);
184
185 // Remove any references from this surface to children, since this surface
186 // no longer exists. A child surface may drop to zero references here,
187 // recursively clearing any references the child surface holds.
188 if (parent_to_child_refs_.count(surface_id) > 0) {
189 for (auto& child_id : CopySurfaceIds(parent_to_child_refs_[surface_id]))
190 RemoveSurfaceIdReference(surface_id, child_id);
191 }
192 DCHECK_EQ(GetSurfaceRefereeCount(surface_id), 0u);
193 }
194
195 size_t SurfaceManager::GetSurfaceReferenceCount(
196 const SurfaceId& surface_id) const {
197 auto iter = child_to_parent_refs_.find(surface_id);
198 if (iter == child_to_parent_refs_.end())
199 return 0;
200 return iter->second.size();
201 }
202
203 size_t SurfaceManager::GetSurfaceRefereeCount(
204 const SurfaceId& surface_id) const {
205 auto iter = parent_to_child_refs_.find(surface_id);
206 if (iter == parent_to_child_refs_.end())
207 return 0;
208 return iter->second.size();
209 }
210
90 void SurfaceManager::GarbageCollectSurfaces() { 211 void SurfaceManager::GarbageCollectSurfaces() {
91 // Simple mark and sweep GC. 212 // Simple mark and sweep GC.
92 // TODO(jbauman): Reduce the amount of work when nothing needs to be 213 // TODO(jbauman): Reduce the amount of work when nothing needs to be
93 // destroyed. 214 // destroyed.
94 std::vector<SurfaceId> live_surfaces; 215 std::vector<SurfaceId> live_surfaces;
95 std::set<SurfaceId> live_surfaces_set; 216 std::unordered_set<SurfaceId, SurfaceIdHash> live_surfaces_set;
96 217
97 // GC roots are surfaces that have not been destroyed, or have not had all 218 // GC roots are surfaces that have not been destroyed, or have not had all
98 // their destruction dependencies satisfied. 219 // their destruction dependencies satisfied.
99 for (auto& map_entry : surface_map_) { 220 for (auto& map_entry : surface_map_) {
100 map_entry.second->SatisfyDestructionDependencies(&satisfied_sequences_, 221 const SurfaceId& surface_id = map_entry.first;
101 &valid_frame_sink_ids_); 222 Surface* surface = map_entry.second;
102 if (!map_entry.second->destroyed() || 223 surface->SatisfyDestructionDependencies(&satisfied_sequences_,
103 map_entry.second->GetDestructionDependencyCount()) { 224 &valid_frame_sink_ids_);
104 live_surfaces_set.insert(map_entry.first); 225
105 live_surfaces.push_back(map_entry.first); 226 // Never use both SurfaceSequence and Surface references.
227 DCHECK(surface->GetDestructionDependencyCount() == 0 ||
228 GetSurfaceReferenceCount(surface_id) == 0);
229
230 if (!surface->destroyed() || surface->GetDestructionDependencyCount() > 0 ||
231 GetSurfaceReferenceCount(surface_id) > 0) {
232 live_surfaces_set.insert(surface_id);
233 live_surfaces.push_back(surface_id);
106 } 234 }
107 } 235 }
108 236
109 // Mark all surfaces reachable from live surfaces by adding them to 237 // Mark all surfaces reachable from live surfaces by adding them to
110 // live_surfaces and live_surfaces_set. 238 // live_surfaces and live_surfaces_set.
111 for (size_t i = 0; i < live_surfaces.size(); i++) { 239 for (size_t i = 0; i < live_surfaces.size(); i++) {
112 Surface* surf = surface_map_[live_surfaces[i]]; 240 Surface* surf = surface_map_[live_surfaces[i]];
113 DCHECK(surf); 241 DCHECK(surf);
114 242
115 for (const SurfaceId& id : surf->referenced_surfaces()) { 243 for (const SurfaceId& id : surf->referenced_surfaces()) {
116 if (live_surfaces_set.count(id)) 244 if (live_surfaces_set.count(id))
117 continue; 245 continue;
118 246
119 Surface* surf2 = GetSurfaceForId(id); 247 Surface* surf2 = GetSurfaceForId(id);
120 if (surf2) { 248 if (surf2) {
121 live_surfaces.push_back(id); 249 live_surfaces.push_back(id);
122 live_surfaces_set.insert(id); 250 live_surfaces_set.insert(id);
123 } 251 }
124 } 252 }
125 } 253 }
126 254
127 std::vector<std::unique_ptr<Surface>> to_destroy; 255 std::vector<std::unique_ptr<Surface>> to_destroy;
128 256
129 // Destroy all remaining unreachable surfaces. 257 // Destroy all remaining unreachable surfaces.
130 for (SurfaceDestroyList::iterator dest_it = surfaces_to_destroy_.begin(); 258 for (auto iter = surfaces_to_destroy_.begin();
131 dest_it != surfaces_to_destroy_.end();) { 259 iter != surfaces_to_destroy_.end();) {
132 if (!live_surfaces_set.count((*dest_it)->surface_id())) { 260 SurfaceId surface_id = (*iter)->surface_id();
133 std::unique_ptr<Surface> surf(std::move(*dest_it)); 261 if (!live_surfaces_set.count(surface_id)) {
134 DeregisterSurface(surf->surface_id()); 262 DeregisterSurface(surface_id);
135 dest_it = surfaces_to_destroy_.erase(dest_it); 263 to_destroy.push_back(std::move(*iter));
136 to_destroy.push_back(std::move(surf)); 264 iter = surfaces_to_destroy_.erase(iter);
265 LOG(ERROR) << "GC destroyed " << surface_id.ToString();
137 } else { 266 } else {
138 ++dest_it; 267 ++iter;
139 } 268 }
140 } 269 }
141 270
142 to_destroy.clear(); 271 to_destroy.clear();
143 } 272 }
144 273
145 void SurfaceManager::RegisterSurfaceFactoryClient( 274 void SurfaceManager::RegisterSurfaceFactoryClient(
146 const FrameSinkId& frame_sink_id, 275 const FrameSinkId& frame_sink_id,
147 SurfaceFactoryClient* client) { 276 SurfaceFactoryClient* client) {
148 DCHECK(client); 277 DCHECK(client);
149 DCHECK(!frame_sink_source_map_[frame_sink_id].client);
150 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u); 278 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u);
151 279
152 auto iter = frame_sink_source_map_.find(frame_sink_id); 280 // Will create a new FrameSinkSourceMapping for |frame_sink_id| if necessary.
153 if (iter == frame_sink_source_map_.end()) { 281 FrameSinkSourceMapping& frame_sink_source =
154 auto insert_result = frame_sink_source_map_.insert( 282 frame_sink_source_map_[frame_sink_id];
155 std::make_pair(frame_sink_id, FrameSinkSourceMapping())); 283 DCHECK(!frame_sink_source.client);
156 DCHECK(insert_result.second); 284 frame_sink_source.client = client;
157 iter = insert_result.first;
158 }
159 iter->second.client = client;
160 285
161 // Propagate any previously set sources to the new client. 286 // Propagate any previously set sources to the new client.
162 if (iter->second.source) 287 if (frame_sink_source.source)
163 client->SetBeginFrameSource(iter->second.source); 288 client->SetBeginFrameSource(frame_sink_source.source);
164 } 289 }
165 290
166 void SurfaceManager::UnregisterSurfaceFactoryClient( 291 void SurfaceManager::UnregisterSurfaceFactoryClient(
167 const FrameSinkId& frame_sink_id) { 292 const FrameSinkId& frame_sink_id) {
168 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u); 293 DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u);
169 DCHECK_EQ(frame_sink_source_map_.count(frame_sink_id), 1u); 294 DCHECK_EQ(frame_sink_source_map_.count(frame_sink_id), 1u);
170 295
296 RemoveAllReferencesForFrameSink(frame_sink_id);
297
171 auto iter = frame_sink_source_map_.find(frame_sink_id); 298 auto iter = frame_sink_source_map_.find(frame_sink_id);
172 if (iter->second.source) 299 if (iter->second.source)
173 iter->second.client->SetBeginFrameSource(nullptr); 300 iter->second.client->SetBeginFrameSource(nullptr);
174 iter->second.client = nullptr; 301 iter->second.client = nullptr;
175 302
176 // The SurfaceFactoryClient and hierarchy can be registered/unregistered 303 // The SurfaceFactoryClient and hierarchy can be registered/unregistered
177 // in either order, so empty namespace_client_map entries need to be 304 // in either order, so empty namespace_client_map entries need to be
178 // checked when removing either clients or relationships. 305 // checked when removing either clients or relationships.
179 if (iter->second.is_empty()) 306 if (iter->second.is_empty())
180 frame_sink_source_map_.erase(iter); 307 frame_sink_source_map_.erase(iter);
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // TODO(enne): these walks could be done in one step. 458 // TODO(enne): these walks could be done in one step.
332 RecursivelyDetachBeginFrameSource(child_frame_sink_id, parent_source); 459 RecursivelyDetachBeginFrameSource(child_frame_sink_id, parent_source);
333 for (auto source_iter : registered_sources_) 460 for (auto source_iter : registered_sources_)
334 RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first); 461 RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first);
335 } 462 }
336 463
337 Surface* SurfaceManager::GetSurfaceForId(const SurfaceId& surface_id) { 464 Surface* SurfaceManager::GetSurfaceForId(const SurfaceId& surface_id) {
338 DCHECK(thread_checker_.CalledOnValidThread()); 465 DCHECK(thread_checker_.CalledOnValidThread());
339 SurfaceMap::iterator it = surface_map_.find(surface_id); 466 SurfaceMap::iterator it = surface_map_.find(surface_id);
340 if (it == surface_map_.end()) 467 if (it == surface_map_.end())
341 return NULL; 468 return nullptr;
342 return it->second; 469 return it->second;
343 } 470 }
344 471
345 bool SurfaceManager::SurfaceModified(const SurfaceId& surface_id) { 472 bool SurfaceManager::SurfaceModified(const SurfaceId& surface_id) {
346 CHECK(thread_checker_.CalledOnValidThread()); 473 CHECK(thread_checker_.CalledOnValidThread());
347 bool changed = false; 474 bool changed = false;
348 for (auto& observer : observer_list_) 475 for (auto& observer : observer_list_)
349 observer.OnSurfaceDamaged(surface_id, &changed); 476 observer.OnSurfaceDamaged(surface_id, &changed);
350 return changed; 477 return changed;
351 } 478 }
352 479
353 void SurfaceManager::SurfaceCreated(const SurfaceId& surface_id, 480 void SurfaceManager::SurfaceCreated(const SurfaceId& surface_id,
354 const gfx::Size& frame_size, 481 const gfx::Size& frame_size,
355 float device_scale_factor) { 482 float device_scale_factor) {
356 CHECK(thread_checker_.CalledOnValidThread()); 483 CHECK(thread_checker_.CalledOnValidThread());
357 for (auto& observer : observer_list_) 484 for (auto& observer : observer_list_)
358 observer.OnSurfaceCreated(surface_id, frame_size, device_scale_factor); 485 observer.OnSurfaceCreated(surface_id, frame_size, device_scale_factor);
359 } 486 }
360 487
361 } // namespace cc 488 } // 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