Index: content/common/gpu/gpu_channel.cc |
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc |
deleted file mode 100644 |
index 20edeafa8467e1ad4f42da2350c052003e8be2a6..0000000000000000000000000000000000000000 |
--- a/content/common/gpu/gpu_channel.cc |
+++ /dev/null |
@@ -1,1072 +0,0 @@ |
-// 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. |
- |
-#include "content/common/gpu/gpu_channel.h" |
- |
-#include <utility> |
- |
-#if defined(OS_WIN) |
-#include <windows.h> |
-#endif |
- |
-#include <algorithm> |
-#include <deque> |
-#include <set> |
-#include <vector> |
- |
-#include "base/atomicops.h" |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/location.h" |
-#include "base/numerics/safe_conversions.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/stl_util.h" |
-#include "base/strings/string_util.h" |
-#include "base/synchronization/lock.h" |
-#include "base/thread_task_runner_handle.h" |
-#include "base/timer/timer.h" |
-#include "base/trace_event/memory_dump_manager.h" |
-#include "base/trace_event/process_memory_dump.h" |
-#include "base/trace_event/trace_event.h" |
-#include "build/build_config.h" |
-#include "content/common/gpu/gpu_channel_manager.h" |
-#include "content/common/gpu/gpu_channel_manager_delegate.h" |
-#include "content/common/gpu/gpu_memory_buffer_factory.h" |
-#include "gpu/command_buffer/common/mailbox.h" |
-#include "gpu/command_buffer/common/value_state.h" |
-#include "gpu/command_buffer/service/command_executor.h" |
-#include "gpu/command_buffer/service/image_factory.h" |
-#include "gpu/command_buffer/service/mailbox_manager.h" |
-#include "gpu/command_buffer/service/sync_point_manager.h" |
-#include "gpu/command_buffer/service/valuebuffer_manager.h" |
-#include "gpu/ipc/common/gpu_messages.h" |
-#include "ipc/ipc_channel.h" |
-#include "ipc/message_filter.h" |
-#include "ui/gl/gl_context.h" |
-#include "ui/gl/gl_image_shared_memory.h" |
-#include "ui/gl/gl_surface.h" |
- |
-#if defined(OS_POSIX) |
-#include "ipc/ipc_channel_posix.h" |
-#endif |
- |
-namespace content { |
-namespace { |
- |
-// Number of milliseconds between successive vsync. Many GL commands block |
-// on vsync, so thresholds for preemption should be multiples of this. |
-const int64_t kVsyncIntervalMs = 17; |
- |
-// Amount of time that we will wait for an IPC to be processed before |
-// preempting. After a preemption, we must wait this long before triggering |
-// another preemption. |
-const int64_t kPreemptWaitTimeMs = 2 * kVsyncIntervalMs; |
- |
-// Once we trigger a preemption, the maximum duration that we will wait |
-// before clearing the preemption. |
-const int64_t kMaxPreemptTimeMs = kVsyncIntervalMs; |
- |
-// Stop the preemption once the time for the longest pending IPC drops |
-// below this threshold. |
-const int64_t kStopPreemptThresholdMs = kVsyncIntervalMs; |
- |
-} // anonymous namespace |
- |
-scoped_refptr<GpuChannelMessageQueue> GpuChannelMessageQueue::Create( |
- int32_t stream_id, |
- gpu::GpuStreamPriority stream_priority, |
- GpuChannel* channel, |
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
- const scoped_refptr<gpu::PreemptionFlag>& preempting_flag, |
- const scoped_refptr<gpu::PreemptionFlag>& preempted_flag, |
- gpu::SyncPointManager* sync_point_manager) { |
- return new GpuChannelMessageQueue(stream_id, stream_priority, channel, |
- io_task_runner, preempting_flag, |
- preempted_flag, sync_point_manager); |
-} |
- |
-scoped_refptr<gpu::SyncPointOrderData> |
-GpuChannelMessageQueue::GetSyncPointOrderData() { |
- return sync_point_order_data_; |
-} |
- |
-GpuChannelMessageQueue::GpuChannelMessageQueue( |
- int32_t stream_id, |
- gpu::GpuStreamPriority stream_priority, |
- GpuChannel* channel, |
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
- const scoped_refptr<gpu::PreemptionFlag>& preempting_flag, |
- const scoped_refptr<gpu::PreemptionFlag>& preempted_flag, |
- gpu::SyncPointManager* sync_point_manager) |
- : stream_id_(stream_id), |
- stream_priority_(stream_priority), |
- enabled_(true), |
- scheduled_(true), |
- channel_(channel), |
- preemption_state_(IDLE), |
- max_preemption_time_( |
- base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs)), |
- timer_(new base::OneShotTimer), |
- sync_point_order_data_(gpu::SyncPointOrderData::Create()), |
- io_task_runner_(io_task_runner), |
- preempting_flag_(preempting_flag), |
- preempted_flag_(preempted_flag), |
- sync_point_manager_(sync_point_manager) { |
- timer_->SetTaskRunner(io_task_runner); |
- io_thread_checker_.DetachFromThread(); |
-} |
- |
-GpuChannelMessageQueue::~GpuChannelMessageQueue() { |
- DCHECK(!enabled_); |
- DCHECK(channel_messages_.empty()); |
-} |
- |
-void GpuChannelMessageQueue::Disable() { |
- { |
- base::AutoLock auto_lock(channel_lock_); |
- DCHECK(enabled_); |
- enabled_ = false; |
- } |
- |
- // We guarantee that the queues will no longer be modified after enabled_ |
- // is set to false, it is now safe to modify the queue without the lock. |
- // All public facing modifying functions check enabled_ while all |
- // private modifying functions DCHECK(enabled_) to enforce this. |
- while (!channel_messages_.empty()) { |
- const IPC::Message& msg = channel_messages_.front()->message; |
- if (msg.is_sync()) { |
- IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); |
- reply->set_reply_error(); |
- channel_->Send(reply); |
- } |
- channel_messages_.pop_front(); |
- } |
- |
- sync_point_order_data_->Destroy(); |
- sync_point_order_data_ = nullptr; |
- |
- io_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&GpuChannelMessageQueue::DisableIO, this)); |
-} |
- |
-void GpuChannelMessageQueue::DisableIO() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- timer_ = nullptr; |
-} |
- |
-bool GpuChannelMessageQueue::IsScheduled() const { |
- base::AutoLock lock(channel_lock_); |
- return scheduled_; |
-} |
- |
-void GpuChannelMessageQueue::OnRescheduled(bool scheduled) { |
- base::AutoLock lock(channel_lock_); |
- DCHECK(enabled_); |
- if (scheduled_ == scheduled) |
- return; |
- scheduled_ = scheduled; |
- if (scheduled) |
- channel_->PostHandleMessage(this); |
- if (preempting_flag_) { |
- io_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&GpuChannelMessageQueue::UpdatePreemptionState, this)); |
- } |
-} |
- |
-uint32_t GpuChannelMessageQueue::GetUnprocessedOrderNum() const { |
- return sync_point_order_data_->unprocessed_order_num(); |
-} |
- |
-uint32_t GpuChannelMessageQueue::GetProcessedOrderNum() const { |
- return sync_point_order_data_->processed_order_num(); |
-} |
- |
-bool GpuChannelMessageQueue::PushBackMessage(const IPC::Message& message) { |
- base::AutoLock auto_lock(channel_lock_); |
- if (enabled_) { |
- if (message.type() == GpuCommandBufferMsg_WaitForTokenInRange::ID || |
- message.type() == GpuCommandBufferMsg_WaitForGetOffsetInRange::ID) { |
- channel_->PostHandleOutOfOrderMessage(message); |
- return true; |
- } |
- |
- uint32_t order_num = sync_point_order_data_->GenerateUnprocessedOrderNumber( |
- sync_point_manager_); |
- scoped_ptr<GpuChannelMessage> msg( |
- new GpuChannelMessage(message, order_num, base::TimeTicks::Now())); |
- |
- if (channel_messages_.empty()) { |
- DCHECK(scheduled_); |
- channel_->PostHandleMessage(this); |
- } |
- |
- channel_messages_.push_back(std::move(msg)); |
- |
- if (preempting_flag_) |
- UpdatePreemptionStateHelper(); |
- |
- return true; |
- } |
- return false; |
-} |
- |
-const GpuChannelMessage* GpuChannelMessageQueue::BeginMessageProcessing() { |
- base::AutoLock auto_lock(channel_lock_); |
- DCHECK(enabled_); |
- // If we have been preempted by another channel, just post a task to wake up. |
- if (preempted_flag_ && preempted_flag_->IsSet()) { |
- channel_->PostHandleMessage(this); |
- return nullptr; |
- } |
- if (channel_messages_.empty()) |
- return nullptr; |
- sync_point_order_data_->BeginProcessingOrderNumber( |
- channel_messages_.front()->order_number); |
- return channel_messages_.front().get(); |
-} |
- |
-void GpuChannelMessageQueue::PauseMessageProcessing() { |
- base::AutoLock auto_lock(channel_lock_); |
- DCHECK(!channel_messages_.empty()); |
- |
- // If we have been preempted by another channel, just post a task to wake up. |
- if (scheduled_) |
- channel_->PostHandleMessage(this); |
- |
- sync_point_order_data_->PauseProcessingOrderNumber( |
- channel_messages_.front()->order_number); |
-} |
- |
-void GpuChannelMessageQueue::FinishMessageProcessing() { |
- base::AutoLock auto_lock(channel_lock_); |
- DCHECK(!channel_messages_.empty()); |
- DCHECK(scheduled_); |
- |
- sync_point_order_data_->FinishProcessingOrderNumber( |
- channel_messages_.front()->order_number); |
- channel_messages_.pop_front(); |
- |
- if (!channel_messages_.empty()) |
- channel_->PostHandleMessage(this); |
- |
- if (preempting_flag_) { |
- io_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&GpuChannelMessageQueue::UpdatePreemptionState, this)); |
- } |
-} |
- |
-void GpuChannelMessageQueue::UpdatePreemptionState() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- base::AutoLock lock(channel_lock_); |
- UpdatePreemptionStateHelper(); |
-} |
- |
-void GpuChannelMessageQueue::UpdatePreemptionStateHelper() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- switch (preemption_state_) { |
- case IDLE: |
- UpdateStateIdle(); |
- break; |
- case WAITING: |
- UpdateStateWaiting(); |
- break; |
- case CHECKING: |
- UpdateStateChecking(); |
- break; |
- case PREEMPTING: |
- UpdateStatePreempting(); |
- break; |
- case WOULD_PREEMPT_DESCHEDULED: |
- UpdateStateWouldPreemptDescheduled(); |
- break; |
- default: |
- NOTREACHED(); |
- } |
-} |
- |
-void GpuChannelMessageQueue::UpdateStateIdle() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(!timer_->IsRunning()); |
- if (!channel_messages_.empty()) |
- TransitionToWaiting(); |
-} |
- |
-void GpuChannelMessageQueue::UpdateStateWaiting() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- // Transition to CHECKING if timer fired. |
- if (!timer_->IsRunning()) |
- TransitionToChecking(); |
-} |
- |
-void GpuChannelMessageQueue::UpdateStateChecking() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- if (!channel_messages_.empty()) { |
- base::TimeTicks time_recv = channel_messages_.front()->time_received; |
- base::TimeDelta time_elapsed = base::TimeTicks::Now() - time_recv; |
- if (time_elapsed.InMilliseconds() < kPreemptWaitTimeMs) { |
- // Schedule another check for when the IPC may go long. |
- timer_->Start( |
- FROM_HERE, |
- base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs) - time_elapsed, |
- this, &GpuChannelMessageQueue::UpdatePreemptionState); |
- } else { |
- timer_->Stop(); |
- if (!scheduled_) |
- TransitionToWouldPreemptDescheduled(); |
- else |
- TransitionToPreempting(); |
- } |
- } |
-} |
- |
-void GpuChannelMessageQueue::UpdateStatePreempting() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- // We should stop preempting if the timer fired or for other conditions. |
- if (!timer_->IsRunning() || ShouldTransitionToIdle()) { |
- TransitionToIdle(); |
- } else if (!scheduled_) { |
- // Save the remaining preemption time before stopping the timer. |
- max_preemption_time_ = timer_->desired_run_time() - base::TimeTicks::Now(); |
- timer_->Stop(); |
- TransitionToWouldPreemptDescheduled(); |
- } |
-} |
- |
-void GpuChannelMessageQueue::UpdateStateWouldPreemptDescheduled() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(!timer_->IsRunning()); |
- if (ShouldTransitionToIdle()) { |
- TransitionToIdle(); |
- } else if (scheduled_) { |
- TransitionToPreempting(); |
- } |
-} |
- |
-bool GpuChannelMessageQueue::ShouldTransitionToIdle() const { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(preemption_state_ == PREEMPTING || |
- preemption_state_ == WOULD_PREEMPT_DESCHEDULED); |
- if (channel_messages_.empty()) { |
- return true; |
- } else { |
- base::TimeTicks next_tick = channel_messages_.front()->time_received; |
- base::TimeDelta time_elapsed = base::TimeTicks::Now() - next_tick; |
- if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs) |
- return true; |
- } |
- return false; |
-} |
- |
-void GpuChannelMessageQueue::TransitionToIdle() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(preemption_state_ == PREEMPTING || |
- preemption_state_ == WOULD_PREEMPT_DESCHEDULED); |
- |
- preemption_state_ = IDLE; |
- preempting_flag_->Reset(); |
- |
- max_preemption_time_ = base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs); |
- timer_->Stop(); |
- |
- TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0); |
- |
- UpdateStateIdle(); |
-} |
- |
-void GpuChannelMessageQueue::TransitionToWaiting() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK_EQ(preemption_state_, IDLE); |
- DCHECK(!timer_->IsRunning()); |
- |
- preemption_state_ = WAITING; |
- |
- timer_->Start(FROM_HERE, |
- base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs), this, |
- &GpuChannelMessageQueue::UpdatePreemptionState); |
-} |
- |
-void GpuChannelMessageQueue::TransitionToChecking() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK_EQ(preemption_state_, WAITING); |
- DCHECK(!timer_->IsRunning()); |
- |
- preemption_state_ = CHECKING; |
- |
- UpdateStateChecking(); |
-} |
- |
-void GpuChannelMessageQueue::TransitionToPreempting() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(preemption_state_ == CHECKING || |
- preemption_state_ == WOULD_PREEMPT_DESCHEDULED); |
- DCHECK(scheduled_); |
- |
- preemption_state_ = PREEMPTING; |
- preempting_flag_->Set(); |
- TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 1); |
- |
- DCHECK_LE(max_preemption_time_, |
- base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs)); |
- timer_->Start(FROM_HERE, max_preemption_time_, this, |
- &GpuChannelMessageQueue::UpdatePreemptionState); |
-} |
- |
-void GpuChannelMessageQueue::TransitionToWouldPreemptDescheduled() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- DCHECK(preempting_flag_); |
- channel_lock_.AssertAcquired(); |
- DCHECK(preemption_state_ == CHECKING || preemption_state_ == PREEMPTING); |
- DCHECK(!scheduled_); |
- |
- preemption_state_ = WOULD_PREEMPT_DESCHEDULED; |
- preempting_flag_->Reset(); |
- TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0); |
-} |
- |
-GpuChannelMessageFilter::GpuChannelMessageFilter() |
- : sender_(nullptr), peer_pid_(base::kNullProcessId) {} |
- |
-GpuChannelMessageFilter::~GpuChannelMessageFilter() {} |
- |
-void GpuChannelMessageFilter::OnFilterAdded(IPC::Sender* sender) { |
- DCHECK(!sender_); |
- sender_ = sender; |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnFilterAdded(sender_); |
- } |
-} |
- |
-void GpuChannelMessageFilter::OnFilterRemoved() { |
- DCHECK(sender_); |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnFilterRemoved(); |
- } |
- sender_ = nullptr; |
- peer_pid_ = base::kNullProcessId; |
-} |
- |
-void GpuChannelMessageFilter::OnChannelConnected(int32_t peer_pid) { |
- DCHECK(peer_pid_ == base::kNullProcessId); |
- peer_pid_ = peer_pid; |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnChannelConnected(peer_pid); |
- } |
-} |
- |
-void GpuChannelMessageFilter::OnChannelError() { |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnChannelError(); |
- } |
-} |
- |
-void GpuChannelMessageFilter::OnChannelClosing() { |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnChannelClosing(); |
- } |
-} |
- |
-void GpuChannelMessageFilter::AddChannelFilter( |
- scoped_refptr<IPC::MessageFilter> filter) { |
- channel_filters_.push_back(filter); |
- if (sender_) |
- filter->OnFilterAdded(sender_); |
- if (peer_pid_ != base::kNullProcessId) |
- filter->OnChannelConnected(peer_pid_); |
-} |
- |
-void GpuChannelMessageFilter::RemoveChannelFilter( |
- scoped_refptr<IPC::MessageFilter> filter) { |
- if (sender_) |
- filter->OnFilterRemoved(); |
- channel_filters_.erase( |
- std::find(channel_filters_.begin(), channel_filters_.end(), filter)); |
-} |
- |
-// This gets called from the main thread and assumes that all messages which |
-// lead to creation of a new route are synchronous messages. |
-// TODO(sunnyps): Create routes (and streams) on the IO thread so that we can |
-// make the CreateCommandBuffer/VideoDecoder/VideoEncoder messages asynchronous. |
-void GpuChannelMessageFilter::AddRoute( |
- int32_t route_id, |
- const scoped_refptr<GpuChannelMessageQueue>& queue) { |
- base::AutoLock lock(routes_lock_); |
- routes_.insert(std::make_pair(route_id, queue)); |
-} |
- |
-void GpuChannelMessageFilter::RemoveRoute(int32_t route_id) { |
- base::AutoLock lock(routes_lock_); |
- routes_.erase(route_id); |
-} |
- |
-bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) { |
- DCHECK(sender_); |
- |
- if (message.should_unblock() || message.is_reply()) |
- return MessageErrorHandler(message, "Unexpected message type"); |
- |
- if (message.type() == GpuChannelMsg_Nop::ID) { |
- IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); |
- Send(reply); |
- return true; |
- } |
- |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- if (filter->OnMessageReceived(message)) |
- return true; |
- } |
- |
- scoped_refptr<GpuChannelMessageQueue> message_queue = |
- LookupStreamByRoute(message.routing_id()); |
- |
- if (!message_queue) |
- return MessageErrorHandler(message, "Could not find message queue"); |
- |
- if (!message_queue->PushBackMessage(message)) |
- return MessageErrorHandler(message, "Channel destroyed"); |
- |
- return true; |
-} |
- |
-bool GpuChannelMessageFilter::Send(IPC::Message* message) { |
- return sender_->Send(message); |
-} |
- |
-scoped_refptr<GpuChannelMessageQueue> |
-GpuChannelMessageFilter::LookupStreamByRoute(int32_t route_id) { |
- base::AutoLock lock(routes_lock_); |
- auto it = routes_.find(route_id); |
- if (it != routes_.end()) |
- return it->second; |
- return nullptr; |
-} |
- |
-bool GpuChannelMessageFilter::MessageErrorHandler(const IPC::Message& message, |
- const char* error_msg) { |
- DLOG(ERROR) << error_msg; |
- if (message.is_sync()) { |
- IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); |
- reply->set_reply_error(); |
- Send(reply); |
- } |
- return true; |
-} |
- |
-GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, |
- gpu::SyncPointManager* sync_point_manager, |
- GpuWatchdog* watchdog, |
- gfx::GLShareGroup* share_group, |
- gpu::gles2::MailboxManager* mailbox, |
- 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) |
- : gpu_channel_manager_(gpu_channel_manager), |
- sync_point_manager_(sync_point_manager), |
- unhandled_message_listener_(nullptr), |
- channel_id_(IPC::Channel::GenerateVerifiedChannelID("gpu")), |
- preempting_flag_(preempting_flag), |
- preempted_flag_(preempted_flag), |
- client_id_(client_id), |
- client_tracing_id_(client_tracing_id), |
- task_runner_(task_runner), |
- io_task_runner_(io_task_runner), |
- share_group_(share_group), |
- mailbox_manager_(mailbox), |
- subscription_ref_set_(new gpu::gles2::SubscriptionRefSet), |
- pending_valuebuffer_state_(new gpu::ValueStateMap), |
- watchdog_(watchdog), |
- allow_view_command_buffers_(allow_view_command_buffers), |
- allow_real_time_streams_(allow_real_time_streams), |
- weak_factory_(this) { |
- DCHECK(gpu_channel_manager); |
- DCHECK(client_id); |
- |
- filter_ = new GpuChannelMessageFilter(); |
- |
- scoped_refptr<GpuChannelMessageQueue> control_queue = |
- CreateStream(gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::HIGH); |
- AddRouteToStream(MSG_ROUTING_CONTROL, gpu::GPU_STREAM_DEFAULT); |
- |
- subscription_ref_set_->AddObserver(this); |
-} |
- |
-GpuChannel::~GpuChannel() { |
- // Clear stubs first because of dependencies. |
- stubs_.clear(); |
- |
- for (auto& kv : streams_) |
- kv.second->Disable(); |
- |
- subscription_ref_set_->RemoveObserver(this); |
- if (preempting_flag_.get()) |
- preempting_flag_->Reset(); |
-} |
- |
-IPC::ChannelHandle GpuChannel::Init(base::WaitableEvent* shutdown_event) { |
- DCHECK(shutdown_event); |
- DCHECK(!channel_); |
- |
- IPC::ChannelHandle channel_handle(channel_id_); |
- |
- channel_ = |
- IPC::SyncChannel::Create(channel_handle, IPC::Channel::MODE_SERVER, this, |
- io_task_runner_, false, shutdown_event); |
- |
-#if defined(OS_POSIX) |
- // On POSIX, pass the renderer-side FD. Also mark it as auto-close so |
- // that it gets closed after it has been sent. |
- base::ScopedFD renderer_fd = channel_->TakeClientFileDescriptor(); |
- DCHECK(renderer_fd.is_valid()); |
- channel_handle.socket = base::FileDescriptor(std::move(renderer_fd)); |
-#endif |
- |
- channel_->AddFilter(filter_.get()); |
- |
- return channel_handle; |
-} |
- |
-void GpuChannel::SetUnhandledMessageListener(IPC::Listener* listener) { |
- unhandled_message_listener_ = listener; |
-} |
- |
-base::WeakPtr<GpuChannel> GpuChannel::AsWeakPtr() { |
- return weak_factory_.GetWeakPtr(); |
-} |
- |
-base::ProcessId GpuChannel::GetClientPID() const { |
- return channel_->GetPeerPID(); |
-} |
- |
-uint32_t GpuChannel::GetProcessedOrderNum() const { |
- uint32_t processed_order_num = 0; |
- for (auto& kv : streams_) { |
- processed_order_num = |
- std::max(processed_order_num, kv.second->GetProcessedOrderNum()); |
- } |
- return processed_order_num; |
-} |
- |
-uint32_t GpuChannel::GetUnprocessedOrderNum() const { |
- uint32_t unprocessed_order_num = 0; |
- for (auto& kv : streams_) { |
- unprocessed_order_num = |
- std::max(unprocessed_order_num, kv.second->GetUnprocessedOrderNum()); |
- } |
- return unprocessed_order_num; |
-} |
- |
-bool GpuChannel::OnMessageReceived(const IPC::Message& msg) { |
- // All messages should be pushed to channel_messages_ and handled separately. |
- NOTREACHED(); |
- return false; |
-} |
- |
-void GpuChannel::OnChannelError() { |
- gpu_channel_manager_->RemoveChannel(client_id_); |
-} |
- |
-bool GpuChannel::Send(IPC::Message* message) { |
- // The GPU process must never send a synchronous IPC message to the renderer |
- // process. This could result in deadlock. |
- DCHECK(!message->is_sync()); |
- |
- DVLOG(1) << "sending message @" << message << " on channel @" << this |
- << " with type " << message->type(); |
- |
- if (!channel_) { |
- delete message; |
- return false; |
- } |
- |
- return channel_->Send(message); |
-} |
- |
-void GpuChannel::OnAddSubscription(unsigned int target) { |
- gpu_channel_manager()->delegate()->AddSubscription(client_id_, target); |
-} |
- |
-void GpuChannel::OnRemoveSubscription(unsigned int target) { |
- gpu_channel_manager()->delegate()->RemoveSubscription(client_id_, target); |
-} |
- |
-void GpuChannel::OnStreamRescheduled(int32_t stream_id, bool scheduled) { |
- scoped_refptr<GpuChannelMessageQueue> queue = LookupStream(stream_id); |
- DCHECK(queue); |
- queue->OnRescheduled(scheduled); |
-} |
- |
-GpuCommandBufferStub* GpuChannel::LookupCommandBuffer(int32_t route_id) { |
- return stubs_.get(route_id); |
-} |
- |
-void GpuChannel::LoseAllContexts() { |
- gpu_channel_manager_->LoseAllContexts(); |
-} |
- |
-void GpuChannel::MarkAllContextsLost() { |
- for (auto& kv : stubs_) |
- kv.second->MarkContextLost(); |
-} |
- |
-bool GpuChannel::AddRoute(int32_t route_id, |
- int32_t stream_id, |
- IPC::Listener* listener) { |
- if (router_.AddRoute(route_id, listener)) { |
- AddRouteToStream(route_id, stream_id); |
- return true; |
- } |
- return false; |
-} |
- |
-void GpuChannel::RemoveRoute(int32_t route_id) { |
- router_.RemoveRoute(route_id); |
- RemoveRouteFromStream(route_id); |
-} |
- |
-bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { |
- bool handled = true; |
- IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) |
- IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateCommandBuffer, |
- OnCreateCommandBuffer) |
- IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, |
- OnDestroyCommandBuffer) |
- IPC_MESSAGE_HANDLER(GpuChannelMsg_GetDriverBugWorkArounds, |
- OnGetDriverBugWorkArounds) |
- IPC_MESSAGE_UNHANDLED(handled = false) |
- IPC_END_MESSAGE_MAP() |
- return handled; |
-} |
- |
-scoped_refptr<gpu::SyncPointOrderData> GpuChannel::GetSyncPointOrderData( |
- int32_t stream_id) { |
- auto it = streams_.find(stream_id); |
- DCHECK(it != streams_.end()); |
- DCHECK(it->second); |
- return it->second->GetSyncPointOrderData(); |
-} |
- |
-void GpuChannel::PostHandleMessage( |
- const scoped_refptr<GpuChannelMessageQueue>& queue) { |
- task_runner_->PostTask(FROM_HERE, |
- base::Bind(&GpuChannel::HandleMessage, |
- weak_factory_.GetWeakPtr(), queue)); |
-} |
- |
-void GpuChannel::PostHandleOutOfOrderMessage(const IPC::Message& msg) { |
- task_runner_->PostTask(FROM_HERE, |
- base::Bind(&GpuChannel::HandleOutOfOrderMessage, |
- weak_factory_.GetWeakPtr(), msg)); |
-} |
- |
-void GpuChannel::HandleMessage( |
- const scoped_refptr<GpuChannelMessageQueue>& message_queue) { |
- const GpuChannelMessage* channel_msg = |
- message_queue->BeginMessageProcessing(); |
- if (!channel_msg) |
- return; |
- |
- const IPC::Message& msg = channel_msg->message; |
- int32_t routing_id = msg.routing_id(); |
- GpuCommandBufferStub* stub = stubs_.get(routing_id); |
- |
- DCHECK(!stub || stub->IsScheduled()); |
- |
- DVLOG(1) << "received message @" << &msg << " on channel @" << this |
- << " with type " << msg.type(); |
- |
- HandleMessageHelper(msg); |
- |
- // If we get descheduled or yield while processing a message. |
- if (stub && stub->HasUnprocessedCommands()) { |
- DCHECK_EQ((uint32_t)GpuCommandBufferMsg_AsyncFlush::ID, msg.type()); |
- message_queue->PauseMessageProcessing(); |
- } else { |
- message_queue->FinishMessageProcessing(); |
- } |
-} |
- |
-void GpuChannel::HandleMessageHelper(const IPC::Message& msg) { |
- int32_t routing_id = msg.routing_id(); |
- |
- bool handled = false; |
- if (routing_id == MSG_ROUTING_CONTROL) { |
- handled = OnControlMessageReceived(msg); |
- } else { |
- handled = router_.RouteMessage(msg); |
- } |
- |
- if (!handled && unhandled_message_listener_) |
- handled = unhandled_message_listener_->OnMessageReceived(msg); |
- |
- // Respond to sync messages even if router failed to route. |
- if (!handled && msg.is_sync()) { |
- IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); |
- reply->set_reply_error(); |
- Send(reply); |
- } |
-} |
- |
-void GpuChannel::HandleOutOfOrderMessage(const IPC::Message& msg) { |
- HandleMessageHelper(msg); |
-} |
- |
-void GpuChannel::HandleMessageForTesting(const IPC::Message& msg) { |
- HandleMessageHelper(msg); |
-} |
- |
-scoped_refptr<GpuChannelMessageQueue> GpuChannel::CreateStream( |
- int32_t stream_id, |
- gpu::GpuStreamPriority stream_priority) { |
- DCHECK(streams_.find(stream_id) == streams_.end()); |
- scoped_refptr<GpuChannelMessageQueue> queue = GpuChannelMessageQueue::Create( |
- stream_id, stream_priority, this, io_task_runner_, |
- (stream_id == gpu::GPU_STREAM_DEFAULT) ? preempting_flag_ : nullptr, |
- preempted_flag_, sync_point_manager_); |
- streams_.insert(std::make_pair(stream_id, queue)); |
- streams_to_num_routes_.insert(std::make_pair(stream_id, 0)); |
- return queue; |
-} |
- |
-scoped_refptr<GpuChannelMessageQueue> GpuChannel::LookupStream( |
- int32_t stream_id) { |
- auto stream_it = streams_.find(stream_id); |
- if (stream_it != streams_.end()) |
- return stream_it->second; |
- return nullptr; |
-} |
- |
-void GpuChannel::DestroyStreamIfNecessary( |
- const scoped_refptr<GpuChannelMessageQueue>& queue) { |
- int32_t stream_id = queue->stream_id(); |
- if (streams_to_num_routes_[stream_id] == 0) { |
- queue->Disable(); |
- streams_to_num_routes_.erase(stream_id); |
- streams_.erase(stream_id); |
- } |
-} |
- |
-void GpuChannel::AddRouteToStream(int32_t route_id, int32_t stream_id) { |
- DCHECK(streams_.find(stream_id) != streams_.end()); |
- DCHECK(routes_to_streams_.find(route_id) == routes_to_streams_.end()); |
- streams_to_num_routes_[stream_id]++; |
- routes_to_streams_.insert(std::make_pair(route_id, stream_id)); |
- filter_->AddRoute(route_id, streams_[stream_id]); |
-} |
- |
-void GpuChannel::RemoveRouteFromStream(int32_t route_id) { |
- DCHECK(routes_to_streams_.find(route_id) != routes_to_streams_.end()); |
- int32_t stream_id = routes_to_streams_[route_id]; |
- DCHECK(streams_.find(stream_id) != streams_.end()); |
- routes_to_streams_.erase(route_id); |
- streams_to_num_routes_[stream_id]--; |
- filter_->RemoveRoute(route_id); |
- DestroyStreamIfNecessary(streams_[stream_id]); |
-} |
- |
-#if defined(OS_ANDROID) |
-const GpuCommandBufferStub* GpuChannel::GetOneStub() const { |
- for (const auto& kv : stubs_) { |
- const GpuCommandBufferStub* stub = kv.second; |
- if (stub->decoder() && !stub->decoder()->WasContextLost()) |
- return stub; |
- } |
- return nullptr; |
-} |
-#endif |
- |
-void GpuChannel::OnCreateCommandBuffer( |
- gpu::SurfaceHandle surface_handle, |
- const gfx::Size& size, |
- const GPUCreateCommandBufferConfig& init_params, |
- int32_t route_id, |
- bool* succeeded) { |
- TRACE_EVENT2("gpu", "GpuChannel::OnCreateCommandBuffer", "route_id", route_id, |
- "offscreen", (surface_handle == gpu::kNullSurfaceHandle)); |
- *succeeded = false; |
- if (surface_handle != gpu::kNullSurfaceHandle && |
- !allow_view_command_buffers_) { |
- DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): attempt to create a " |
- "view context on a non-priviledged channel"; |
- return; |
- } |
- |
- int32_t share_group_id = init_params.share_group_id; |
- GpuCommandBufferStub* share_group = stubs_.get(share_group_id); |
- |
- if (!share_group && share_group_id != MSG_ROUTING_NONE) { |
- DLOG(ERROR) |
- << "GpuChannel::OnCreateCommandBuffer(): invalid share group id"; |
- return; |
- } |
- |
- int32_t stream_id = init_params.stream_id; |
- if (share_group && stream_id != share_group->stream_id()) { |
- DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): stream id does not " |
- "match share group stream id"; |
- return; |
- } |
- |
- gpu::GpuStreamPriority stream_priority = init_params.stream_priority; |
- if (!allow_real_time_streams_ && |
- stream_priority == gpu::GpuStreamPriority::REAL_TIME) { |
- DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): real time stream " |
- "priority not allowed"; |
- return; |
- } |
- |
- scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( |
- this, sync_point_manager_, task_runner_.get(), share_group, |
- surface_handle, mailbox_manager_.get(), preempted_flag_.get(), |
- subscription_ref_set_.get(), pending_valuebuffer_state_.get(), size, |
- disallowed_features_, init_params.attribs, init_params.gpu_preference, |
- init_params.stream_id, route_id, watchdog_, init_params.active_url)); |
- |
- scoped_refptr<GpuChannelMessageQueue> queue = LookupStream(stream_id); |
- if (!queue) |
- queue = CreateStream(stream_id, stream_priority); |
- |
- if (!AddRoute(route_id, stream_id, stub.get())) { |
- DestroyStreamIfNecessary(queue); |
- DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): failed to add route"; |
- return; |
- } |
- |
- stubs_.set(route_id, std::move(stub)); |
- *succeeded = true; |
-} |
- |
-void GpuChannel::OnDestroyCommandBuffer(int32_t route_id) { |
- TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer", |
- "route_id", route_id); |
- |
- scoped_ptr<GpuCommandBufferStub> stub = stubs_.take_and_erase(route_id); |
- // In case the renderer is currently blocked waiting for a sync reply from the |
- // stub, we need to make sure to reschedule the correct stream here. |
- if (stub && !stub->IsScheduled()) { |
- // This stub won't get a chance to reschedule the stream so do that now. |
- OnStreamRescheduled(stub->stream_id(), true); |
- } |
- |
- RemoveRoute(route_id); |
-} |
- |
-void GpuChannel::OnGetDriverBugWorkArounds( |
- std::vector<std::string>* gpu_driver_bug_workarounds) { |
- // TODO(j.isorce): http://crbug.com/599964 Do the extraction of workarounds in |
- // the GpuChannelManager constructor. Currently it is done in the FeatureInfo |
- // constructor. There is no need to extract them from the command-line every |
- // time a new FeatureInfo is created (i.e. per ContextGroup) since parsing |
- // result is a constant. |
- scoped_refptr<gpu::gles2::FeatureInfo> feature_info = |
- new gpu::gles2::FeatureInfo; |
- gpu_driver_bug_workarounds->clear(); |
-#define GPU_OP(type, name) \ |
- if (feature_info->workarounds().name) \ |
- gpu_driver_bug_workarounds->push_back(#name); |
- GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) |
-#undef GPU_OP |
-} |
- |
-void GpuChannel::CacheShader(const std::string& key, |
- const std::string& shader) { |
- gpu_channel_manager_->delegate()->StoreShaderToDisk(client_id_, key, shader); |
-} |
- |
-void GpuChannel::AddFilter(IPC::MessageFilter* filter) { |
- io_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&GpuChannelMessageFilter::AddChannelFilter, |
- filter_, make_scoped_refptr(filter))); |
-} |
- |
-void GpuChannel::RemoveFilter(IPC::MessageFilter* filter) { |
- io_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&GpuChannelMessageFilter::RemoveChannelFilter, |
- filter_, make_scoped_refptr(filter))); |
-} |
- |
-uint64_t GpuChannel::GetMemoryUsage() { |
- // Collect the unique memory trackers in use by the |stubs_|. |
- std::set<gpu::gles2::MemoryTracker*> unique_memory_trackers; |
- for (auto& kv : stubs_) |
- unique_memory_trackers.insert(kv.second->GetMemoryTracker()); |
- |
- // Sum the memory usage for all unique memory trackers. |
- uint64_t size = 0; |
- for (auto* tracker : unique_memory_trackers) { |
- size += gpu_channel_manager()->gpu_memory_manager()->GetTrackerMemoryUsage( |
- tracker); |
- } |
- |
- return size; |
-} |
- |
-scoped_refptr<gl::GLImage> GpuChannel::CreateImageForGpuMemoryBuffer( |
- const gfx::GpuMemoryBufferHandle& handle, |
- const gfx::Size& size, |
- gfx::BufferFormat format, |
- uint32_t internalformat) { |
- switch (handle.type) { |
- case gfx::SHARED_MEMORY_BUFFER: { |
- if (!base::IsValueInRangeForNumericType<size_t>(handle.stride)) |
- return nullptr; |
- scoped_refptr<gl::GLImageSharedMemory> image( |
- new gl::GLImageSharedMemory(size, internalformat)); |
- if (!image->Initialize(handle.handle, handle.id, format, handle.offset, |
- handle.stride)) { |
- return nullptr; |
- } |
- |
- return image; |
- } |
- default: { |
- GpuChannelManager* manager = gpu_channel_manager(); |
- if (!manager->gpu_memory_buffer_factory()) |
- return nullptr; |
- |
- return manager->gpu_memory_buffer_factory() |
- ->AsImageFactory() |
- ->CreateImageForGpuMemoryBuffer(handle, |
- size, |
- format, |
- internalformat, |
- client_id_); |
- } |
- } |
-} |
- |
-void GpuChannel::HandleUpdateValueState( |
- unsigned int target, const gpu::ValueState& state) { |
- pending_valuebuffer_state_->UpdateState(target, state); |
-} |
- |
-} // namespace content |