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..bc73adb2dacc4dd1d84b2ffcd8077e40b67f7da5 100644 |
--- a/gpu/command_buffer/service/sync_point_manager.cc |
+++ b/gpu/command_buffer/service/sync_point_manager.cc |
@@ -6,47 +6,281 @@ |
#include <climits> |
+#include "base/bind.h" |
+#include "base/containers/hash_tables.h" |
+#include "base/location.h" |
#include "base/logging.h" |
#include "base/rand_util.h" |
#include "base/sequence_checker.h" |
+#include "base/single_thread_task_runner.h" |
namespace gpu { |
static const int kMaxSyncBase = INT_MAX; |
-scoped_refptr<SyncPointClientState> SyncPointClientState::Create() { |
- return new SyncPointClientState; |
+namespace { |
+ |
+void RunOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
+ const base::Closure& callback) { |
+ if (task_runner->BelongsToCurrentThread()) { |
+ callback.Run(); |
+ } else { |
+ task_runner->PostTask(FROM_HERE, callback); |
+ } |
+} |
+ |
+} // namespace |
+ |
+scoped_refptr<SyncPointOrderData> SyncPointOrderData::Create() { |
+ return new SyncPointOrderData; |
} |
-uint32_t SyncPointClientState::GenerateUnprocessedOrderNumber( |
+void SyncPointOrderData::Destroy() { |
+ // Because of circular references between the SyncPointOrderData and |
+ // SyncPointClientState, we must remove the references on destroy. Releasing |
+ // the fence syncs in the order fence queue would be redundant at this point |
+ // because they are assumed to be released on the destruction of the |
+ // SyncPointClient. |
+ base::AutoLock auto_lock(lock_); |
+ destroyed_ = true; |
+ while (!order_fence_queue_.empty()) { |
+ order_fence_queue_.pop(); |
+ } |
+} |
+ |
+uint32_t SyncPointOrderData::GenerateUnprocessedOrderNumber( |
SyncPointManager* sync_point_manager) { |
const uint32_t order_num = sync_point_manager->GenerateOrderNumber(); |
- base::subtle::Release_Store(&unprocessed_order_num_, order_num); |
+ base::AutoLock auto_lock(lock_); |
+ unprocessed_order_num_ = order_num; |
return order_num; |
} |
-SyncPointClientState::SyncPointClientState() |
- : processed_order_num_(0), |
- unprocessed_order_num_(0), |
- current_order_num_(0) { |
+void SyncPointOrderData::BeginProcessingOrderNumber(uint32_t order_num) { |
+ DCHECK(processing_thread_checker_.CalledOnValidThread()); |
+ DCHECK_GE(order_num, current_order_num_); |
+ current_order_num_ = order_num; |
+ |
+ // Catch invalid waits which were waiting on fence syncs that do not exist. |
+ // When we begin processing an order number, we should release any fence |
+ // syncs which were enqueued but the order number never existed. |
+ // Release without the lock to avoid possible deadlocks. |
+ std::vector<OrderFence> ensure_releases; |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ while (!order_fence_queue_.empty()) { |
+ const OrderFence& order_fence = order_fence_queue_.top(); |
+ if (order_fence_queue_.top().order_num < order_num) { |
+ ensure_releases.push_back(order_fence); |
+ order_fence_queue_.pop(); |
+ continue; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ for (OrderFence& order_fence : ensure_releases) { |
+ order_fence.client_state->EnsureReleased(order_fence.fence_release); |
+ } |
} |
+void SyncPointOrderData::FinishProcessingOrderNumber(uint32_t order_num) { |
+ DCHECK(processing_thread_checker_.CalledOnValidThread()); |
+ DCHECK_EQ(current_order_num_, order_num); |
+ |
+ // Catch invalid waits which were waiting on fence syncs that do not exist. |
+ // When we end processing an order number, we should release any fence syncs |
+ // which were suppose to be released during this order number. |
+ // Release without the lock to avoid possible deadlocks. |
+ std::vector<OrderFence> ensure_releases; |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_GT(order_num, processed_order_num_); |
+ processed_order_num_ = order_num; |
+ |
+ while (!order_fence_queue_.empty()) { |
+ const OrderFence& order_fence = order_fence_queue_.top(); |
+ if (order_fence_queue_.top().order_num <= order_num) { |
+ ensure_releases.push_back(order_fence); |
+ order_fence_queue_.pop(); |
+ continue; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ for (OrderFence& order_fence : ensure_releases) { |
+ order_fence.client_state->EnsureReleased(order_fence.fence_release); |
+ } |
+} |
+ |
+SyncPointOrderData::OrderFence::OrderFence( |
+ uint32_t order, |
+ uint64_t release, |
+ scoped_refptr<SyncPointClientState> state) |
+ : order_num(order), fence_release(release), client_state(state) {} |
+ |
+SyncPointOrderData::OrderFence::~OrderFence() {} |
+ |
+SyncPointOrderData::SyncPointOrderData() |
+ : current_order_num_(0), |
+ destroyed_(false), |
+ processed_order_num_(0), |
+ unprocessed_order_num_(0) {} |
+ |
+SyncPointOrderData::~SyncPointOrderData() {} |
+ |
+bool SyncPointOrderData::ValidateReleaseOrderNumber( |
+ scoped_refptr<SyncPointClientState> client_state, |
+ uint32_t wait_order_num, |
+ uint64_t fence_release) { |
+ base::AutoLock auto_lock(lock_); |
+ if (destroyed_) |
+ return false; |
+ |
+ // Release should have a possible unprocessed order number lower |
+ // than the wait order number. |
+ if ((processed_order_num_ + 1) >= wait_order_num) |
+ return false; |
+ |
+ // Release should have more unprocessed numbers if we are waiting. |
+ if (unprocessed_order_num_ <= processed_order_num_) |
+ return false; |
+ |
+ // So far it could be valid, but add an order fence guard to be sure it |
+ // gets released eventually. |
+ const uint32_t expected_order_num = |
+ std::min(unprocessed_order_num_, wait_order_num); |
+ order_fence_queue_.push( |
+ OrderFence(expected_order_num, fence_release, client_state)); |
+ return true; |
+} |
+ |
+SyncPointClientState::ReleaseCallback::ReleaseCallback( |
+ uint64_t release, |
+ const base::Closure& callback) |
+ : release_count(release), callback_closure(callback) {} |
+ |
+SyncPointClientState::ReleaseCallback::~ReleaseCallback() {} |
+ |
+SyncPointClientState::SyncPointClientState( |
+ scoped_refptr<SyncPointOrderData> order_data) |
+ : order_data_(order_data), fence_sync_release_(0) {} |
+ |
SyncPointClientState::~SyncPointClientState() { |
} |
+bool SyncPointClientState::WaitForRelease(uint32_t wait_order_num, |
+ uint64_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_) { |
+ if (!order_data_->ValidateReleaseOrderNumber(this, wait_order_num, |
+ release)) { |
+ return false; |
+ } else { |
+ // Add the callback which will be called upon release. |
+ release_callback_queue_.push(ReleaseCallback(release, callback)); |
+ return true; |
+ } |
+ } |
+ } |
+ |
+ // Already released, run the callback now. |
+ callback.Run(); |
+ return true; |
+} |
+ |
+void SyncPointClientState::ReleaseFenceSync(uint64_t release) { |
+ // Call callbacks without the lock to avoid possible deadlocks. |
+ std::vector<base::Closure> callback_list; |
+ { |
+ base::AutoLock auto_lock(fence_sync_lock_); |
+ ReleaseFenceSyncLocked(release, &callback_list); |
+ } |
+ |
+ for (const base::Closure& closure : callback_list) { |
+ closure.Run(); |
+ } |
+} |
+ |
+void SyncPointClientState::EnsureReleased(uint64_t release) { |
+ // Call callbacks without the lock to avoid possible deadlocks. |
+ std::vector<base::Closure> callback_list; |
+ { |
+ base::AutoLock auto_lock(fence_sync_lock_); |
+ if (release <= fence_sync_release_) |
+ return; |
+ |
+ ReleaseFenceSyncLocked(release, &callback_list); |
+ } |
+ |
+ for (const base::Closure& closure : callback_list) { |
+ closure.Run(); |
+ } |
+} |
+ |
+void SyncPointClientState::ReleaseFenceSyncLocked( |
+ uint64_t release, |
+ std::vector<base::Closure>* callback_list) { |
+ fence_sync_lock_.AssertAcquired(); |
+ 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(); |
+ } |
+} |
+ |
SyncPointClient::~SyncPointClient() { |
+ // Release all fences on destruction. |
+ ReleaseFenceSync(UINT64_MAX); |
+ |
sync_point_manager_->DestroySyncPointClient(namespace_id_, client_id_); |
} |
+bool SyncPointClient::Wait(SyncPointClientState* release_state, |
+ uint64_t release_count, |
+ const base::Closure& wait_complete_callback) { |
+ const uint32_t wait_order_number = |
+ client_state_->order_data()->current_order_num(); |
+ |
+ // If waiting on self or wait was invalid, call the callback and return false. |
+ if (client_state_ == release_state || |
+ !release_state->WaitForRelease(wait_order_number, release_count, |
+ wait_complete_callback)) { |
+ wait_complete_callback.Run(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool SyncPointClient::WaitNonThreadSafe( |
+ SyncPointClientState* release_state, |
+ uint64_t release_count, |
+ scoped_refptr<base::SingleThreadTaskRunner> runner, |
+ const base::Closure& wait_complete_callback) { |
+ return Wait(release_state, release_count, |
+ base::Bind(&RunOnThread, runner, wait_complete_callback)); |
+} |
+ |
+void SyncPointClient::ReleaseFenceSync(uint64_t release) { |
+ client_state_->ReleaseFenceSync(release); |
+} |
+ |
SyncPointClient::SyncPointClient(SyncPointManager* sync_point_manager, |
- scoped_refptr<SyncPointClientState> state, |
+ scoped_refptr<SyncPointOrderData> order_data, |
CommandBufferNamespace namespace_id, |
uint64_t client_id) |
- : sync_point_manager_(sync_point_manager), |
- client_state_(state), |
- namespace_id_(namespace_id), |
- client_id_(client_id) { |
-} |
+ : sync_point_manager_(sync_point_manager), |
+ client_state_(new SyncPointClientState(order_data)), |
+ namespace_id_(namespace_id), |
+ client_id_(client_id) {} |
SyncPointManager::SyncPointManager(bool allow_threaded_wait) |
: allow_threaded_wait_(allow_threaded_wait), |
@@ -65,18 +299,17 @@ SyncPointManager::~SyncPointManager() { |
} |
scoped_ptr<SyncPointClient> SyncPointManager::CreateSyncPointClient( |
- scoped_refptr<SyncPointClientState> client_state, |
- CommandBufferNamespace namespace_id, uint64_t client_id) { |
+ scoped_refptr<SyncPointOrderData> order_data, |
+ CommandBufferNamespace namespace_id, |
+ uint64_t client_id) { |
DCHECK_GE(namespace_id, 0); |
DCHECK_LT(static_cast<size_t>(namespace_id), arraysize(client_maps_)); |
base::AutoLock auto_lock(client_maps_lock_); |
ClientMap& client_map = client_maps_[namespace_id]; |
std::pair<ClientMap::iterator, bool> result = client_map.insert( |
- std::make_pair(client_id, new SyncPointClient(this, |
- client_state, |
- namespace_id, |
- client_id))); |
+ std::make_pair(client_id, new SyncPointClient(this, order_data, |
+ namespace_id, client_id))); |
DCHECK(result.second); |
return make_scoped_ptr(result.first->second); |