| Index: content/common/gpu/gpu_channel.cc
|
| diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
|
| index 64e6a1943216664be4528788aeab5b60ac8dd0d0..364260c817e0fb44f5106476ec0279c4da9c81e7 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,6 @@ 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();
|
| if (log_messages_) {
|
| DVLOG(1) << "received message @" << &message << " on channel @" << this
|
| << " with type " << message.type();
|
| @@ -304,9 +331,12 @@ bool GpuChannel::OnMessageReceived(const IPC::Message& message) {
|
|
|
| // Control messages are not deferred and can be handled out of order with
|
| // respect to routed ones.
|
| - if (message.routing_id() == MSG_ROUTING_CONTROL)
|
| + if (message.routing_id() == MSG_ROUTING_CONTROL) {
|
| + MessageProcessed();
|
| return OnControlMessageReceived(message);
|
| + }
|
|
|
| + bool message_processed = true;
|
| if (message.type() == GpuCommandBufferMsg_GetStateFast::ID) {
|
| if (processed_get_state_fast_) {
|
| // Require a non-GetStateFast message in between two GetStateFast
|
| @@ -323,18 +353,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 +398,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 +449,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 +515,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,16 +569,21 @@ 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();
|
| }
|
| return;
|
| }
|
|
|
| + if (stub && stub->IsPreempted()) {
|
| + OnScheduled();
|
| + return;
|
| + }
|
| +
|
| 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 +608,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 +649,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 +732,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
|
|
|