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; |
32 } | 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()) { |
| 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, |
| 119 uint64_t release, |
| 120 scoped_refptr<SyncPointClientState> state) |
| 121 : order_num(order), fence_release(release), client_state(state) {} |
| 122 |
| 123 SyncPointOrderData::OrderFence::~OrderFence() {} |
| 124 |
| 125 SyncPointOrderData::SyncPointOrderData() |
| 126 : current_order_num_(0), |
| 127 destroyed_(false), |
| 128 processed_order_num_(0), |
| 129 unprocessed_order_num_(0) {} |
| 130 |
| 131 SyncPointOrderData::~SyncPointOrderData() {} |
| 132 |
| 133 bool SyncPointOrderData::ValidateReleaseOrderNumber( |
| 134 scoped_refptr<SyncPointClientState> client_state, |
| 135 uint32_t wait_order_num, |
| 136 uint64_t fence_release) { |
| 137 base::AutoLock auto_lock(lock_); |
| 138 if (destroyed_) |
| 139 return false; |
| 140 |
| 141 // Release should have a possible unprocessed order number lower |
| 142 // than the wait order number. |
| 143 if ((processed_order_num_ + 1) >= wait_order_num) |
| 144 return false; |
| 145 |
| 146 // Release should have more unprocessed numbers if we are waiting. |
| 147 if (unprocessed_order_num_ <= processed_order_num_) |
| 148 return false; |
| 149 |
| 150 // So far it could be valid, but add an order fence guard to be sure it |
| 151 // gets released eventually. |
| 152 const uint32_t expected_order_num = |
| 153 std::min(unprocessed_order_num_, wait_order_num); |
| 154 order_fence_queue_.push( |
| 155 OrderFence(expected_order_num, fence_release, client_state)); |
| 156 return true; |
| 157 } |
| 158 |
| 159 SyncPointClientState::ReleaseCallback::ReleaseCallback( |
| 160 uint64_t release, |
| 161 const base::Closure& callback) |
| 162 : release_count(release), callback_closure(callback) {} |
| 163 |
| 164 SyncPointClientState::ReleaseCallback::~ReleaseCallback() {} |
| 165 |
| 166 SyncPointClientState::SyncPointClientState( |
| 167 scoped_refptr<SyncPointOrderData> order_data) |
| 168 : order_data_(order_data), fence_sync_release_(0) {} |
33 | 169 |
34 SyncPointClientState::~SyncPointClientState() { | 170 SyncPointClientState::~SyncPointClientState() { |
35 } | 171 } |
36 | 172 |
| 173 bool SyncPointClientState::WaitForRelease(uint32_t wait_order_num, |
| 174 uint64_t release, |
| 175 const base::Closure& callback) { |
| 176 // Lock must be held the whole time while we validate otherwise it could be |
| 177 // released while we are checking. |
| 178 { |
| 179 base::AutoLock auto_lock(fence_sync_lock_); |
| 180 if (release > fence_sync_release_) { |
| 181 if (!order_data_->ValidateReleaseOrderNumber(this, wait_order_num, |
| 182 release)) { |
| 183 return false; |
| 184 } else { |
| 185 // Add the callback which will be called upon release. |
| 186 release_callback_queue_.push(ReleaseCallback(release, callback)); |
| 187 return true; |
| 188 } |
| 189 } |
| 190 } |
| 191 |
| 192 // Already released, run the callback now. |
| 193 callback.Run(); |
| 194 return true; |
| 195 } |
| 196 |
| 197 void SyncPointClientState::ReleaseFenceSync(uint64_t release) { |
| 198 // Call callbacks without the lock to avoid possible deadlocks. |
| 199 std::vector<base::Closure> callback_list; |
| 200 { |
| 201 base::AutoLock auto_lock(fence_sync_lock_); |
| 202 ReleaseFenceSyncLocked(release, &callback_list); |
| 203 } |
| 204 |
| 205 for (const base::Closure& closure : callback_list) { |
| 206 closure.Run(); |
| 207 } |
| 208 } |
| 209 |
| 210 void SyncPointClientState::EnsureReleased(uint64_t release) { |
| 211 // Call callbacks without the lock to avoid possible deadlocks. |
| 212 std::vector<base::Closure> callback_list; |
| 213 { |
| 214 base::AutoLock auto_lock(fence_sync_lock_); |
| 215 if (release <= fence_sync_release_) |
| 216 return; |
| 217 |
| 218 ReleaseFenceSyncLocked(release, &callback_list); |
| 219 } |
| 220 |
| 221 for (const base::Closure& closure : callback_list) { |
| 222 closure.Run(); |
| 223 } |
| 224 } |
| 225 |
| 226 void SyncPointClientState::ReleaseFenceSyncLocked( |
| 227 uint64_t release, |
| 228 std::vector<base::Closure>* callback_list) { |
| 229 fence_sync_lock_.AssertAcquired(); |
| 230 DCHECK_GT(release, fence_sync_release_); |
| 231 |
| 232 fence_sync_release_ = release; |
| 233 while (!release_callback_queue_.empty() && |
| 234 release_callback_queue_.top().release_count <= release) { |
| 235 callback_list->push_back(release_callback_queue_.top().callback_closure); |
| 236 release_callback_queue_.pop(); |
| 237 } |
| 238 } |
| 239 |
37 SyncPointClient::~SyncPointClient() { | 240 SyncPointClient::~SyncPointClient() { |
| 241 // Release all fences on destruction. |
| 242 ReleaseFenceSync(UINT64_MAX); |
| 243 |
38 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); | 244 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); |
39 } | 245 } |
40 | 246 |
| 247 bool SyncPointClient::Wait(SyncPointClientState* release_state, |
| 248 uint64_t release_count, |
| 249 const base::Closure& wait_complete_callback) { |
| 250 const uint32_t wait_order_number = |
| 251 client_state_->order_data()->current_order_num(); |
| 252 |
| 253 // If waiting on self or wait was invalid, call the callback and return false. |
| 254 if (client_state_ == release_state || |
| 255 !release_state->WaitForRelease(wait_order_number, release_count, |
| 256 wait_complete_callback)) { |
| 257 wait_complete_callback.Run(); |
| 258 return false; |
| 259 } |
| 260 return true; |
| 261 } |
| 262 |
| 263 bool SyncPointClient::WaitNonThreadSafe( |
| 264 SyncPointClientState* release_state, |
| 265 uint64_t release_count, |
| 266 scoped_refptr<base::SingleThreadTaskRunner> runner, |
| 267 const base::Closure& wait_complete_callback) { |
| 268 return Wait(release_state, release_count, |
| 269 base::Bind(&RunOnThread, runner, wait_complete_callback)); |
| 270 } |
| 271 |
| 272 void SyncPointClient::ReleaseFenceSync(uint64_t release) { |
| 273 client_state_->ReleaseFenceSync(release); |
| 274 } |
| 275 |
41 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, | 276 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, |
42 scoped_refptr<SyncPointClientState> state, | 277 scoped_refptr<SyncPointOrderData> order_data, |
43 CommandBufferNamespace namespace_id, | 278 CommandBufferNamespace namespace_id, |
44 uint64_t client_id) | 279 uint64_t client_id) |
45 : sync_point_manager_(sync_point_manager), | 280 : sync_point_manager_(sync_point_manager), |
46 client_state_(state), | 281 client_state_(new SyncPointClientState(order_data)), |
47 namespace_id_(namespace_id), | 282 namespace_id_(namespace_id), |
48 client_id_(client_id) { | 283 client_id_(client_id) {} |
49 } | |
50 | 284 |
51 SyncPointManager::SyncPointManager(bool allow_threaded_wait) | 285 SyncPointManager::SyncPointManager(bool allow_threaded_wait) |
52 : allow_threaded_wait_(allow_threaded_wait), | 286 : allow_threaded_wait_(allow_threaded_wait), |
53 // To reduce the risk that a sync point created in a previous GPU process | 287 // 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 | 288 // will be in flight in the next GPU process, randomize the starting sync |
55 // point number. http://crbug.com/373452 | 289 // point number. http://crbug.com/373452 |
56 next_sync_point_(base::RandInt(1, kMaxSyncBase)), | 290 next_sync_point_(base::RandInt(1, kMaxSyncBase)), |
57 retire_cond_var_(&lock_) { | 291 retire_cond_var_(&lock_) { |
58 global_order_num_.GetNext(); | 292 global_order_num_.GetNext(); |
59 } | 293 } |
60 | 294 |
61 SyncPointManager::~SyncPointManager() { | 295 SyncPointManager::~SyncPointManager() { |
62 for (const ClientMap& client_map : client_maps_) { | 296 for (const ClientMap& client_map : client_maps_) { |
63 DCHECK(client_map.empty()); | 297 DCHECK(client_map.empty()); |
64 } | 298 } |
65 } | 299 } |
66 | 300 |
67 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( | 301 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( |
68 scoped_refptr<SyncPointClientState> client_state, | 302 scoped_refptr<SyncPointOrderData> order_data, |
69 CommandBufferNamespace namespace_id, uint64_t client_id) { | 303 CommandBufferNamespace namespace_id, |
| 304 uint64_t client_id) { |
70 DCHECK_GE(namespace_id, 0); | 305 DCHECK_GE(namespace_id, 0); |
71 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 306 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
72 base::AutoLock auto_lock(client_maps_lock_); | 307 base::AutoLock auto_lock(client_maps_lock_); |
73 | 308 |
74 ClientMap& client_map = client_maps_[namespace_id]; | 309 ClientMap& client_map = client_maps_[namespace_id]; |
75 std::pair<ClientMap::iterator, bool> result = client_map.insert( | 310 std::pair<ClientMap::iterator, bool> result = client_map.insert( |
76 std::make_pair(client_id, new SyncPointClient(this, | 311 std::make_pair(client_id, new SyncPointClient(this, order_data, |
77 client_state, | 312 namespace_id, client_id))); |
78 namespace_id, | |
79 client_id))); | |
80 DCHECK(result.second); | 313 DCHECK(result.second); |
81 | 314 |
82 return make_scoped_ptr(result.first->second); | 315 return make_scoped_ptr(result.first->second); |
83 } | 316 } |
84 | 317 |
85 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( | 318 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( |
86 CommandBufferNamespace namespace_id, uint64_t client_id) { | 319 CommandBufferNamespace namespace_id, uint64_t client_id) { |
87 DCHECK_GE(namespace_id, 0); | 320 DCHECK_GE(namespace_id, 0); |
88 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 321 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
89 base::AutoLock auto_lock(client_maps_lock_); | 322 base::AutoLock auto_lock(client_maps_lock_); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 410 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
178 | 411 |
179 base::AutoLock auto_lock(client_maps_lock_); | 412 base::AutoLock auto_lock(client_maps_lock_); |
180 ClientMap& client_map = client_maps_[namespace_id]; | 413 ClientMap& client_map = client_maps_[namespace_id]; |
181 ClientMap::iterator it = client_map.find(client_id); | 414 ClientMap::iterator it = client_map.find(client_id); |
182 DCHECK(it != client_map.end()); | 415 DCHECK(it != client_map.end()); |
183 client_map.erase(it); | 416 client_map.erase(it); |
184 } | 417 } |
185 | 418 |
186 } // namespace gpu | 419 } // namespace gpu |
OLD | NEW |