|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_ | 
|  | #define GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_ | 
|  |  | 
|  | #include <functional> | 
|  | #include <queue> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/atomic_sequence_num.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/containers/hash_tables.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/synchronization/condition_variable.h" | 
|  | #include "base/synchronization/lock.h" | 
|  | #include "base/threading/thread_checker.h" | 
|  | #include "gpu/command_buffer/common/constants.h" | 
|  | #include "gpu/gpu_export.h" | 
|  |  | 
|  | namespace base { | 
|  | class SingleThreadTaskRunner; | 
|  | }  // namespace base | 
|  |  | 
|  | namespace gpu { | 
|  |  | 
|  | class SyncPointClient; | 
|  | class SyncPointClientState; | 
|  | class SyncPointManager; | 
|  |  | 
|  | class GPU_EXPORT SyncPointOrderData | 
|  | : public base::RefCountedThreadSafe<SyncPointOrderData> { | 
|  | public: | 
|  | static scoped_refptr<SyncPointOrderData> Create(); | 
|  | void Destroy(); | 
|  |  | 
|  | uint32_t GenerateUnprocessedOrderNumber(SyncPointManager* sync_point_manager); | 
|  | void BeginProcessingOrderNumber(uint32_t order_num); | 
|  | void FinishProcessingOrderNumber(uint32_t order_num); | 
|  |  | 
|  | uint32_t processed_order_num() const { | 
|  | base::AutoLock auto_lock(lock_); | 
|  | return processed_order_num_; | 
|  | } | 
|  |  | 
|  | uint32_t unprocessed_order_num() const { | 
|  | base::AutoLock auto_lock(lock_); | 
|  | return unprocessed_order_num_; | 
|  | } | 
|  |  | 
|  | uint32_t current_order_num() const { | 
|  | DCHECK(processing_thread_checker_.CalledOnValidThread()); | 
|  | return current_order_num_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class base::RefCountedThreadSafe<SyncPointOrderData>; | 
|  | friend class SyncPointClientState; | 
|  |  | 
|  | struct OrderFence { | 
|  | uint32_t order_num; | 
|  | uint64_t fence_release; | 
|  | scoped_refptr<SyncPointClientState> client_state; | 
|  |  | 
|  | OrderFence(uint32_t order, | 
|  | uint64_t release, | 
|  | scoped_refptr<SyncPointClientState> state); | 
|  | ~OrderFence(); | 
|  |  | 
|  | bool operator>(const OrderFence& rhs) const { | 
|  | return (order_num > rhs.order_num) || | 
|  | ((order_num == rhs.order_num) && | 
|  | (fence_release > rhs.fence_release)); | 
|  | } | 
|  | }; | 
|  | typedef std::priority_queue<OrderFence, | 
|  | std::vector<OrderFence>, | 
|  | std::greater<OrderFence>> OrderFenceQueue; | 
|  |  | 
|  | SyncPointOrderData(); | 
|  | ~SyncPointOrderData(); | 
|  |  | 
|  | bool ValidateReleaseOrderNumber( | 
|  | scoped_refptr<SyncPointClientState> client_state, | 
|  | uint32_t wait_order_num, | 
|  | uint64_t fence_release); | 
|  |  | 
|  | // Non thread-safe functions need to be called from a single thread. | 
|  | base::ThreadChecker processing_thread_checker_; | 
|  |  | 
|  | // Current IPC order number being processed (only used on processing thread). | 
|  | uint32_t current_order_num_; | 
|  |  | 
|  | // This lock protects destroyed_, processed_order_num_, | 
|  | // unprocessed_order_num_, and order_fence_queue_. All order numbers (n) in | 
|  | // order_fence_queue_ must follow the invariant: | 
|  | //   processed_order_num_ < n <= unprocessed_order_num_. | 
|  | mutable base::Lock lock_; | 
|  |  | 
|  | bool destroyed_; | 
|  |  | 
|  | // Last finished IPC order number. | 
|  | uint32_t processed_order_num_; | 
|  |  | 
|  | // Unprocessed order number expected to be processed under normal execution. | 
|  | uint32_t unprocessed_order_num_; | 
|  |  | 
|  | // In situations where we are waiting on fence syncs that do not exist, we | 
|  | // validate by making sure the order number does not pass the order number | 
|  | // which the wait command was issued. If the order number reaches the | 
|  | // wait command's, we should automatically release up to the expected | 
|  | // release count. Note that this also releases other lower release counts, | 
|  | // so a single misbehaved fence sync is enough to invalidate/signal all | 
|  | // previous fence syncs. | 
|  | OrderFenceQueue order_fence_queue_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SyncPointOrderData); | 
|  | }; | 
|  |  | 
|  | class GPU_EXPORT SyncPointClientState | 
|  | : public base::RefCountedThreadSafe<SyncPointClientState> { | 
|  | public: | 
|  | scoped_refptr<SyncPointOrderData> order_data() { return order_data_; } | 
|  |  | 
|  | bool IsFenceSyncReleased(uint64_t release) { | 
|  | return release <= fence_sync_release(); | 
|  | } | 
|  |  | 
|  | uint64_t fence_sync_release() { | 
|  | base::AutoLock auto_lock(fence_sync_lock_); | 
|  | return fence_sync_release_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class base::RefCountedThreadSafe<SyncPointClientState>; | 
|  | friend class SyncPointClient; | 
|  | friend class SyncPointClientWaiter; | 
|  | friend class SyncPointOrderData; | 
|  |  | 
|  | struct ReleaseCallback { | 
|  | uint64_t release_count; | 
|  | base::Closure callback_closure; | 
|  |  | 
|  | ReleaseCallback(uint64_t release, const base::Closure& callback); | 
|  | ~ReleaseCallback(); | 
|  |  | 
|  | bool operator>(const ReleaseCallback& rhs) const { | 
|  | return release_count > rhs.release_count; | 
|  | } | 
|  | }; | 
|  | typedef std::priority_queue<ReleaseCallback, | 
|  | std::vector<ReleaseCallback>, | 
|  | std::greater<ReleaseCallback>> | 
|  | ReleaseCallbackQueue; | 
|  |  | 
|  | SyncPointClientState(scoped_refptr<SyncPointOrderData> order_data); | 
|  | ~SyncPointClientState(); | 
|  |  | 
|  | // Queues the callback to be called if the release is valid. If the release | 
|  | // is invalid this function will return False and the callback will never | 
|  | // be called. | 
|  | bool WaitForRelease(uint32_t wait_order_num, | 
|  | uint64_t release, | 
|  | const base::Closure& callback); | 
|  |  | 
|  | void ReleaseFenceSync(uint64_t release); | 
|  | void EnsureReleased(uint64_t release); | 
|  | void ReleaseFenceSyncLocked(uint64_t release, | 
|  | std::vector<base::Closure>* callback_list); | 
|  |  | 
|  | // Global order data where releases will originate from. | 
|  | scoped_refptr<SyncPointOrderData> order_data_; | 
|  |  | 
|  | // Protects fence_sync_release_, fence_callback_queue_. | 
|  | base::Lock fence_sync_lock_; | 
|  |  | 
|  | // Current fence sync release that has been signaled. | 
|  | uint64_t fence_sync_release_; | 
|  |  | 
|  | // In well defined fence sync operations, fence syncs are released in order | 
|  | // so simply having a priority queue for callbacks is enough. | 
|  | ReleaseCallbackQueue release_callback_queue_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SyncPointClientState); | 
|  | }; | 
|  |  | 
|  | class GPU_EXPORT SyncPointClient { | 
|  | public: | 
|  | ~SyncPointClient(); | 
|  |  | 
|  | scoped_refptr<SyncPointClientState> client_state() { return client_state_; } | 
|  |  | 
|  | // Wait for a release count to be reached on a SyncPointClientState. If this | 
|  | // function returns false, that means the wait was invalid. Otherwise if it | 
|  | // returns True it means the release was valid. In the case where the release | 
|  | // is valid but has happened already, it will still return true. In all cases | 
|  | // wait_complete_callback will be called eventually. The callback function | 
|  | // may be called on another thread so it should be thread-safe. For | 
|  | // convenience, another non-threadsafe version is defined below where you | 
|  | // can supply a task runner. | 
|  | bool Wait(SyncPointClientState* release_state, | 
|  | uint64_t release_count, | 
|  | const base::Closure& wait_complete_callback); | 
|  |  | 
|  | bool WaitNonThreadSafe(SyncPointClientState* release_state, | 
|  | uint64_t release_count, | 
|  | scoped_refptr<base::SingleThreadTaskRunner> runner, | 
|  | const base::Closure& wait_complete_callback); | 
|  |  | 
|  | void ReleaseFenceSync(uint64_t release); | 
|  |  | 
|  | private: | 
|  | friend class SyncPointManager; | 
|  |  | 
|  | SyncPointClient(SyncPointManager* sync_point_manager, | 
|  | scoped_refptr<SyncPointOrderData> order_data, | 
|  | CommandBufferNamespace namespace_id, | 
|  | uint64_t client_id); | 
|  |  | 
|  | // Sync point manager is guaranteed to exist in the lifetime of the client. | 
|  | SyncPointManager* sync_point_manager_; | 
|  |  | 
|  | // Keep the state that is sharable across multiple threads. | 
|  | scoped_refptr<SyncPointClientState> client_state_; | 
|  |  | 
|  | // Unique namespace/client id pair for this sync point client. | 
|  | const CommandBufferNamespace namespace_id_; | 
|  | const uint64_t client_id_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SyncPointClient); | 
|  | }; | 
|  |  | 
|  | // A SyncPointClientWaiter is a Sync Point Client which can only wait and on | 
|  | // fence syncs and not release any fence syncs itself. Because they cannot | 
|  | // release any fence syncs they do not need an associated order number since | 
|  | // deadlocks cannot happen. Note that it is important that this class does | 
|  | // not exist in the same execution context as a SyncPointClient, or else a | 
|  | // deadlock could occur. Basically, SyncPointClientWaiter::Wait() should never | 
|  | // be called between SyncPointOrderData::BeginProcessingOrderNumber() and | 
|  | // SyncPointOrderData::FinishProcessingOrderNumber() on the same thread. | 
|  | class GPU_EXPORT SyncPointClientWaiter { | 
|  | public: | 
|  | SyncPointClientWaiter() {} | 
|  | ~SyncPointClientWaiter() {} | 
|  |  | 
|  | bool Wait(SyncPointClientState* release_state, | 
|  | uint64_t release_count, | 
|  | const base::Closure& wait_complete_callback); | 
|  |  | 
|  | bool WaitNonThreadSafe(SyncPointClientState* release_state, | 
|  | uint64_t release_count, | 
|  | scoped_refptr<base::SingleThreadTaskRunner> runner, | 
|  | const base::Closure& wait_complete_callback); | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(SyncPointClientWaiter); | 
|  | }; | 
|  |  | 
|  | // This class manages the sync points, which allow cross-channel | 
|  | // synchronization. | 
|  | class GPU_EXPORT SyncPointManager { | 
|  | public: | 
|  | explicit SyncPointManager(bool allow_threaded_wait); | 
|  | ~SyncPointManager(); | 
|  |  | 
|  | // Creates/Destroy a sync point client which message processors should hold. | 
|  | scoped_ptr<SyncPointClient> CreateSyncPointClient( | 
|  | scoped_refptr<SyncPointOrderData> order_data, | 
|  | CommandBufferNamespace namespace_id, | 
|  | uint64_t client_id); | 
|  |  | 
|  | // Finds the state of an already created sync point client. | 
|  | scoped_refptr<SyncPointClientState> GetSyncPointClientState( | 
|  | CommandBufferNamespace namespace_id, uint64_t client_id); | 
|  |  | 
|  | // Generates a sync point, returning its ID. This can me called on any thread. | 
|  | // IDs start at a random number. Never return 0. | 
|  | uint32 GenerateSyncPoint(); | 
|  |  | 
|  | // Retires a sync point. This will call all the registered callbacks for this | 
|  | // sync point. This can only be called on the main thread. | 
|  | void RetireSyncPoint(uint32 sync_point); | 
|  |  | 
|  | // Adds a callback to the sync point. The callback will be called when the | 
|  | // sync point is retired, or immediately (from within that function) if the | 
|  | // sync point was already retired (or not created yet). This can only be | 
|  | // called on the main thread. | 
|  | void AddSyncPointCallback(uint32 sync_point, const base::Closure& callback); | 
|  |  | 
|  | bool IsSyncPointRetired(uint32 sync_point); | 
|  |  | 
|  | // Block and wait until a sync point is signaled. This is only useful when | 
|  | // the sync point is signaled on another thread. | 
|  | void WaitSyncPoint(uint32 sync_point); | 
|  |  | 
|  | private: | 
|  | friend class SyncPointClient; | 
|  | friend class SyncPointOrderData; | 
|  |  | 
|  | typedef std::vector<base::Closure> ClosureList; | 
|  | typedef base::hash_map<uint32, ClosureList> SyncPointMap; | 
|  | typedef base::hash_map<uint64_t, SyncPointClient*> ClientMap; | 
|  |  | 
|  | bool IsSyncPointRetiredLocked(uint32 sync_point); | 
|  | uint32_t GenerateOrderNumber(); | 
|  | void DestroySyncPointClient(CommandBufferNamespace namespace_id, | 
|  | uint64_t client_id); | 
|  |  | 
|  | const bool allow_threaded_wait_; | 
|  |  | 
|  | // Order number is global for all clients. | 
|  | base::AtomicSequenceNumber global_order_num_; | 
|  |  | 
|  | // Client map holds a map of clients id to client for each namespace. | 
|  | base::Lock client_maps_lock_; | 
|  | ClientMap client_maps_[NUM_COMMAND_BUFFER_NAMESPACES]; | 
|  |  | 
|  | // Protects the 2 fields below. Note: callbacks shouldn't be called with this | 
|  | // held. | 
|  | base::Lock lock_; | 
|  | SyncPointMap sync_point_map_; | 
|  | uint32 next_sync_point_; | 
|  | base::ConditionVariable retire_cond_var_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SyncPointManager); | 
|  | }; | 
|  |  | 
|  | }  // namespace gpu | 
|  |  | 
|  | #endif  // GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_ |