GPUChannel pools mailbox names.

It asynchronously refills the pool to a target size when it falls below half that size.

GenerateMailboxNames is only synchronous if the pool is depleted. Common case is a few microseconds per name.

Review URL: https://chromiumcodereview.appspot.com/11362171

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166962 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index 38cf2d66..73f53a7 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -154,6 +154,7 @@
   void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message);
   void OnSetMemoryAllocation(const GpuMemoryAllocationForRenderer& allocation);
   void OnSignalSyncPointAck(uint32 id);
+  void OnGenerateMailboxNamesReply(const std::vector<std::string>& names);
 
   // Try to read an updated copy of the state from shared memory.
   void TryUpdateState();
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 294035d..cb20909 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -71,6 +71,18 @@
   return gpu_info_;
 }
 
+void GpuChannelHost::OnMessageReceived(const IPC::Message& message) {
+    bool handled = true;
+
+    IPC_BEGIN_MESSAGE_MAP(GpuChannelHost, message)
+      IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNamesReply,
+                          OnGenerateMailboxNamesReply)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+    IPC_END_MESSAGE_MAP()
+
+    DCHECK(handled);
+}
+
 void GpuChannelHost::OnChannelError() {
   state_ = kLost;
 
@@ -246,7 +258,35 @@
                                           std::vector<std::string>* names) {
   TRACE_EVENT0("gpu", "GenerateMailboxName");
   AutoLock lock(context_lock_);
-  return Send(new GpuChannelMsg_GenerateMailboxNames(num, names));
+
+  if (num > mailbox_name_pool_.size()) {
+    if (!Send(new GpuChannelMsg_GenerateMailboxNames(num, names)))
+      return false;
+  } else {
+    names->insert(names->begin(),
+                  mailbox_name_pool_.end() - num,
+                  mailbox_name_pool_.end());
+    mailbox_name_pool_.erase(mailbox_name_pool_.end() - num,
+                             mailbox_name_pool_.end());
+  }
+
+  const unsigned ideal_mailbox_pool_size = 100;
+  if (mailbox_name_pool_.size() < ideal_mailbox_pool_size / 2) {
+    Send(new GpuChannelMsg_GenerateMailboxNamesAsync(
+        ideal_mailbox_pool_size - mailbox_name_pool_.size()));
+  }
+
+  return true;
+}
+
+void GpuChannelHost::OnGenerateMailboxNamesReply(
+    const std::vector<std::string>& names) {
+  TRACE_EVENT0("gpu", "OnGenerateMailboxNamesReply");
+  AutoLock lock(context_lock_);
+
+  mailbox_name_pool_.insert(mailbox_name_pool_.end(),
+                            names.begin(),
+                            names.end());
 }
 
 GpuChannelHost::~GpuChannelHost() {}
@@ -280,11 +320,19 @@
 bool GpuChannelHost::MessageFilter::OnMessageReceived(
     const IPC::Message& message) {
   DCHECK(parent_->factory_->IsIOThread());
+
   // Never handle sync message replies or we will deadlock here.
   if (message.is_reply())
     return false;
 
-  DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
+  if (message.routing_id() == MSG_ROUTING_CONTROL) {
+    MessageLoop* main_loop = parent_->factory_->GetMainLoop();
+    main_loop->PostTask(FROM_HERE,
+                        base::Bind(&GpuChannelHost::OnMessageReceived,
+                                   parent_,
+                                   message));
+    return true;
+  }
 
   ListenerMap::iterator it = listeners_.find(message.routing_id());
 
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 55454dc..ab5b7a9e 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -106,6 +106,7 @@
   void set_gpu_info(const GPUInfo& gpu_info);
   const GPUInfo& gpu_info() const;
 
+  void OnMessageReceived(const IPC::Message& message);
   void OnChannelError();
 
   // IPC::Sender implementation:
@@ -162,6 +163,9 @@
   friend class base::RefCountedThreadSafe<GpuChannelHost>;
   virtual ~GpuChannelHost();
 
+  // Message handlers.
+  void OnGenerateMailboxNamesReply(const std::vector<std::string>& names);
+
   // A filter used internally to route incoming messages from the IO thread
   // to the correct message loop.
   class MessageFilter : public IPC::ChannelProxy::MessageFilter {
@@ -208,6 +212,9 @@
   // A filter for sending messages from thread other than the main thread.
   scoped_refptr<IPC::SyncMessageFilter> sync_filter_;
 
+  // A pool of valid mailbox names.
+  std::vector<std::string> mailbox_name_pool_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuChannelHost);
 };
 
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index a2247db..31a116e 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -172,6 +172,8 @@
     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()
 
@@ -206,6 +208,12 @@
     }
   }
 
+  void OnGenerateMailboxNamesAsync(unsigned num) {
+    std::vector<std::string> names;
+    OnGenerateMailboxNames(num, &names);
+    Send(new GpuChannelMsg_GenerateMailboxNamesReply(names));
+  }
+
   IPC::Channel* channel_;
   crypto::HMAC hmac_;
 };
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 8af0477..f042471 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -414,11 +414,19 @@
 IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer,
                             int32 /* instance_id */)
 
-// Generates n new unique mailbox names.
+// Generates n new unique mailbox names synchronously.
 IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_GenerateMailboxNames,
                             unsigned, /* num */
                             std::vector<std::string> /* mailbox_names */)
 
+// Generates n new unique mailbox names asynchronously.
+IPC_MESSAGE_CONTROL1(GpuChannelMsg_GenerateMailboxNamesAsync,
+                     unsigned /* num */)
+
+// Reply to GpuChannelMsg_GenerateMailboxNamesAsync.
+IPC_MESSAGE_CONTROL1(GpuChannelMsg_GenerateMailboxNamesReply,
+                     std::vector<std::string> /* mailbox_names */)
+
 #if defined(OS_ANDROID)
 // Register the StreamTextureProxy class with the GPU process, so that
 // the renderer process will get notified whenever a frame becomes available.