summaryrefslogtreecommitdiffstats
path: root/content/common/gpu/gpu_channel.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/common/gpu/gpu_channel.cc')
-rw-r--r--content/common/gpu/gpu_channel.cc250
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