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 base::AutoLock auto_lock(order_fence_queue_lock_); | |
40 while (!order_fence_queue_.empty()) { | |
41 order_fence_queue_.pop(); | |
42 } | |
43 } | |
44 | |
45 uint32_t SyncPointOrderData::GenerateUnprocessedOrderNumber( | |
22 SyncPointManager* sync_point_manager) { | 46 SyncPointManager* sync_point_manager) { |
23 const uint32_t order_num = sync_point_manager->GenerateOrderNumber(); | 47 const uint32_t order_num = sync_point_manager->GenerateOrderNumber(); |
24 base::subtle::Release_Store(&unprocessed_order_num_, order_num); | 48 base::subtle::Release_Store(&unprocessed_order_num_, order_num); |
25 return order_num; | 49 return order_num; |
26 } | 50 } |
27 | 51 |
28 SyncPointClientState::SyncPointClientState() | 52 void SyncPointOrderData::BeginProcessingOrderNumber(uint32_t order_num) { |
53 DCHECK(processing_thread_checker_.CalledOnValidThread()); | |
54 DCHECK_GE(order_num, current_order_num_); | |
55 current_order_num_ = order_num; | |
56 } | |
57 | |
58 void SyncPointOrderData::FinishProcessingOrderNumber(uint32_t order_num) { | |
59 DCHECK(processing_thread_checker_.CalledOnValidThread()); | |
60 DCHECK_EQ(current_order_num_, order_num); | |
61 DCHECK_GT(order_num, processed_order_num()); | |
62 | |
63 // Catch invalid waits which were waiting on fence syncs that do not exist. | |
64 // Release without the lock to avoid possible deadlocks. | |
65 std::vector<OrderFence> ensure_releases; | |
66 { | |
67 base::AutoLock auto_lock(order_fence_queue_lock_); | |
68 while (!order_fence_queue_.empty()) { | |
69 const OrderFence& order_fence = order_fence_queue_.top(); | |
70 if (order_fence_queue_.top().order_num <= order_num) { | |
71 ensure_releases.push_back(order_fence); | |
72 order_fence_queue_.pop(); | |
73 continue; | |
74 } | |
75 break; | |
76 } | |
77 } | |
78 for (OrderFence& order_fence : ensure_releases) { | |
79 order_fence.client_state->EnsureReleased(order_fence.fence_release); | |
80 } | |
81 | |
82 base::subtle::Release_Store(&processed_order_num_, order_num); | |
piman
2015/09/30 22:50:23
This should happen before we do the EnsureReleased
David Yen
2015/09/30 23:55:18
That is true, in that case even the release counts
| |
83 } | |
84 | |
85 SyncPointOrderData::OrderFence::OrderFence( | |
86 uint32_t order, uint64_t release, scoped_refptr<SyncPointClientState> state) | |
87 : order_num(order), | |
88 fence_release(release), | |
89 client_state(state) { | |
90 } | |
91 | |
92 SyncPointOrderData::OrderFence::~OrderFence() { | |
93 } | |
94 | |
95 SyncPointOrderData::SyncPointOrderData() | |
29 : processed_order_num_(0), | 96 : processed_order_num_(0), |
30 unprocessed_order_num_(0), | 97 unprocessed_order_num_(0), |
31 current_order_num_(0) { | 98 current_order_num_(0) { |
32 } | 99 } |
33 | 100 |
101 SyncPointOrderData::~SyncPointOrderData() { | |
102 } | |
103 | |
104 void SyncPointOrderData::AddOrderFenceGuard( | |
105 uint32_t order_num, uint64_t fence_release, | |
106 scoped_refptr<SyncPointClientState> client_state) { | |
107 base::AutoLock auto_lock(order_fence_queue_lock_); | |
108 order_fence_queue_.push(OrderFence(order_num, fence_release, client_state)); | |
109 } | |
110 | |
111 SyncPointClientState::ReleaseCallback::ReleaseCallback( | |
112 uint64_t release, const base::Closure& callback) | |
113 : release_count(release), | |
114 callback_closure(callback) { | |
115 } | |
116 | |
117 SyncPointClientState::ReleaseCallback::~ReleaseCallback() { | |
118 } | |
119 | |
120 SyncPointClientState::SyncPointClientState( | |
121 scoped_refptr<SyncPointOrderData> order_data) | |
122 : order_data_(order_data), | |
123 fence_sync_release_(0) { | |
124 } | |
125 | |
34 SyncPointClientState::~SyncPointClientState() { | 126 SyncPointClientState::~SyncPointClientState() { |
35 } | 127 } |
36 | 128 |
129 bool SyncPointClientState::WaitForRelease(uint32_t wait_order_num, | |
130 uint64_t release, | |
131 const base::Closure& callback) { | |
132 // Lock must be held the whole time while we validate otherwise it could be | |
133 // released while we are checking. | |
134 { | |
135 base::AutoLock auto_lock(fence_sync_lock_); | |
136 if (release > fence_sync_release_) { | |
137 const uint32_t processed_num = order_data_->processed_order_num(); | |
138 const uint32_t unprocessed_num = order_data_->unprocessed_order_num(); | |
139 | |
140 // Release should have a possible unprocessed order number lower | |
141 // than the wait order number. | |
142 if ((processed_num + 1) >= wait_order_num) | |
piman
2015/09/30 22:50:23
I think this should be processed_num >= wait_order
David Yen
2015/09/30 23:55:18
This is a bit tricky and I only found it after wri
piman
2015/10/01 01:00:23
Ok, I think I convinced myself of why, but I think
David Yen
2015/10/01 17:15:51
Ah, that is a tricky case. I think we actually did
| |
143 return false; | |
144 | |
145 // Release should have more unprocessed numbers if we are waiting. | |
146 if (unprocessed_num <= processed_num) | |
147 return false; | |
148 | |
149 // Add the callback which will be called upon release. | |
150 release_callback_queue_.push(ReleaseCallback(release, callback)); | |
151 | |
152 // Validate by ensuring fence is released by the expected order number. | |
153 const uint32_t expected_order_num = std::min(unprocessed_num, | |
154 wait_order_num); | |
155 order_data_->AddOrderFenceGuard(expected_order_num, release, this); | |
156 return true; | |
157 } | |
158 } | |
159 | |
160 // Already released, run the callback now. | |
161 callback.Run(); | |
162 return true; | |
163 } | |
164 | |
165 void SyncPointClientState::ReleaseFenceSync(uint64_t release) { | |
166 // Call callbacks without the lock to avoid possible deadlocks. | |
167 std::vector<base::Closure> callback_list; | |
168 { | |
169 base::AutoLock auto_lock(fence_sync_lock_); | |
170 ReleaseFenceSyncLocked(release, &callback_list); | |
171 } | |
172 | |
173 for (const base::Closure& closure : callback_list) { | |
174 closure.Run(); | |
175 } | |
176 } | |
177 | |
178 void SyncPointClientState::EnsureReleased(uint64_t release) { | |
179 // Call callbacks without the lock to avoid possible deadlocks. | |
180 std::vector<base::Closure> callback_list; | |
181 { | |
182 base::AutoLock auto_lock(fence_sync_lock_); | |
183 if (release <= fence_sync_release_) | |
184 return; | |
185 | |
186 ReleaseFenceSyncLocked(release, &callback_list); | |
187 } | |
188 | |
189 for (const base::Closure& closure : callback_list) { | |
190 closure.Run(); | |
191 } | |
192 } | |
193 | |
194 void SyncPointClientState::ReleaseFenceSyncLocked( | |
195 uint64_t release, std::vector<base::Closure>* callback_list) { | |
196 fence_sync_lock_.AssertAcquired(); | |
197 DCHECK_GT(release, fence_sync_release_); | |
198 | |
199 fence_sync_release_ = release; | |
200 while (!release_callback_queue_.empty() && | |
201 release_callback_queue_.top().release_count <= release) { | |
202 callback_list->push_back(release_callback_queue_.top().callback_closure); | |
203 release_callback_queue_.pop(); | |
204 } | |
205 } | |
206 | |
37 SyncPointClient::~SyncPointClient() { | 207 SyncPointClient::~SyncPointClient() { |
208 // Release all fences on destruction. | |
209 ReleaseFenceSync(UINT64_MAX); | |
210 | |
38 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); | 211 sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); |
39 } | 212 } |
40 | 213 |
214 bool SyncPointClient::Wait(scoped_refptr<SyncPointClientState> release_state, | |
215 uint64_t release_count, | |
216 const base::Closure& wait_complete_callback) { | |
217 const uint32_t wait_order_number = | |
218 client_state_->order_data()->current_order_num(); | |
219 return release_state->WaitForRelease(wait_order_number, | |
220 release_count, | |
221 wait_complete_callback); | |
222 } | |
223 | |
224 bool SyncPointClient::WaitNonThreadSafe( | |
225 scoped_refptr<SyncPointClientState> release_state, | |
226 uint64_t release_count, | |
227 scoped_refptr<base::SingleThreadTaskRunner> runner, | |
228 const base::Closure& wait_complete_callback) { | |
229 return Wait(release_state, | |
230 release_count, | |
231 base::Bind(&RunOnThread, runner, wait_complete_callback)); | |
232 } | |
233 | |
234 void SyncPointClient::ReleaseFenceSync(uint64_t release) { | |
235 client_state_->ReleaseFenceSync(release); | |
236 } | |
237 | |
41 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, | 238 SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, |
42 scoped_refptr<SyncPointClientState> state, | 239 scoped_refptr<SyncPointOrderData> order_data, |
43 CommandBufferNamespace namespace_id, | 240 CommandBufferNamespace namespace_id, |
44 uint64_t client_id) | 241 uint64_t client_id) |
45 : sync_point_manager_(sync_point_manager), | 242 : sync_point_manager_(sync_point_manager), |
46 client_state_(state), | 243 client_state_(new SyncPointClientState(order_data)), |
47 namespace_id_(namespace_id), | 244 namespace_id_(namespace_id), |
48 client_id_(client_id) { | 245 client_id_(client_id) { |
49 } | 246 } |
50 | 247 |
51 SyncPointManager::SyncPointManager(bool allow_threaded_wait) | 248 SyncPointManager::SyncPointManager(bool allow_threaded_wait) |
52 : allow_threaded_wait_(allow_threaded_wait), | 249 : allow_threaded_wait_(allow_threaded_wait), |
53 // To reduce the risk that a sync point created in a previous GPU process | 250 // 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 | 251 // will be in flight in the next GPU process, randomize the starting sync |
55 // point number. http://crbug.com/373452 | 252 // point number. http://crbug.com/373452 |
56 next_sync_point_(base::RandInt(1, kMaxSyncBase)), | 253 next_sync_point_(base::RandInt(1, kMaxSyncBase)), |
57 retire_cond_var_(&lock_) { | 254 retire_cond_var_(&lock_) { |
58 global_order_num_.GetNext(); | 255 global_order_num_.GetNext(); |
59 } | 256 } |
60 | 257 |
61 SyncPointManager::~SyncPointManager() { | 258 SyncPointManager::~SyncPointManager() { |
62 for (const ClientMap& client_map : client_maps_) { | 259 for (const ClientMap& client_map : client_maps_) { |
63 DCHECK(client_map.empty()); | 260 DCHECK(client_map.empty()); |
64 } | 261 } |
65 } | 262 } |
66 | 263 |
67 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( | 264 scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( |
68 scoped_refptr<SyncPointClientState> client_state, | 265 scoped_refptr<SyncPointOrderData> order_data, |
69 CommandBufferNamespace namespace_id, uint64_t client_id) { | 266 CommandBufferNamespace namespace_id, uint64_t client_id) { |
70 DCHECK_GE(namespace_id, 0); | 267 DCHECK_GE(namespace_id, 0); |
71 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); | 268 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
72 base::AutoLock auto_lock(client_maps_lock_); | 269 base::AutoLock auto_lock(client_maps_lock_); |
73 | 270 |
74 ClientMap& client_map = client_maps_[namespace_id]; | 271 ClientMap& client_map = client_maps_[namespace_id]; |
75 std::pair<ClientMap::iterator, bool> result = client_map.insert( | 272 std::pair<ClientMap::iterator, bool> result = client_map.insert( |
76 std::make_pair(client_id, new SyncPointClient(this, | 273 std::make_pair(client_id, new SyncPointClient(this, |
77 client_state, | 274 order_data, |
78 namespace_id, | 275 namespace_id, |
79 client_id))); | 276 client_id))); |
80 DCHECK(result.second); | 277 DCHECK(result.second); |
81 | 278 |
82 return make_scoped_ptr(result.first->second); | 279 return make_scoped_ptr(result.first->second); |
83 } | 280 } |
84 | 281 |
85 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( | 282 scoped_refptr<SyncPointClientState> SyncPointManager::GetSyncPointClientState( |
86 CommandBufferNamespace namespace_id, uint64_t client_id) { | 283 CommandBufferNamespace namespace_id, uint64_t client_id) { |
87 DCHECK_GE(namespace_id, 0); | 284 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_)); | 374 DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
178 | 375 |
179 base::AutoLock auto_lock(client_maps_lock_); | 376 base::AutoLock auto_lock(client_maps_lock_); |
180 ClientMap& client_map = client_maps_[namespace_id]; | 377 ClientMap& client_map = client_maps_[namespace_id]; |
181 ClientMap::iterator it = client_map.find(client_id); | 378 ClientMap::iterator it = client_map.find(client_id); |
182 DCHECK(it != client_map.end()); | 379 DCHECK(it != client_map.end()); |
183 client_map.erase(it); | 380 client_map.erase(it); |
184 } | 381 } |
185 | 382 |
186 } // namespace gpu | 383 } // namespace gpu |
OLD | NEW |