Index: gpu/command_buffer/service/sync_point_manager.cc |
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc |
index 039e494de8b1d4bd5ea3df100c89ec10cb508690..ade353c7d260828347b7d95e18693bea924114fe 100644 |
--- a/gpu/command_buffer/service/sync_point_manager.cc |
+++ b/gpu/command_buffer/service/sync_point_manager.cc |
@@ -25,19 +25,136 @@ uint32_t SyncPointClientState::GenerateUnprocessedOrderNumber( |
return order_num; |
} |
+void SyncPointClientState::BeginProcessingOrderNumber(uint32_t order_num) { |
+ DCHECK(processing_thread_checker_.CalledOnValidThread()); |
+ DCHECK_GE(order_num, current_order_num_); |
+ current_order_num_ = order_num; |
+} |
+ |
+void SyncPointClientState::FinishProcessingOrderNumber(uint32_t order_num) { |
+ DCHECK(processing_thread_checker_.CalledOnValidThread()); |
+ DCHECK_EQ(current_order_num_, order_num); |
+ DCHECK_GT(order_num, processed_order_num()); |
+ |
+ // Catch invalid waits which were waiting on fence syncs that do not exist. |
+ uint32_t invalid_release = 0; |
+ { |
+ base::AutoLock auto_lock(fence_sync_lock_); |
+ uint32_t highest_wait_release = 0; |
+ while (!order_fence_queue_.empty() && |
+ order_fence_queue_.top().order_num <= order_num) { |
+ const uint32_t fence_release = order_fence_queue_.top().fence_release; |
+ highest_wait_release = std::max(highest_wait_release, fence_release); |
+ order_fence_queue_.pop(); |
+ } |
+ |
+ if (highest_wait_release > fence_sync_release_) { |
+ invalid_release = fence_sync_release_; |
+ } |
+ } |
+ |
+ if (invalid_release) { |
+ // Bad wait for release that doesn't exist, release all waits up to here. |
+ ReleaseFenceSync(invalid_release); |
+ } |
+ |
+ base::subtle::Release_Store(&processed_order_num_, order_num); |
+} |
+ |
SyncPointClientState::SyncPointClientState() |
: processed_order_num_(0), |
unprocessed_order_num_(0), |
- current_order_num_(0) { |
+ current_order_num_(0), |
+ fence_sync_release_(0) { |
} |
SyncPointClientState::~SyncPointClientState() { |
+ // Release all fences on destruction. |
+ ReleaseFenceSync(UINT32_MAX); |
+} |
+ |
+SyncPointClientState::ReleaseCallback::ReleaseCallback( |
+ uint32_t release, const base::Closure& callback) |
+ : release_count(release), |
+ callback_closure(callback) { |
+} |
+ |
+SyncPointClientState::ReleaseCallback::~ReleaseCallback() { |
+} |
+ |
+bool SyncPointClientState::WaitForRelease(uint32_t wait_order_num, |
+ uint32_t release, |
+ const base::Closure& callback) { |
+ // Lock must be held the whole time while we validate otherwise it could be |
+ // released while we are checking. |
+ { |
+ base::AutoLock auto_lock(fence_sync_lock_); |
+ if (release > fence_sync_release_) { |
+ const uint32_t processed_num = processed_order_num(); |
+ const uint32_t unprocessed_num = unprocessed_order_num(); |
+ |
+ // Release should have a lower order number than wait order number. |
+ if (processed_num > wait_order_num) |
+ return false; |
+ |
+ // Release should have more unprocessed numbers if we are waiting. |
+ if (unprocessed_num > processed_num) |
+ return false; |
+ |
+ // Add the callback which will be called upon release. |
+ release_callback_queue_.push(ReleaseCallback(release, callback)); |
+ |
+ // Validate by ensuring fence is released by the expected order number. |
+ const uint32_t expected_order_num = std::min(unprocessed_num, |
+ wait_order_num); |
+ order_fence_queue_.push(OrderFence(expected_order_num, release)); |
+ |
+ return true; |
+ } |
+ } |
+ |
+ // Already released, run the callback now. |
+ callback.Run(); |
+ return true; |
+} |
+ |
+void SyncPointClientState::ReleaseFenceSync(uint32_t release) { |
+ // Call callbacks without the lock to avoid possible deadlocks. |
+ std::vector<base::Closure> callback_list; |
+ { |
+ base::AutoLock auto_lock(fence_sync_lock_); |
+ DCHECK_GT(release, fence_sync_release_); |
+ fence_sync_release_ = release; |
+ |
+ while (!release_callback_queue_.empty() && |
+ release_callback_queue_.top().release_count <= release) { |
+ callback_list.push_back(release_callback_queue_.top().callback_closure); |
+ release_callback_queue_.pop(); |
+ } |
+ } |
+ |
+ for (const base::Closure& closure : callback_list) { |
+ closure.Run(); |
+ } |
} |
SyncPointClient::~SyncPointClient() { |
sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); |
} |
+bool SyncPointClient::Wait(scoped_refptr<SyncPointClientState> release_state, |
+ uint32_t release_count, |
+ const base::Closure& wait_complete_callback) { |
+ const uint32_t wait_order_number = client_state_->current_order_num(); |
+ return release_state->WaitForRelease(wait_order_number, |
+ release_count, |
+ wait_complete_callback); |
+} |
+ |
+void SyncPointClient::ReleaseFenceSync(uint32_t release) { |
+ client_state_->ReleaseFenceSync(release); |
+} |
+ |
SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, |
scoped_refptr<SyncPointClientState> state, |
CommandBufferNamespace namespace_id, |