OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 "gpu/command_buffer/service/sync_point_manager.h" | 5 #include "gpu/command_buffer/service/sync_point_manager.h" |
6 | 6 |
7 #include <climits> | 7 #include <climits> |
8 | 8 |
9 #include "base/bind.h" | |
10 #include "base/containers/hash_tables.h" | |
11 #include "base/location.h" | |
9 #include "base/logging.h" | 12 #include "base/logging.h" |
10 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
11 #include "base/sequence_checker.h" | 14 #include "base/sequence_checker.h" |
15 #include "base/single_thread_task_runner.h" | |
12 | 16 |
13 namespace gpu { | 17 namespace gpu { |
14 | 18 |
15 static const int kMaxSyncBase = INT_MAX; | 19 static const int kMaxSyncBase = INT_MAX; |
16 | 20 |
17 scoped_refptr<SyncPointClientState> SyncPointClientState::Create() { | 21 namespace { |
18 return new SyncPointClientState; | 22 |
19 } | 23 void RunOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
20 | 24 const base::Closure& callback) { |
21 uint32_t SyncPointClientState::GenerateUnprocessedOrderNumber( | 25 if (task_runner->BelongsToCurrentThread()) { |
26 callback.Run(); | |
27 } else { | |
28 task_runner->PostTask(FROM_HERE, callback); | |
29 } | |
30 } | |
31 | |
32 } // namespace | |
33 | |
34 scoped_refptr<SyncPointOrderData> SyncPointOrderData::Create() { | |
35 return new SyncPointOrderData; | |
36 } | |
37 | |
38 void SyncPointOrderData::Destroy() { | |
39 // Because of circular references between the SyncPointOrderData and | |
40 // SyncPointClientState, we must remove the references on destroy. Releasing | |
41 // the fence syncs in the order fence queue would be redundant at this point | |
42 // because they are assumed to be released on the destruction of the | |
43 // SyncPointClient. | |
44 base::AutoLock auto_lock(lock_); | |
45 destroyed_ = true; | |
46 while (!order_fence_queue_.empty()) { | |
47 order_fence_queue_.pop(); | |
48 } | |
49 } | |
50 | |
51 uint32_t SyncPointOrderData::GenerateUnprocessedOrderNumber( | |
22 SyncPointManager* sync_point_manager) { | 52 SyncPointManager* sync_point_manager) { |
23 const uint32_t order_num = sync_point_manager->GenerateOrderNumber(); | 53 const uint32_t order_num = sync_point_manager->GenerateOrderNumber(); |
24 base::subtle::Release_Store(&unprocessed_order_num_, order_num); | 54 base::AutoLock auto_lock(lock_); |
55 unprocessed_order_num_ = order_num; | |
25 return order_num; | 56 return order_num; |
26 } | 57 } |
27 | 58 |
28 SyncPointClientState::SyncPointClientState() | 59 void SyncPointOrderData::BeginProcessingOrderNumber(uint32_t order_num) { |
29 : processed_order_num_(0), | 60 DCHECK(processing_thread_checker_.CalledOnValidThread()); |
30 unprocessed_order_num_(0), | 61 DCHECK_GE(order_num, current_order_num_); |
31 current_order_num_(0) { | 62 current_order_num_ = order_num; |
63 | |
64 // Catch invalid waits which were waiting on fence syncs that do not exist. | |
65 // When we begin processing an order number, we should release any fence | |
66 // syncs which were enqueued but the order number never existed. | |
67 // Release without the lock to avoid possible deadlocks. | |
68 std::vector<OrderFence> ensure_releases; | |
69 { | |
70 base::AutoLock auto_lock(lock_); | |
71 while (!order_fence_queue_.empty()) { | |
72 const OrderFence& order_fence = order_fence_queue_.top(); | |
73 if (order_fence_queue_.top().order_num < order_num) { | |
74 ensure_releases.push_back(order_fence); | |
75 order_fence_queue_.pop(); | |
76 continue; | |
77 } | |
78 break; | |
79 } | |
80 } | |
81 | |
82 for (OrderFence& order_fence : ensure_releases) { | |
83 order_fence.client_state->EnsureReleased(order_fence.fence_release); | |
84 } | |
85 } | |
86 | |
87 void SyncPointOrderData::FinishProcessingOrderNumber(uint32_t order_num) { | |
88 DCHECK(processing_thread_checker_.CalledOnValidThread()); | |
89 DCHECK_EQ(current_order_num_, order_num); | |
90 | |
91 // Catch invalid waits which were waiting on fence syncs that do not exist. | |
92 // When we end processing an order number, we should release any fence syncs | |
93 // which were suppose to be released during this order number. | |
94 // Release without the lock to avoid possible deadlocks. | |
95 std::vector<OrderFence> ensure_releases; | |
96 { | |
97 base::AutoLock auto_lock(lock_); | |
98 DCHECK_GT(order_num, processed_order_num_); | |
99 processed_order_num_ = order_num; | |
100 | |
101 while (!order_fence_queue_.empty()) { | |
piman
2015/10/01 17:58:16
Do we need this any more?
The only case not handle
David Yen
2015/10/01 18:12:00
The way I have come to understand these 2 cases is
David Yen
2015/10/01 18:56:32
I also added a check if a client is waiting on its
| |
102 const OrderFence& order_fence = order_fence_queue_.top(); | |
103 if (order_fence_queue_.top().order_num <= order_num) { | |
104 ensure_releases.push_back(order_fence); | |
105 order_fence_queue_.pop(); | |
106 continue; | |
107 } | |
108 break; | |
109 } | |
110 } | |
111 | |
112 for (OrderFence& order_fence : ensure_releases) { | |
113 order_fence.client_state->EnsureReleased(order_fence.fence_release); | |
114 } | |
115 } | |
116 | |
117 SyncPointOrderData::OrderFence::OrderFence( | |
118 uint32_t order, uint64_t release, scoped_refptr<SyncPointClientState> state) | |
119 : order_num(order), | |
120 fence_release(release), | |
121 client_state(state) { | |
122 } | |
123 | |
124 SyncPointOrderData::OrderFence::~OrderFence() { | |
125 } | |
126 | |
127 SyncPointOrderData::SyncPointOrderData() | |
128 : current_order_num_(0), | |
129 destroyed_(false), | |
130 processed_order_num_(0), | |
131 unprocessed_order_num_(0) { | |
132 } | |
133 | |
134 SyncPointOrderData::~SyncPointOrderData() { | |
135 } | |
136 | |
137 bool SyncPointOrderData::ValidateReleaseOrderNumber( | |
138 scoped_refptr<SyncPointClientState> client_state, | |
139 uint32_t wait_order_num, | |
140 uint64_t fence_release) { | |
141 base::AutoLock auto_lock(lock_); | |
142 if (destroyed_) | |
143 return false; | |
144 | |
145 // Release should have a possible unprocessed order number lower | |
146 // than the wait order number. | |
147 if ((processed_order_num_ + 1) >= wait_order_num) | |
148 return false; | |
149 | |
150 // Release should have more unprocessed numbers if we are waiting. | |
151 if (unprocessed_order_num_ <= processed_order_num_) | |
152 return false; | |
153 | |
154 // So far it could be valid, but add an order fence guard to be sure it | |
155 // gets released eventually. | |
156 const uint32_t expected_order_num = std::min(unprocessed_order_num_, | |
157 wait_order_num); | |
158 order_fence_queue_.push(OrderFence(expected_order_num, fence_release, | |
159 client_state)); | |
160 return true; | |
161 } | |
162 | |
163 SyncPointClientState::ReleaseCallback::ReleaseCallback( | |
164 uint64_t release, const base::Closure& callback) | |
165 : release_count(release), | |
166 callback_closure(callback) { | |
167 } | |
168 | |
169 SyncPointClientState::ReleaseCallback::~ReleaseCallback() { | |
170 } | |
171 | |
172 SyncPointClientState::SyncPointClientState( | |
173 scoped_refptr<SyncPointOrderData> order_data) | |
174 : order_data_(order_data), | |
175 fence_sync_release_(0) { | |
32 } | 176 } |
33 | 177 |
34 SyncPointClientState::~SyncPointClientState() { | 178 SyncPointClientState::~SyncPointClientState() { |
35 } | 179 } |
36 | 180 |
181 bool SyncPointClientState::WaitForRelease(uint32_t wait_order_num, | |
182 uint64_t release, | |
183 const base::Closure& callback) { | |
184 // Lock must be held the whole time while we validate otherwise it could be | |
185 // released while we are checking. | |
186 { | |
187 base::AutoLock auto_lock(fence_sync_lock_); | |
188 if (release > fence_sync_release_) { | |
189 if (!order_data_->ValidateReleaseOrderNumber(this, wait_order_num, | |
190 release)) { | |
191 return false; | |
192 } else { | |
193 // Add the callback which will be called upon release. | |
194 release_callback_queue_.push(ReleaseCallback(release, callback)); | |
195 return true; | |
196 } | |
197 } | |
198 } | |
199 | |
200 // Already released, run the callback now. | |
201 callback.Run(); | |
202 return true; | |
203 } | |
204 | |
205 void SyncPointClientState::ReleaseFenceSync(uint64_t release) { | |
206 // Call callbacks without the lock to avoid possible deadlocks. | |
207 std::vector<base::Closure> callback_list; | |
208 { | |
209 base::AutoLock auto_lock(fence_sync_lock_); | |
210 ReleaseFenceSyncLocked(release, &callback_list); | |
211 } | |
212 | |
213 for (const base::Closure& closure : callback_list) { | |
214 closure.Run(); | |
215 } | |
216 } | |
217 | |
218 void SyncPointClientState::EnsureReleased(uint64_t release) { | |
219 // Call callbacks without the lock to avoid possible deadlocks. | |
220 std::vector<base::Closure> callback_list; | |
221 { | |
222 base::AutoLock auto_lock(fence_sync_lock_); | |
223 if (release <= fence_sync_release_) | |
224 return; | |
225 | |
226 ReleaseFenceSyncLocked(release, &callback_list); | |
227 } | |
228 | |
229 for (const base::Closure& closure : callback_list) { | |
230 closure.Run(); | |
231 } | |
232 } | |
233 | |
234 void SyncPointClientState::ReleaseFenceSyncLocked( | |
235 uint64_t release, std::vector<base::Closure>* callback_list) { | |
236 fence_sync_lock_.AssertAcquired(); | |
237 DCHECK_GT(release, fence_sync_release_); | |
238 | |
239 fence_sync_release_ = release; | |
240 while (!release_callback_queue_.empty() && | |
241 release_callback_queue_.top().release_count <= release) { | |
242 callback_list->push_back(release_callback_queue_.top().callback_closure); | |
243 release_callback_queue_.pop(); | |
244 } | |
245 } | |
246 | |
37 SyncPointClient::~SyncPointClient() { | 247 SyncPointClient::~SyncPointClient() { |
248 // Release all fences on destruction. | |
249 ReleaseFenceSync(UINT64_MAX); | |
250 | |
38 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); | 251 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); |
39 } | 252 } |
40 | 253 |
254 bool SyncPointClient::Wait(scoped_refptr<SyncPointClientState> release_state, | |
255 uint64_t release_count, | |
256 const base::Closure& wait_complete_callback) { | |
257 const uint32_t wait_order_number = | |
258 client_state_->order_data()->current_order_num(); | |
259 return release_state->WaitForRelease(wait_order_number, | |
260 release_count, | |
261 wait_complete_callback); | |
262 } | |
263 | |
264 bool SyncPointClient::WaitNonThreadSafe( | |
265 scoped_refptr<SyncPointClientState> release_state, | |
266 uint64_t release_count, | |
267 scoped_refptr<base::SingleThreadTaskRunner> runner, | |
268 const base::Closure& wait_complete_callback) { | |
269 return Wait(release_state, | |
270 release_count, | |
271 base::Bind(&RunOnThread, runner, wait_complete_callback)); | |
272 } | |
273 | |
274 void SyncPointClient::ReleaseFenceSync(uint64_t release) { | |
275 client_state_->ReleaseFenceSync(release); | |
276 } | |
277 | |
41 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, | 278 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, |
42 scoped_refptr<SyncPointClientState> state, | 279 scoped_refptr<SyncPointOrderData> order_data, |
43 CommandBufferNamespace namespace_id, | 280 CommandBufferNamespace namespace_id, |
44 uint64_t client_id) | 281 uint64_t client_id) |
45 : sync_point_manager_(sync_point_manager), | 282 : sync_point_manager_(sync_point_manager), |
46 client_state_(state), | 283 client_state_(new SyncPointClientState(order_data)), |
47 namespace_id_(namespace_id), | 284 namespace_id_(namespace_id), |
48 client_id_(client_id) { | 285 client_id_(client_id) { |
49 } | 286 } |
50 | 287 |
51 SyncPointManager::SyncPointManager(bool allow_threaded_wait) | 288 SyncPointManager::SyncPointManager(bool allow_threaded_wait) |
52 : allow_threaded_wait_(allow_threaded_wait), | 289 : allow_threaded_wait_(allow_threaded_wait), |
53 // To reduce the risk that a sync point created in a previous GPU process | 290 // To reduce the risk that a sync point created in a previous GPU process |
54 // will be in flight in the next GPU process, randomize the starting sync | 291 // will be in flight in the next GPU process, randomize the starting sync |
55 // point number. http://crbug.com/373452 | 292 // point number. http://crbug.com/373452 |
56 next_sync_point_(base::RandInt(1, kMaxSyncBase)), | 293 next_sync_point_(base::RandInt(1, kMaxSyncBase)), |
57 retire_cond_var_(&lock_) { | 294 retire_cond_var_(&lock_) { |
58 global_order_num_.GetNext(); | 295 global_order_num_.GetNext(); |
59 } | 296 } |
60 | 297 |
61 SyncPointManager::~SyncPointManager() { | 298 SyncPointManager::~SyncPointManager() { |
62 for (const ClientMap& client_map : client_maps_) { | 299 for (const ClientMap& client_map : client_maps_) { |
63 DCHECK(client_map.empty()); | 300 DCHECK(client_map.empty()); |
64 } | 301 } |
65 } | 302 } |
66 | 303 |
67 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( | 304 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( |
68 scoped_refptr<SyncPointClientState> client_state, | 305 scoped_refptr<SyncPointOrderData> order_data, |
69 CommandBufferNamespace namespace_id, uint64_t client_id) { | 306 CommandBufferNamespace namespace_id, uint64_t client_id) { |
70 DCHECK_GE(namespace_id, 0); | 307 DCHECK_GE(namespace_id, 0); |
71 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 308 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
72 base::AutoLock auto_lock(client_maps_lock_); | 309 base::AutoLock auto_lock(client_maps_lock_); |
73 | 310 |
74 ClientMap& client_map = client_maps_[namespace_id]; | 311 ClientMap& client_map = client_maps_[namespace_id]; |
75 std::pair<ClientMap::iterator, bool> result = client_map.insert( | 312 std::pair<ClientMap::iterator, bool> result = client_map.insert( |
76 std::make_pair(client_id, new SyncPointClient(this, | 313 std::make_pair(client_id, new SyncPointClient(this, |
77 client_state, | 314 order_data, |
78 namespace_id, | 315 namespace_id, |
79 client_id))); | 316 client_id))); |
80 DCHECK(result.second); | 317 DCHECK(result.second); |
81 | 318 |
82 return make_scoped_ptr(result.first->second); | 319 return make_scoped_ptr(result.first->second); |
83 } | 320 } |
84 | 321 |
85 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( | 322 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( |
86 CommandBufferNamespace namespace_id, uint64_t client_id) { | 323 CommandBufferNamespace namespace_id, uint64_t client_id) { |
87 DCHECK_GE(namespace_id, 0); | 324 DCHECK_GE(namespace_id, 0); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 414 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
178 | 415 |
179 base::AutoLock auto_lock(client_maps_lock_); | 416 base::AutoLock auto_lock(client_maps_lock_); |
180 ClientMap& client_map = client_maps_[namespace_id]; | 417 ClientMap& client_map = client_maps_[namespace_id]; |
181 ClientMap::iterator it = client_map.find(client_id); | 418 ClientMap::iterator it = client_map.find(client_id); |
182 DCHECK(it != client_map.end()); | 419 DCHECK(it != client_map.end()); |
183 client_map.erase(it); | 420 client_map.erase(it); |
184 } | 421 } |
185 | 422 |
186 } // namespace gpu | 423 } // namespace gpu |
OLD | NEW |