diff options
Diffstat (limited to 'content/common/gpu/gpu_channel.cc')
-rw-r--r-- | content/common/gpu/gpu_channel.cc | 250 |
1 files changed, 145 insertions, 105 deletions
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index 64e6a19..217d9ef 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc @@ -15,6 +15,7 @@ #include "base/process_util.h" #include "base/rand_util.h" #include "base/string_util.h" +#include "base/timer.h" #include "content/common/child_process.h" #include "content/common/gpu/gpu_channel_manager.h" #include "content/common/gpu/gpu_messages.h" @@ -40,6 +41,87 @@ namespace content { namespace { + +// How long to wait for an IPC on this channel to be processed before +// signaling the need for a preemption. +// TODO(backer): This should really be the time between vblank on +// platforms that provide this information. +const int64 kPreemptPeriodMs = 16; + +// Generates mailbox names for clients of the GPU process on the IO thread. +class MailboxMessageFilter : public IPC::ChannelProxy::MessageFilter { + public: + explicit MailboxMessageFilter(const std::string& private_key) + : channel_(NULL), + hmac_(crypto::HMAC::SHA256) { + bool success = hmac_.Init(base::StringPiece(private_key)); + DCHECK(success); + } + + virtual void OnFilterAdded(IPC::Channel* channel) { + DCHECK(!channel_); + channel_ = channel; + } + + virtual void OnFilterRemoved() { + DCHECK(channel_); + channel_ = NULL; + } + + virtual bool OnMessageReceived(const IPC::Message& message) { + DCHECK(channel_); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MailboxMessageFilter, message) + IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNames, + OnGenerateMailboxNames) + IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNamesAsync, + OnGenerateMailboxNamesAsync) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; + } + + bool Send(IPC::Message* message) { + return channel_->Send(message); + } + + private: + ~MailboxMessageFilter() { + } + + // Message handlers. + void OnGenerateMailboxNames(unsigned num, std::vector<std::string>* result) { + TRACE_EVENT1("gpu", "OnGenerateMailboxNames", "num", num); + + result->resize(num); + + for (unsigned i = 0; i < num; ++i) { + char name[GL_MAILBOX_SIZE_CHROMIUM]; + base::RandBytes(name, sizeof(name) / 2); + + bool success = hmac_.Sign( + base::StringPiece(name, sizeof(name) / 2), + reinterpret_cast<unsigned char*>(name) + sizeof(name) / 2, + sizeof(name) / 2); + DCHECK(success); + + (*result)[i].assign(name, sizeof(name)); + } + } + + void OnGenerateMailboxNamesAsync(unsigned num) { + std::vector<std::string> names; + OnGenerateMailboxNames(num, &names); + Send(new GpuChannelMsg_GenerateMailboxNamesReply(names)); + } + + IPC::Channel* channel_; + crypto::HMAC hmac_; +}; +} // anonymous namespace + // This filter does two things: // - it counts the number of messages coming in on the channel // - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO @@ -52,12 +134,13 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { SyncPointMessageFilter(base::WeakPtr<GpuChannel>* gpu_channel, scoped_refptr<SyncPointManager> sync_point_manager, scoped_refptr<base::MessageLoopProxy> message_loop, - scoped_refptr<gpu::RefCountedCounter> - unprocessed_messages) + scoped_refptr<gpu::PreemptionFlag> processing_stalled, + base::AtomicRefCount* unprocessed_messages) : gpu_channel_(gpu_channel), channel_(NULL), sync_point_manager_(sync_point_manager), message_loop_(message_loop), + processing_stalled_(processing_stalled), unprocessed_messages_(unprocessed_messages) { } @@ -73,7 +156,11 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { virtual bool OnMessageReceived(const IPC::Message& message) { DCHECK(channel_); - unprocessed_messages_->IncCount(); + base::AtomicRefCountInc(unprocessed_messages_.get()); + if (!timer_.IsRunning()) + timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kPreemptPeriodMs), + this, &SyncPointMessageFilter::TriggerPreemption); if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) { uint32 sync_point = sync_point_manager_->GenerateSyncPoint(); IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); @@ -85,18 +172,29 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { sync_point_manager_, message.routing_id(), sync_point, - unprocessed_messages_)); + unprocessed_messages_.get())); return true; } else if (message.type() == GpuCommandBufferMsg_RetireSyncPoint::ID) { // This message should not be sent explicitly by the renderer. NOTREACHED(); - unprocessed_messages_->DecCount(); + base::AtomicRefCountDec(unprocessed_messages_.get()); return true; } else { return false; } } + void TriggerPreemption() { + if (!base::AtomicRefCountIsZero(unprocessed_messages_.get())) + processing_stalled_->Set(); + } + + void ReschedulePreemption() { + processing_stalled_->Reset(); + if (timer_.IsRunning()) + timer_.Reset(); + } + protected: virtual ~SyncPointMessageFilter() { message_loop_->PostTask(FROM_HERE, base::Bind( @@ -109,7 +207,7 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { scoped_refptr<SyncPointManager> manager, int32 routing_id, uint32 sync_point, - scoped_refptr<gpu::RefCountedCounter> unprocessed_messages_) { + base::AtomicRefCount* unprocessed_messages) { // This function must ensure that the sync point will be retired. Normally // we'll find the stub based on the routing ID, and associate the sync point // with it, but if that fails for any reason (channel or stub already @@ -124,7 +222,7 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { gpu_channel->get()->OnMessageReceived(message); return; } else { - unprocessed_messages_->DecCount(); + base::AtomicRefCountDec(unprocessed_messages); } } manager->RetireSyncPoint(sync_point); @@ -142,83 +240,11 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter { IPC::Channel* channel_; scoped_refptr<SyncPointManager> sync_point_manager_; scoped_refptr<base::MessageLoopProxy> message_loop_; - scoped_refptr<gpu::RefCountedCounter> unprocessed_messages_; + scoped_refptr<gpu::PreemptionFlag> processing_stalled_; + scoped_ptr<base::AtomicRefCount> unprocessed_messages_; + base::OneShotTimer<SyncPointMessageFilter> timer_; }; -// Generates mailbox names for clients of the GPU process on the IO thread. -class MailboxMessageFilter : public IPC::ChannelProxy::MessageFilter { - public: - explicit MailboxMessageFilter(const std::string& private_key) - : channel_(NULL), - hmac_(crypto::HMAC::SHA256) { - bool success = hmac_.Init(base::StringPiece(private_key)); - DCHECK(success); - } - - virtual void OnFilterAdded(IPC::Channel* channel) { - DCHECK(!channel_); - channel_ = channel; - } - - virtual void OnFilterRemoved() { - DCHECK(channel_); - channel_ = NULL; - } - - virtual bool OnMessageReceived(const IPC::Message& message) { - DCHECK(channel_); - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(MailboxMessageFilter, message) - IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNames, - OnGenerateMailboxNames) - IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNamesAsync, - OnGenerateMailboxNamesAsync) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; - } - - bool Send(IPC::Message* message) { - return channel_->Send(message); - } - - private: - ~MailboxMessageFilter() { - } - - // Message handlers. - void OnGenerateMailboxNames(unsigned num, std::vector<std::string>* result) { - TRACE_EVENT1("gpu", "OnGenerateMailboxNames", "num", num); - - result->resize(num); - - for (unsigned i = 0; i < num; ++i) { - char name[GL_MAILBOX_SIZE_CHROMIUM]; - base::RandBytes(name, sizeof(name) / 2); - - bool success = hmac_.Sign( - base::StringPiece(name, sizeof(name) / 2), - reinterpret_cast<unsigned char*>(name) + sizeof(name) / 2, - sizeof(name) / 2); - DCHECK(success); - - (*result)[i].assign(name, sizeof(name)); - } - } - - void OnGenerateMailboxNamesAsync(unsigned num) { - std::vector<std::string> names; - OnGenerateMailboxNames(num, &names); - Send(new GpuChannelMsg_GenerateMailboxNamesReply(names)); - } - - IPC::Channel* channel_; - crypto::HMAC hmac_; -}; -} // anonymous namespace - GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, GpuWatchdog* watchdog, gfx::GLShareGroup* share_group, @@ -226,7 +252,8 @@ GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, int client_id, bool software) : gpu_channel_manager_(gpu_channel_manager), - unprocessed_messages_(new gpu::RefCountedCounter), + unprocessed_messages_(NULL), + processing_stalled_(new gpu::PreemptionFlag), client_id_(client_id), share_group_(share_group ? share_group : new gfx::GLShareGroup), mailbox_manager_(mailbox ? mailbox : new gpu::gles2::MailboxManager), @@ -266,12 +293,15 @@ bool GpuChannel::Init(base::MessageLoopProxy* io_message_loop, base::WeakPtr<GpuChannel>* weak_ptr(new base::WeakPtr<GpuChannel>( weak_factory_.GetWeakPtr())); - scoped_refptr<SyncPointMessageFilter> filter(new SyncPointMessageFilter( + unprocessed_messages_ = new base::AtomicRefCount(0); + filter_ = new SyncPointMessageFilter( weak_ptr, gpu_channel_manager_->sync_point_manager(), base::MessageLoopProxy::current(), - unprocessed_messages_)); - channel_->AddFilter(filter); + processing_stalled_, + unprocessed_messages_); + io_message_loop_ = io_message_loop; + channel_->AddFilter(filter_); channel_->AddFilter( new MailboxMessageFilter(mailbox_manager_->private_key())); @@ -294,9 +324,7 @@ int GpuChannel::TakeRendererFileDescriptor() { #endif // defined(OS_POSIX) bool GpuChannel::OnMessageReceived(const IPC::Message& message) { - // Drop the count that was incremented on the IO thread because we are - // about to process that message. - unprocessed_messages_->DecCount(); + bool message_processed = true; if (log_messages_) { DVLOG(1) << "received message @" << &message << " on channel @" << this << " with type " << message.type(); @@ -323,18 +351,21 @@ bool GpuChannel::OnMessageReceived(const IPC::Message& message) { } deferred_messages_.insert(point, new IPC::Message(message)); - unprocessed_messages_->IncCount(); + message_processed = false; } else { // Move GetStateFast commands to the head of the queue, so the renderer // doesn't have to wait any longer than necessary. deferred_messages_.push_front(new IPC::Message(message)); - unprocessed_messages_->IncCount(); + message_processed = false; } } else { deferred_messages_.push_back(new IPC::Message(message)); - unprocessed_messages_->IncCount(); + message_processed = false; } + if (message_processed) + MessageProcessed(); + OnScheduled(); return true; @@ -365,7 +396,7 @@ void GpuChannel::RequeueMessage() { DCHECK(currently_processing_message_); deferred_messages_.push_front( new IPC::Message(*currently_processing_message_)); - unprocessed_messages_->IncCount(); + base::AtomicRefCountInc(unprocessed_messages_); currently_processing_message_ = NULL; } @@ -416,8 +447,8 @@ void GpuChannel::CreateViewCommandBuffer( watchdog_, software_, init_params.active_url)); - if (preempt_by_counter_.get()) - stub->SetPreemptByCounter(preempt_by_counter_); + if (preemption_flag_.get()) + stub->SetPreemptByFlag(preemption_flag_); router_.AddRoute(*route_id, stub.get()); stubs_.AddWithID(stub.release(), *route_id); #endif // ENABLE_GPU @@ -482,18 +513,18 @@ void GpuChannel::RemoveRoute(int32 route_id) { router_.RemoveRoute(route_id); } -void GpuChannel::SetPreemptByCounter( - scoped_refptr<gpu::RefCountedCounter> preempt_by_counter) { - preempt_by_counter_ = preempt_by_counter; +void GpuChannel::SetPreemptByFlag( + scoped_refptr<gpu::PreemptionFlag> preemption_flag) { + preemption_flag_ = preemption_flag; for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_); !it.IsAtEnd(); it.Advance()) { - it.GetCurrentValue()->SetPreemptByCounter(preempt_by_counter_); + it.GetCurrentValue()->SetPreemptByFlag(preemption_flag_); } } GpuChannel::~GpuChannel() { - unprocessed_messages_->Reset(); + processing_stalled_->Reset(); } void GpuChannel::OnDestroy() { @@ -536,7 +567,7 @@ void GpuChannel::HandleMessage() { if (m->type() == GpuCommandBufferMsg_Echo::ID) { stub->DelayEcho(m); deferred_messages_.pop_front(); - unprocessed_messages_->DecCount(); + MessageProcessed(); if (!deferred_messages_.empty()) OnScheduled(); } @@ -545,7 +576,7 @@ void GpuChannel::HandleMessage() { scoped_ptr<IPC::Message> message(m); deferred_messages_.pop_front(); - unprocessed_messages_->DecCount(); + bool message_processed = true; processed_get_state_fast_ = (message->type() == GpuCommandBufferMsg_GetStateFast::ID); @@ -570,10 +601,12 @@ void GpuChannel::HandleMessage() { if (stub->HasUnprocessedCommands()) { deferred_messages_.push_front(new GpuCommandBufferMsg_Rescheduled( stub->route_id())); - unprocessed_messages_->IncCount(); + message_processed = false; } } } + if (message_processed) + MessageProcessed(); } if (!deferred_messages_.empty()) { @@ -609,8 +642,8 @@ void GpuChannel::OnCreateOffscreenCommandBuffer( 0, watchdog_, software_, init_params.active_url)); - if (preempt_by_counter_.get()) - stub->SetPreemptByCounter(preempt_by_counter_); + if (preemption_flag_.get()) + stub->SetPreemptByFlag(preemption_flag_); router_.AddRoute(route_id, stub.get()); stubs_.AddWithID(stub.release(), route_id); TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", @@ -692,4 +725,11 @@ void GpuChannel::OnCollectRenderingStatsForSurface( Send(reply_message); } +void GpuChannel::MessageProcessed() { + base::AtomicRefCountDec(unprocessed_messages_); + io_message_loop_->PostTask( + FROM_HERE, + base::Bind(&SyncPointMessageFilter::ReschedulePreemption, filter_)); +} + } // namespace content |