// 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 CONTENT_COMMON_GPU_GPU_CHANNEL_H_ #define CONTENT_COMMON_GPU_GPU_CHANNEL_H_ #include #include #include #include "base/containers/hash_tables.h" #include "base/containers/scoped_ptr_hash_map.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/process/process.h" #include "base/threading/thread_checker.h" #include "base/trace_event/memory_dump_provider.h" #include "build/build_config.h" #include "content/common/content_export.h" #include "content/common/gpu/gpu_command_buffer_stub.h" #include "content/common/gpu/gpu_memory_manager.h" #include "gpu/command_buffer/service/valuebuffer_manager.h" #include "gpu/ipc/common/gpu_stream_constants.h" #include "ipc/ipc_sync_channel.h" #include "ipc/message_router.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gpu_preference.h" struct GPUCreateCommandBufferConfig; namespace base { class WaitableEvent; } namespace gpu { class PreemptionFlag; class SyncPointOrderData; class SyncPointManager; union ValueState; class ValueStateMap; namespace gles2 { class SubscriptionRefSet; } } namespace IPC { class MessageFilter; } namespace content { class GpuChannelManager; class GpuChannelMessageFilter; class GpuChannelMessageQueue; class GpuWatchdog; // Encapsulates an IPC channel between the GPU process and one renderer // process. On the renderer side there's a corresponding GpuChannelHost. class CONTENT_EXPORT GpuChannel : public IPC::Listener, public IPC::Sender, public gpu::gles2::SubscriptionRefSet::Observer { public: // Takes ownership of the renderer process handle. GpuChannel(GpuChannelManager* gpu_channel_manager, gpu::SyncPointManager* sync_point_manager, GpuWatchdog* watchdog, gfx::GLShareGroup* share_group, gpu::gles2::MailboxManager* mailbox_manager, gpu::PreemptionFlag* preempting_flag, gpu::PreemptionFlag* preempted_flag, base::SingleThreadTaskRunner* task_runner, base::SingleThreadTaskRunner* io_task_runner, int32_t client_id, uint64_t client_tracing_id, bool allow_view_command_buffers, bool allow_real_time_streams); ~GpuChannel() override; // Initializes the IPC channel. Caller takes ownership of the client FD in // the returned handle and is responsible for closing it. virtual IPC::ChannelHandle Init(base::WaitableEvent* shutdown_event); void SetUnhandledMessageListener(IPC::Listener* listener); // Get the GpuChannelManager that owns this channel. GpuChannelManager* gpu_channel_manager() const { return gpu_channel_manager_; } const std::string& channel_id() const { return channel_id_; } virtual base::ProcessId GetClientPID() const; int client_id() const { return client_id_; } uint64_t client_tracing_id() const { return client_tracing_id_; } base::WeakPtr AsWeakPtr(); scoped_refptr io_task_runner() const { return io_task_runner_; } // IPC::Listener implementation: bool OnMessageReceived(const IPC::Message& msg) override; void OnChannelError() override; // IPC::Sender implementation: bool Send(IPC::Message* msg) override; // SubscriptionRefSet::Observer implementation void OnAddSubscription(unsigned int target) override; void OnRemoveSubscription(unsigned int target) override; void OnStreamRescheduled(int32_t stream_id, bool scheduled); gfx::GLShareGroup* share_group() const { return share_group_.get(); } GpuCommandBufferStub* LookupCommandBuffer(int32_t route_id); void LoseAllContexts(); void MarkAllContextsLost(); // Called to add a listener for a particular message routing ID. // Returns true if succeeded. bool AddRoute(int32_t route_id, int32_t stream_id, IPC::Listener* listener); // Called to remove a listener for a particular message routing ID. void RemoveRoute(int32_t route_id); void CacheShader(const std::string& key, const std::string& shader); void AddFilter(IPC::MessageFilter* filter); void RemoveFilter(IPC::MessageFilter* filter); uint64_t GetMemoryUsage(); scoped_refptr CreateImageForGpuMemoryBuffer( const gfx::GpuMemoryBufferHandle& handle, const gfx::Size& size, gfx::BufferFormat format, uint32_t internalformat); void HandleUpdateValueState(unsigned int target, const gpu::ValueState& state); GpuChannelMessageFilter* filter() const { return filter_.get(); } // Visible for testing. const gpu::ValueStateMap* pending_valuebuffer_state() const { return pending_valuebuffer_state_.get(); } // Returns the global order number for the last processed IPC message. uint32_t GetProcessedOrderNum() const; // Returns the global order number for the last unprocessed IPC message. uint32_t GetUnprocessedOrderNum() const; // Returns the shared sync point global order data for the stream. scoped_refptr GetSyncPointOrderData( int32_t stream_id); void PostHandleOutOfOrderMessage(const IPC::Message& message); void PostHandleMessage(const scoped_refptr& queue); // Synchronously handle the message to make testing convenient. void HandleMessageForTesting(const IPC::Message& msg); #if defined(OS_ANDROID) const GpuCommandBufferStub* GetOneStub() const; #endif protected: // The message filter on the io thread. scoped_refptr filter_; // Map of routing id to command buffer stub. base::ScopedPtrHashMap> stubs_; private: bool OnControlMessageReceived(const IPC::Message& msg); void HandleMessage(const scoped_refptr& queue); // Some messages such as WaitForGetOffsetInRange and WaitForTokenInRange are // processed as soon as possible because the client is blocked until they // are completed. void HandleOutOfOrderMessage(const IPC::Message& msg); void HandleMessageHelper(const IPC::Message& msg); scoped_refptr CreateStream( int32_t stream_id, gpu::GpuStreamPriority stream_priority); scoped_refptr LookupStream(int32_t stream_id); void DestroyStreamIfNecessary( const scoped_refptr& queue); void AddRouteToStream(int32_t route_id, int32_t stream_id); void RemoveRouteFromStream(int32_t route_id); // Message handlers for control messages. void OnCreateCommandBuffer(gpu::SurfaceHandle surface_handle, const gfx::Size& size, const GPUCreateCommandBufferConfig& init_params, int32_t route_id, bool* succeeded); void OnDestroyCommandBuffer(int32_t route_id); // The lifetime of objects of this class is managed by a GpuChannelManager. // The GpuChannelManager destroy all the GpuChannels that they own when they // are destroyed. So a raw pointer is safe. GpuChannelManager* const gpu_channel_manager_; // Sync point manager. Outlives the channel and is guaranteed to outlive the // message loop. gpu::SyncPointManager* const sync_point_manager_; scoped_ptr channel_; IPC::Listener* unhandled_message_listener_; // Uniquely identifies the channel within this GPU process. std::string channel_id_; // Used to implement message routing functionality to CommandBuffer objects IPC::MessageRouter router_; // Whether the processing of IPCs on this channel is stalled and we should // preempt other GpuChannels. scoped_refptr preempting_flag_; // If non-NULL, all stubs on this channel should stop processing GL // commands (via their CommandExecutor) when preempted_flag_->IsSet() scoped_refptr preempted_flag_; // The id of the client who is on the other side of the channel. const int32_t client_id_; // The tracing ID used for memory allocations associated with this client. const uint64_t client_tracing_id_; // The task runners for the main thread and the io thread. scoped_refptr task_runner_; scoped_refptr io_task_runner_; // The share group that all contexts associated with a particular renderer // process use. scoped_refptr share_group_; scoped_refptr mailbox_manager_; scoped_refptr subscription_ref_set_; scoped_refptr pending_valuebuffer_state_; gpu::gles2::DisallowedFeatures disallowed_features_; GpuWatchdog* const watchdog_; // Map of stream id to appropriate message queue. base::hash_map> streams_; // Multimap of stream id to route ids. base::hash_map streams_to_num_routes_; // Map of route id to stream id; base::hash_map routes_to_streams_; // Can view command buffers be created on this channel. const bool allow_view_command_buffers_; // Can real time streams be created on this channel. const bool allow_real_time_streams_; // Member variables should appear before the WeakPtrFactory, to ensure // that any WeakPtrs to Controller are invalidated before its members // variable's destructors are executed, rendering them invalid. base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(GpuChannel); }; // This filter does three things: // - it counts and timestamps each message forwarded to the channel // so that we can preempt other channels if a message takes too long to // process. To guarantee fairness, we must wait a minimum amount of time // before preempting and we limit the amount of time that we can preempt in // one shot (see constants above). // - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO // thread, generating the sync point ID and responding immediately, and then // posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message // into the channel's queue. // - it generates mailbox names for clients of the GPU process on the IO thread. class GpuChannelMessageFilter : public IPC::MessageFilter { public: GpuChannelMessageFilter(); // IPC::MessageFilter implementation. void OnFilterAdded(IPC::Sender* sender) override; void OnFilterRemoved() override; void OnChannelConnected(int32_t peer_pid) override; void OnChannelError() override; void OnChannelClosing() override; bool OnMessageReceived(const IPC::Message& message) override; void AddChannelFilter(scoped_refptr filter); void RemoveChannelFilter(scoped_refptr filter); void AddRoute(int32_t route_id, const scoped_refptr& queue); void RemoveRoute(int32_t route_id); bool Send(IPC::Message* message); protected: ~GpuChannelMessageFilter() override; private: scoped_refptr LookupStreamByRoute(int32_t route_id); bool MessageErrorHandler(const IPC::Message& message, const char* error_msg); // Map of route id to message queue. base::hash_map> routes_; base::Lock routes_lock_; // Protects |routes_|. IPC::Sender* sender_; base::ProcessId peer_pid_; std::vector> channel_filters_; DISALLOW_COPY_AND_ASSIGN(GpuChannelMessageFilter); }; struct GpuChannelMessage { IPC::Message message; uint32_t order_number; base::TimeTicks time_received; GpuChannelMessage(const IPC::Message& msg, uint32_t order_num, base::TimeTicks ts) : message(msg), order_number(order_num), time_received(ts) {} private: DISALLOW_COPY_AND_ASSIGN(GpuChannelMessage); }; class GpuChannelMessageQueue : public base::RefCountedThreadSafe { public: static scoped_refptr Create( int32_t stream_id, gpu::GpuStreamPriority stream_priority, GpuChannel* channel, const scoped_refptr& io_task_runner, const scoped_refptr& preempting_flag, const scoped_refptr& preempted_flag, gpu::SyncPointManager* sync_point_manager); void Disable(); void DisableIO(); int32_t stream_id() const { return stream_id_; } gpu::GpuStreamPriority stream_priority() const { return stream_priority_; } bool IsScheduled() const; void OnRescheduled(bool scheduled); bool HasQueuedMessages() const; base::TimeTicks GetNextMessageTimeTick() const; scoped_refptr GetSyncPointOrderData(); // Returns the global order number for the last unprocessed IPC message. uint32_t GetUnprocessedOrderNum() const; // Returns the global order number for the last unprocessed IPC message. uint32_t GetProcessedOrderNum() const; // Should be called before a message begins to be processed. Returns false if // there are no messages to process. const GpuChannelMessage* BeginMessageProcessing(); // Should be called if a message began processing but did not finish. void PauseMessageProcessing(); // Should be called if a message is completely processed. Returns true if // there are more messages to process. void FinishMessageProcessing(); bool PushBackMessage(const IPC::Message& message); private: enum PreemptionState { // Either there's no other channel to preempt, there are no messages // pending processing, or we just finished preempting and have to wait // before preempting again. IDLE, // We are waiting kPreemptWaitTimeMs before checking if we should preempt. WAITING, // We can preempt whenever any IPC processing takes more than // kPreemptWaitTimeMs. CHECKING, // We are currently preempting (i.e. no stub is descheduled). PREEMPTING, // We would like to preempt, but some stub is descheduled. WOULD_PREEMPT_DESCHEDULED, }; friend class base::RefCountedThreadSafe; GpuChannelMessageQueue( int32_t stream_id, gpu::GpuStreamPriority stream_priority, GpuChannel* channel, const scoped_refptr& io_task_runner, const scoped_refptr& preempting_flag, const scoped_refptr& preempted_flag, gpu::SyncPointManager* sync_point_manager); ~GpuChannelMessageQueue(); void UpdatePreemptionState(); void UpdatePreemptionStateHelper(); void UpdateStateIdle(); void UpdateStateWaiting(); void UpdateStateChecking(); void UpdateStatePreempting(); void UpdateStateWouldPreemptDescheduled(); void TransitionToIdle(); void TransitionToWaiting(); void TransitionToChecking(); void TransitionToPreempting(); void TransitionToWouldPreemptDescheduled(); bool ShouldTransitionToIdle() const; const int32_t stream_id_; const gpu::GpuStreamPriority stream_priority_; // These can be accessed from both IO and main threads and are protected by // |channel_lock_|. bool enabled_; bool scheduled_; GpuChannel* const channel_; std::deque> channel_messages_; mutable base::Lock channel_lock_; // The following are accessed on the IO thread only. // No lock is necessary for preemption state because it's only accessed on the // IO thread. PreemptionState preemption_state_; // Maximum amount of time that we can spend in PREEMPTING. // It is reset when we transition to IDLE. base::TimeDelta max_preemption_time_; // This timer is used and runs tasks on the IO thread. scoped_ptr timer_; base::ThreadChecker io_thread_checker_; // Keeps track of sync point related state such as message order numbers. scoped_refptr sync_point_order_data_; scoped_refptr io_task_runner_; scoped_refptr preempting_flag_; scoped_refptr preempted_flag_; gpu::SyncPointManager* const sync_point_manager_; DISALLOW_COPY_AND_ASSIGN(GpuChannelMessageQueue); }; } // namespace content #endif // CONTENT_COMMON_GPU_GPU_CHANNEL_H_