summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/gpu_process_host.cc292
-rw-r--r--chrome/browser/gpu_process_host.h72
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc335
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.h71
-rw-r--r--chrome/browser/renderer_host/gpu_message_filter.cc22
-rw-r--r--chrome/browser/renderer_host/gpu_message_filter.h2
6 files changed, 380 insertions, 414 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
index d126a86..64e8e46 100644
--- a/chrome/browser/gpu_process_host.cc
+++ b/chrome/browser/gpu_process_host.cc
@@ -5,15 +5,12 @@
#include "chrome/browser/gpu_process_host.h"
#include "app/app_switches.h"
-#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/ref_counted.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/gpu_blacklist.h"
#include "chrome/browser/gpu_process_host_ui_shim.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
@@ -23,11 +20,9 @@
#include "chrome/common/gpu_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/gpu/gpu_thread.h"
-#include "grit/browser_resources.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_switches.h"
#include "media/base/media_switches.h"
-#include "ui/base/resource/resource_bundle.h"
#if defined(OS_LINUX)
#include "ui/gfx/gtk_native_view_id_manager.h"
@@ -114,8 +109,7 @@ class GpuMainThread : public base::Thread {
GpuProcessHost::GpuProcessHost()
: BrowserChildProcessHost(GPU_PROCESS, NULL),
initialized_(false),
- initialized_successfully_(false),
- gpu_feature_flags_set_(false) {
+ initialized_successfully_(false) {
DCHECK_EQ(sole_instance_, static_cast<GpuProcessHost*>(NULL));
}
@@ -136,9 +130,6 @@ bool GpuProcessHost::EnsureInitialized() {
}
bool GpuProcessHost::Init() {
- if (!LoadGpuBlacklist())
- return false;
-
if (!CreateChannel())
return false;
@@ -168,275 +159,28 @@ bool GpuProcessHost::Send(IPC::Message* msg) {
bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
DCHECK(CalledOnValidThread());
-
- if (message.routing_id() == MSG_ROUTING_CONTROL)
- return OnControlMessageReceived(message);
-
RouteOnUIThread(message);
return true;
}
-// Post a Task to execute callbacks on a error conditions in order to
-// clear the call stacks (and aid debugging).
-namespace {
-
-void EstablishChannelCallbackDispatcher(
- linked_ptr<GpuProcessHost::EstablishChannelCallback> callback,
- const IPC::ChannelHandle& channel_handle,
- const GPUInfo& gpu_info) {
- callback->Run(channel_handle, gpu_info);
-}
-
-void EstablishChannelError(
- linked_ptr<GpuProcessHost::EstablishChannelCallback> callback,
- const IPC::ChannelHandle& channel_handle,
- const GPUInfo& gpu_info) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&EstablishChannelCallbackDispatcher,
- callback, channel_handle, gpu_info));
-}
-
-void SynchronizeCallbackDispatcher(
- linked_ptr<GpuProcessHost::SynchronizeCallback> callback) {
- callback->Run();
+bool GpuProcessHost::CanShutdown() {
+ return true;
}
-void SynchronizeError(
- linked_ptr<GpuProcessHost::SynchronizeCallback> callback) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&SynchronizeCallbackDispatcher, callback));
-}
+namespace {
-void CreateCommandBufferCallbackDispatcher(
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback,
- int32 route_id) {
- callback->Run(route_id);
+void SendOutstandingRepliesDispatcher() {
+ GpuProcessHostUIShim::GetInstance()->SendOutstandingReplies();
}
-void CreateCommandBufferError(
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback,
- int32 route_id) {
+void SendOutstandingReplies() {
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&CreateCommandBufferCallbackDispatcher,
- callback, route_id));
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&SendOutstandingRepliesDispatcher));
}
} // namespace
-void GpuProcessHost::EstablishGpuChannel(int renderer_id,
- EstablishChannelCallback *callback) {
- DCHECK(CalledOnValidThread());
- linked_ptr<EstablishChannelCallback> wrapped_callback(callback);
-
- if (Send(new GpuMsg_EstablishChannel(renderer_id))) {
- channel_requests_.push(wrapped_callback);
- } else {
- EstablishChannelError(wrapped_callback, IPC::ChannelHandle(), GPUInfo());
- }
-}
-
-void GpuProcessHost::Synchronize(SynchronizeCallback* callback) {
- DCHECK(CalledOnValidThread());
- linked_ptr<SynchronizeCallback> wrapped_callback(callback);
-
- if (Send(new GpuMsg_Synchronize())) {
- synchronize_requests_.push(wrapped_callback);
- } else {
- SynchronizeError(wrapped_callback);
- }
-}
-
-class CVCBThreadHopping {
- public:
- // Send the request for a command buffer from the IO thread and
- // queue that we are expecting a response.
- static void DispatchIPCAndQueueReply(
- gfx::PluginWindowHandle view,
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback);
-
- // Get a window for the command buffer that we're creating.
- static void GetViewWindow(
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback);
-};
-
-void CVCBThreadHopping::DispatchIPCAndQueueReply(
- gfx::PluginWindowHandle view,
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- GpuProcessHost* host = GpuProcessHost::Get();
-
- if (view != gfx::kNullPluginWindow &&
- SendDelayedMsg(new GpuMsg_CreateViewCommandBuffer(
- view, render_view_id, renderer_id, init_params))) {
- host->create_command_buffer_requests_.push(callback);
- } else {
- CreateCommandBufferError(callback, MSG_ROUTING_NONE);
- }
-}
-
-void CVCBThreadHopping::GetViewWindow(
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- gfx::PluginWindowHandle window = gfx::kNullPluginWindow;
- RenderProcessHost* process = RenderProcessHost::FromID(renderer_id);
- RenderWidgetHost* host = NULL;
- if (process) {
- host = static_cast<RenderWidgetHost*>(
- process->GetListenerByID(render_view_id));
- }
-
- RenderWidgetHostView* view = NULL;
- if (host)
- view = host->view();
-
- if (view) {
-#if defined(OS_LINUX)
- gfx::NativeViewId view_id = NULL;
- view_id = gfx::IdFromNativeView(view->GetNativeView());
-
- // Lock the window that we will draw into.
- GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
- if (!manager->GetPermanentXIDForId(&window, view_id)) {
- DLOG(ERROR) << "Can't find XID for view id " << view_id;
- }
-#elif defined(OS_MACOSX)
- // On Mac OS X we currently pass a (fake) PluginWindowHandle for the
- // window that we draw to.
- window = view->AllocateFakePluginWindowHandle(
- /*opaque=*/true, /*root=*/true);
-#elif defined(OS_WIN)
- // Create a window that we will overlay.
- window = view->GetCompositorHostWindow();
-#endif
- }
-
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableFunction(
- &CVCBThreadHopping::DispatchIPCAndQueueReply,
- window, render_view_id, renderer_id, init_params, callback));
-}
-
-void GpuProcessHost::CreateViewCommandBuffer(
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- CreateCommandBufferCallback* callback) {
- DCHECK(CalledOnValidThread());
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableFunction(
- &CVCBThreadHopping::GetViewWindow,
- render_view_id, renderer_id, init_params,
- linked_ptr<CreateCommandBufferCallback>(callback)));
-}
-
-bool GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
- DCHECK(CalledOnValidThread());
-
- IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
- IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
- IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply)
- IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
- // If the IO thread does not handle the message then automatically route it
- // to the UI thread. The UI thread will report an error if it does not
- // handle it.
- IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message))
- IPC_END_MESSAGE_MAP()
-
- return true;
-}
-
-void GpuProcessHost::OnChannelEstablished(
- const IPC::ChannelHandle& channel_handle,
- const GPUInfo& gpu_info) {
- if (channel_handle.name.size() != 0 && !gpu_feature_flags_set_) {
- gpu_feature_flags_ = gpu_blacklist_->DetermineGpuFeatureFlags(
- GpuBlacklist::kOsAny, NULL, gpu_info);
- gpu_feature_flags_set_ = true;
- uint32 max_entry_id = gpu_blacklist_->max_entry_id();
- if (gpu_feature_flags_.flags() != 0) {
- std::vector<uint32> flag_entries;
- gpu_blacklist_->GetGpuFeatureFlagEntries(GpuFeatureFlags::kGpuFeatureAll,
- flag_entries);
- DCHECK_GT(flag_entries.size(), 0u);
- for (size_t i = 0; i < flag_entries.size(); ++i) {
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
- flag_entries[i], max_entry_id + 1);
- }
- } else {
- // id 0 is never used by any entry, so we use it here to indicate that
- // gpu is allowed.
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
- 0, max_entry_id + 1);
- }
- }
- linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
- channel_requests_.pop();
-
- // Currently if any of the GPU features are blacklisted, we don't establish a
- // GPU channel.
- if (gpu_feature_flags_.flags() != 0) {
- Send(new GpuMsg_CloseChannel(channel_handle));
- EstablishChannelError(callback, IPC::ChannelHandle(), gpu_info);
- } else {
- callback->Run(channel_handle, gpu_info);
- }
-}
-
-void GpuProcessHost::OnSynchronizeReply() {
- // Guard against race conditions in abrupt GPU process termination.
- if (synchronize_requests_.size() > 0) {
- linked_ptr<SynchronizeCallback> callback = synchronize_requests_.front();
- synchronize_requests_.pop();
- callback->Run();
- }
-}
-
-void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) {
- if (create_command_buffer_requests_.size() > 0) {
- linked_ptr<CreateCommandBufferCallback> callback =
- create_command_buffer_requests_.front();
- create_command_buffer_requests_.pop();
- if (route_id == MSG_ROUTING_NONE)
- CreateCommandBufferError(callback, route_id);
- else
- callback->Run(route_id);
- }
-}
-
-void GpuProcessHost::SendOutstandingReplies() {
- // First send empty channel handles for all EstablishChannel requests.
- while (!channel_requests_.empty()) {
- linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
- channel_requests_.pop();
- EstablishChannelError(callback, IPC::ChannelHandle(), GPUInfo());
- }
-
- // Now unblock all renderers waiting for synchronization replies.
- while (!synchronize_requests_.empty()) {
- linked_ptr<SynchronizeCallback> callback = synchronize_requests_.front();
- synchronize_requests_.pop();
- SynchronizeError(callback);
- }
-}
-
-bool GpuProcessHost::CanShutdown() {
- return true;
-}
-
void GpuProcessHost::OnChildDied() {
SendOutstandingReplies();
// Located in OnChildDied because OnProcessCrashed suffers from a race
@@ -533,21 +277,3 @@ bool GpuProcessHost::LaunchGpuProcess() {
LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX);
return true;
}
-
-bool GpuProcessHost::LoadGpuBlacklist() {
- if (gpu_blacklist_.get() != NULL)
- return true;
- static const base::StringPiece gpu_blacklist_json(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_GPU_BLACKLIST));
- GpuBlacklist* blacklist = new GpuBlacklist();
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) ||
- blacklist->LoadGpuBlacklist(gpu_blacklist_json.as_string(), true)) {
- gpu_blacklist_.reset(blacklist);
- return true;
- }
- delete blacklist;
- return false;
-}
-
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
index bca4674..4ac4326 100644
--- a/chrome/browser/gpu_process_host.h
+++ b/chrome/browser/gpu_process_host.h
@@ -6,22 +6,10 @@
#define CHROME_BROWSER_GPU_PROCESS_HOST_H_
#pragma once
-#include <queue>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/linked_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/browser_child_process_host.h"
-#include "chrome/common/gpu_feature_flags.h"
-#include "ui/gfx/native_widget_types.h"
-
-class GpuBlacklist;
-struct GPUCreateCommandBufferConfig;
-class GPUInfo;
namespace IPC {
-struct ChannelHandle;
class Message;
}
@@ -36,35 +24,6 @@ class GpuProcessHost : public BrowserChildProcessHost,
// IPC::Channel::Listener implementation.
virtual bool OnMessageReceived(const IPC::Message& message);
- typedef Callback2<const IPC::ChannelHandle&, const GPUInfo&>::Type
- EstablishChannelCallback;
-
- // Tells the GPU process to create a new channel for communication with a
- // renderer. Once the GPU process responds asynchronously with the IPC handle
- // and GPUInfo, we call the callback.
- void EstablishGpuChannel(
- int renderer_id, EstablishChannelCallback* callback);
-
- typedef Callback0::Type SynchronizeCallback;
-
- // Sends a reply message later when the next GpuHostMsg_SynchronizeReply comes
- // in.
- void Synchronize(SynchronizeCallback* callback);
-
- typedef Callback1<int32>::Type CreateCommandBufferCallback;
-
- // Tells the GPU process to create a new command buffer that draws into the
- // window associated with the given renderer.
- void CreateViewCommandBuffer(
- int32 render_view_id,
- int32 renderer_id,
- const GPUCreateCommandBufferConfig& init_params,
- CreateCommandBufferCallback* callback);
-
- // We need to hop threads when creating the command buffer.
- // Let these tasks access our internals.
- friend class CVCBThreadHopping;
-
private:
GpuProcessHost();
virtual ~GpuProcessHost();
@@ -72,19 +31,6 @@ class GpuProcessHost : public BrowserChildProcessHost,
bool EnsureInitialized();
bool Init();
- bool OnControlMessageReceived(const IPC::Message& message);
-
- // Message handlers.
- void OnChannelEstablished(const IPC::ChannelHandle& channel_handle,
- const GPUInfo& gpu_info);
- void OnSynchronizeReply();
- void OnCommandBufferCreated(const int32 route_id);
-
- // Sends outstanding replies to renderer processes. This is only called
- // in error situations like the GPU process crashing -- but is necessary
- // to prevent the renderer process from hanging.
- void SendOutstandingReplies();
-
virtual bool CanShutdown();
virtual void OnChildDied();
virtual void OnProcessCrashed(int exit_code);
@@ -92,28 +38,10 @@ class GpuProcessHost : public BrowserChildProcessHost,
bool CanLaunchGpuProcess() const;
bool LaunchGpuProcess();
- bool LoadGpuBlacklist();
-
bool initialized_;
bool initialized_successfully_;
- bool gpu_feature_flags_set_;
- scoped_ptr<GpuBlacklist> gpu_blacklist_;
- GpuFeatureFlags gpu_feature_flags_;
-
- // These are the channel requests that we have already sent to
- // the GPU process, but haven't heard back about yet.
- std::queue<linked_ptr<EstablishChannelCallback> > channel_requests_;
-
- // The pending synchronization requests we need to reply to.
- std::queue<linked_ptr<SynchronizeCallback> > synchronize_requests_;
-
- // The pending create command buffer requests we need to reply to.
- std::queue<linked_ptr<CreateCommandBufferCallback> >
- create_command_buffer_requests_;
-
DISALLOW_COPY_AND_ASSIGN(GpuProcessHost);
};
-
#endif // CHROME_BROWSER_GPU_PROCESS_HOST_H_
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
index 184d8c1..04b535c 100644
--- a/chrome/browser/gpu_process_host_ui_shim.cc
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -4,13 +4,19 @@
#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "base/command_line.h"
+#include "base/metrics/histogram.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gpu_blacklist.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
#if defined(OS_LINUX)
// These two #includes need to come after gpu_messages.h.
@@ -38,12 +44,28 @@ class SendOnIOThreadTask : public Task {
} // namespace
-GpuProcessHostUIShim::GpuProcessHostUIShim() : last_routing_id_(1) {
+GpuProcessHostUIShim::GpuProcessHostUIShim()
+ : last_routing_id_(1),
+ initialized_(false),
+ initialized_successfully_(false),
+ gpu_feature_flags_set_(false) {
}
GpuProcessHostUIShim::~GpuProcessHostUIShim() {
}
+bool GpuProcessHostUIShim::EnsureInitialized() {
+ if (!initialized_) {
+ initialized_ = true;
+ initialized_successfully_ = Init();
+ }
+ return initialized_successfully_;
+}
+
+bool GpuProcessHostUIShim::Init() {
+ return LoadGpuBlacklist();
+}
+
// static
GpuProcessHostUIShim* GpuProcessHostUIShim::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -52,12 +74,87 @@ GpuProcessHostUIShim* GpuProcessHostUIShim::GetInstance() {
bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
DCHECK(CalledOnValidThread());
+ if (!EnsureInitialized())
+ return false;
+
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
new SendOnIOThreadTask(msg));
return true;
}
+// Post a Task to execute callbacks on a error conditions in order to
+// clear the call stacks (and aid debugging).
+namespace {
+
+void EstablishChannelCallbackDispatcher(
+ GpuProcessHostUIShim::EstablishChannelCallback* callback,
+ const IPC::ChannelHandle& channel_handle,
+ const GPUInfo& gpu_info) {
+ scoped_ptr<GpuProcessHostUIShim::EstablishChannelCallback>
+ wrapped_callback(callback);
+ wrapped_callback->Run(channel_handle, gpu_info);
+}
+
+void EstablishChannelError(
+ GpuProcessHostUIShim::EstablishChannelCallback* callback,
+ const IPC::ChannelHandle& channel_handle,
+ const GPUInfo& gpu_info) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&EstablishChannelCallbackDispatcher,
+ callback, channel_handle, gpu_info));
+}
+
+void SynchronizeCallbackDispatcher(
+ GpuProcessHostUIShim::SynchronizeCallback* callback) {
+ scoped_ptr<GpuProcessHostUIShim::SynchronizeCallback>
+ wrapped_callback(callback);
+ wrapped_callback->Run();
+}
+
+void SynchronizeError(
+ GpuProcessHostUIShim::SynchronizeCallback* callback) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&SynchronizeCallbackDispatcher, callback));
+}
+
+void CreateCommandBufferCallbackDispatcher(
+ GpuProcessHostUIShim::CreateCommandBufferCallback* callback,
+ int32 route_id) {
+ scoped_ptr<GpuProcessHostUIShim::CreateCommandBufferCallback>
+ wrapped_callback(callback);
+ callback->Run(route_id);
+}
+
+void CreateCommandBufferError(
+ GpuProcessHostUIShim::CreateCommandBufferCallback* callback,
+ int32 route_id) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&CreateCommandBufferCallbackDispatcher,
+ callback, route_id));
+}
+
+} // namespace
+
+void GpuProcessHostUIShim::SendOutstandingReplies() {
+ // First send empty channel handles for all EstablishChannel requests.
+ while (!channel_requests_.empty()) {
+ linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
+ channel_requests_.pop();
+ EstablishChannelError(callback.release(), IPC::ChannelHandle(), GPUInfo());
+ }
+
+ // Now unblock all renderers waiting for synchronization replies.
+ while (!synchronize_requests_.empty()) {
+ linked_ptr<SynchronizeCallback> callback = synchronize_requests_.front();
+ synchronize_requests_.pop();
+ SynchronizeError(callback.release());
+ }
+}
+
int32 GpuProcessHostUIShim::GetNextRoutingId() {
DCHECK(CalledOnValidThread());
return ++last_routing_id_;
@@ -83,29 +180,94 @@ bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
return router_.RouteMessage(message);
}
+void GpuProcessHostUIShim::EstablishGpuChannel(
+ int renderer_id, EstablishChannelCallback *callback) {
+ DCHECK(CalledOnValidThread());
+ linked_ptr<EstablishChannelCallback> wrapped_callback(callback);
+
+ if (Send(new GpuMsg_EstablishChannel(renderer_id))) {
+ channel_requests_.push(wrapped_callback);
+ } else {
+ EstablishChannelError(
+ wrapped_callback.release(), IPC::ChannelHandle(), GPUInfo());
+ }
+}
+
+void GpuProcessHostUIShim::Synchronize(SynchronizeCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ linked_ptr<SynchronizeCallback> wrapped_callback(callback);
+
+ if (Send(new GpuMsg_Synchronize())) {
+ synchronize_requests_.push(wrapped_callback);
+ } else {
+ SynchronizeError(wrapped_callback.release());
+ }
+}
+
+void GpuProcessHostUIShim::CreateViewCommandBuffer(
+ int32 render_view_id,
+ int32 renderer_id,
+ const GPUCreateCommandBufferConfig& init_params,
+ CreateCommandBufferCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ linked_ptr<CreateCommandBufferCallback> wrapped_callback(callback);
+
+ gfx::PluginWindowHandle window = gfx::kNullPluginWindow;
+ RenderProcessHost* process = RenderProcessHost::FromID(renderer_id);
+ RenderWidgetHost* host = NULL;
+ if (process) {
+ host = static_cast<RenderWidgetHost*>(
+ process->GetListenerByID(render_view_id));
+ }
+
+ RenderWidgetHostView* view = NULL;
+ if (host)
+ view = host->view();
+
+ if (view) {
+#if defined(OS_LINUX)
+ gfx::NativeViewId view_id = NULL;
+ view_id = gfx::IdFromNativeView(view->GetNativeView());
+
+ // Lock the window that we will draw into.
+ GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
+ if (!manager->GetPermanentXIDForId(&window, view_id)) {
+ DLOG(ERROR) << "Can't find XID for view id " << view_id;
+ }
+#elif defined(OS_MACOSX)
+ // On Mac OS X we currently pass a (fake) PluginWindowHandle for the
+ // window that we draw to.
+ window = view->AllocateFakePluginWindowHandle(
+ /*opaque=*/true, /*root=*/true);
+#elif defined(OS_WIN)
+ // Create a window that we will overlay.
+ window = view->GetCompositorHostWindow();
+#endif
+ }
+
+ if (window != gfx::kNullPluginWindow &&
+ Send(new GpuMsg_CreateViewCommandBuffer(
+ window, render_view_id, renderer_id, init_params))) {
+ create_command_buffer_requests_.push(wrapped_callback);
+ } else {
+ CreateCommandBufferError(wrapped_callback.release(), MSG_ROUTING_NONE);
+ }
+}
+
void GpuProcessHostUIShim::CollectGraphicsInfoAsynchronously(
GPUInfo::Level level) {
DCHECK(CalledOnValidThread());
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- new SendOnIOThreadTask(new GpuMsg_CollectGraphicsInfo(level)));
+ Send(new GpuMsg_CollectGraphicsInfo(level));
}
void GpuProcessHostUIShim::SendAboutGpuCrash() {
DCHECK(CalledOnValidThread());
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- new SendOnIOThreadTask(new GpuMsg_Crash()));
+ Send(new GpuMsg_Crash());
}
void GpuProcessHostUIShim::SendAboutGpuHang() {
DCHECK(CalledOnValidThread());
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- new SendOnIOThreadTask(new GpuMsg_Hang()));
+ Send(new GpuMsg_Hang());
}
const GPUInfo& GpuProcessHostUIShim::gpu_info() const {
@@ -113,6 +275,97 @@ const GPUInfo& GpuProcessHostUIShim::gpu_info() const {
return gpu_info_;
}
+bool GpuProcessHostUIShim::OnControlMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
+
+ IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished,
+ OnChannelEstablished)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated,
+ OnCommandBufferCreated)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer,
+ OnDestroyCommandBuffer)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
+ OnGraphicsInfoCollected)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
+ OnLogMessage)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply,
+ OnSynchronizeReply)
+#if defined(OS_LINUX)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_ResizeXID, OnResizeXID)
+#elif defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
+ OnAcceleratedSurfaceSetIOSurface)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
+ OnAcceleratedSurfaceBuffersSwapped)
+#elif defined(OS_WIN)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite, OnScheduleComposite);
+#endif
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+
+ return true;
+}
+
+void GpuProcessHostUIShim::OnChannelEstablished(
+ const IPC::ChannelHandle& channel_handle,
+ const GPUInfo& gpu_info) {
+ if (channel_handle.name.size() != 0 && !gpu_feature_flags_set_) {
+ gpu_feature_flags_ = gpu_blacklist_->DetermineGpuFeatureFlags(
+ GpuBlacklist::kOsAny, NULL, gpu_info);
+ gpu_feature_flags_set_ = true;
+ uint32 max_entry_id = gpu_blacklist_->max_entry_id();
+ if (gpu_feature_flags_.flags() != 0) {
+ std::vector<uint32> flag_entries;
+ gpu_blacklist_->GetGpuFeatureFlagEntries(GpuFeatureFlags::kGpuFeatureAll,
+ flag_entries);
+ DCHECK_GT(flag_entries.size(), 0u);
+ for (size_t i = 0; i < flag_entries.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
+ flag_entries[i], max_entry_id + 1);
+ }
+ } else {
+ // id 0 is never used by any entry, so we use it here to indicate that
+ // gpu is allowed.
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
+ 0, max_entry_id + 1);
+ }
+ }
+ linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
+ channel_requests_.pop();
+
+ // Currently if any of the GPU features are blacklisted, we don't establish a
+ // GPU channel.
+ if (gpu_feature_flags_.flags() != 0) {
+ Send(new GpuMsg_CloseChannel(channel_handle));
+ EstablishChannelError(callback.release(), IPC::ChannelHandle(), gpu_info);
+ } else {
+ callback->Run(channel_handle, gpu_info);
+ }
+}
+
+void GpuProcessHostUIShim::OnSynchronizeReply() {
+ // Guard against race conditions in abrupt GPU process termination.
+ if (synchronize_requests_.size() > 0) {
+ linked_ptr<SynchronizeCallback> callback(synchronize_requests_.front());
+ synchronize_requests_.pop();
+ callback->Run();
+ }
+}
+
+void GpuProcessHostUIShim::OnCommandBufferCreated(const int32 route_id) {
+ if (create_command_buffer_requests_.size() > 0) {
+ linked_ptr<CreateCommandBufferCallback> callback =
+ create_command_buffer_requests_.front();
+ create_command_buffer_requests_.pop();
+ if (route_id == MSG_ROUTING_NONE)
+ CreateCommandBufferError(callback.release(), route_id);
+ else
+ callback->Run(route_id);
+ }
+}
+
void GpuProcessHostUIShim::OnDestroyCommandBuffer(
gfx::PluginWindowHandle window, int32 renderer_id,
int32 render_view_id) {
@@ -162,44 +415,6 @@ void GpuProcessHostUIShim::OnLogMessage(int level,
log_messages_.Append(dict);
}
-bool GpuProcessHostUIShim::OnControlMessageReceived(
- const IPC::Message& message) {
- DCHECK(CalledOnValidThread());
-
- IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
- IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer,
- OnDestroyCommandBuffer)
- IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
- OnGraphicsInfoCollected)
- IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
- OnLogMessage)
-#if defined(OS_LINUX)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_ResizeXID, OnResizeXID)
-#elif defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
- OnAcceleratedSurfaceSetIOSurface)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
- OnAcceleratedSurfaceBuffersSwapped)
-#elif defined(OS_WIN)
- IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite, OnScheduleComposite);
-#endif
- IPC_MESSAGE_UNHANDLED_ERROR()
- IPC_END_MESSAGE_MAP()
-
- return true;
-}
-
-namespace {
-
-void SendDelayedReply(IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- new SendOnIOThreadTask(reply_msg));
-}
-
-} // namespace
-
#if defined(OS_LINUX)
void GpuProcessHostUIShim::OnResizeXID(unsigned long xid, gfx::Size size,
@@ -212,7 +427,7 @@ void GpuProcessHostUIShim::OnResizeXID(unsigned long xid, gfx::Size size,
}
GpuHostMsg_ResizeXID::WriteReplyParams(reply_msg, (window != NULL));
- SendDelayedReply(reply_msg);
+ Send(reply_msg);
}
#elif defined(OS_MACOSX)
@@ -264,3 +479,19 @@ void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
}
#endif
+
+bool GpuProcessHostUIShim::LoadGpuBlacklist() {
+ if (gpu_blacklist_.get() != NULL)
+ return true;
+ static const base::StringPiece gpu_blacklist_json(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_GPU_BLACKLIST));
+ gpu_blacklist_.reset(new GpuBlacklist());
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) ||
+ gpu_blacklist_->LoadGpuBlacklist(gpu_blacklist_json.as_string(), true)) {
+ return true;
+ }
+ gpu_blacklist_.reset(NULL);
+ return false;
+}
diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h
index bfb6f52..a47e2e6d 100644
--- a/chrome/browser/gpu_process_host_ui_shim.h
+++ b/chrome/browser/gpu_process_host_ui_shim.h
@@ -11,11 +11,15 @@
// portion of this class, the GpuProcessHost, is responsible for
// shuttling messages between the browser and GPU processes.
+#include <queue>
+
#include "base/callback.h"
+#include "base/linked_ptr.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "base/values.h"
#include "base/threading/non_thread_safe.h"
+#include "chrome/common/gpu_feature_flags.h"
#include "chrome/common/gpu_info.h"
#include "chrome/common/message_router.h"
#include "ipc/ipc_channel.h"
@@ -25,9 +29,17 @@ namespace gfx {
class Size;
}
+class GpuBlacklist;
+struct GPUCreateCommandBufferConfig;
+class GPUInfo;
struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params;
struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
+namespace IPC {
+struct ChannelHandle;
+class Message;
+}
+
class GpuProcessHostUIShim : public IPC::Channel::Sender,
public IPC::Channel::Listener,
public base::NonThreadSafe {
@@ -40,12 +52,42 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
// IPC::Channel::Sender implementation.
virtual bool Send(IPC::Message* msg);
+ // Sends outstanding replies. This is only called
+ // in error situations like the GPU process crashing -- but is necessary
+ // to prevent the blocked clients from hanging.
+ void SendOutstandingReplies();
+
// IPC::Channel::Listener implementation.
// The GpuProcessHost causes this to be called on the UI thread to
// dispatch the incoming messages from the GPU process, which are
// actually received on the IO thread.
virtual bool OnMessageReceived(const IPC::Message& message);
+ typedef Callback2<const IPC::ChannelHandle&, const GPUInfo&>::Type
+ EstablishChannelCallback;
+
+ // Tells the GPU process to create a new channel for communication with a
+ // renderer. Once the GPU process responds asynchronously with the IPC handle
+ // and GPUInfo, we call the callback.
+ void EstablishGpuChannel(
+ int renderer_id, EstablishChannelCallback* callback);
+
+ typedef Callback0::Type SynchronizeCallback;
+
+ // Sends a reply message later when the next GpuHostMsg_SynchronizeReply comes
+ // in.
+ void Synchronize(SynchronizeCallback* callback);
+
+ typedef Callback1<int32>::Type CreateCommandBufferCallback;
+
+ // Tells the GPU process to create a new command buffer that draws into the
+ // window associated with the given renderer.
+ void CreateViewCommandBuffer(
+ int32 render_view_id,
+ int32 renderer_id,
+ const GPUCreateCommandBufferConfig& init_params,
+ CreateCommandBufferCallback* callback);
+
// See documentation on MessageRouter for AddRoute and RemoveRoute
void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
void RemoveRoute(int32 routing_id);
@@ -73,20 +115,31 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
ListValue* logMessages() const { return log_messages_.DeepCopy(); }
+ bool LoadGpuBlacklist();
+
private:
friend struct DefaultSingletonTraits<GpuProcessHostUIShim>;
GpuProcessHostUIShim();
virtual ~GpuProcessHostUIShim();
+ // TODO(apatrick): Following the pattern from GpuProcessHost. Talk to zmo
+ // and see if we can find a better mechanism.
+ bool EnsureInitialized();
+ bool Init();
+
// Message handlers.
bool OnControlMessageReceived(const IPC::Message& message);
+ void OnChannelEstablished(const IPC::ChannelHandle& channel_handle,
+ const GPUInfo& gpu_info);
+ void OnCommandBufferCreated(const int32 route_id);
void OnDestroyCommandBuffer(gfx::PluginWindowHandle window,
int32 renderer_id, int32 render_view_id);
void OnGraphicsInfoCollected(const GPUInfo& gpu_info);
void OnLogMessage(int level, const std::string& header,
const std::string& message);
+ void OnSynchronizeReply();
#if defined(OS_LINUX)
void OnResizeXID(unsigned long xid, gfx::Size size, IPC::Message* reply_msg);
#elif defined(OS_MACOSX)
@@ -108,6 +161,24 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
// Used only in testing. If set, the callback is invoked when the GPU info
// has been collected.
scoped_ptr<Callback0::Type> gpu_info_collected_callback_;
+
+ // These are the channel requests that we have already sent to
+ // the GPU process, but haven't heard back about yet.
+ std::queue<linked_ptr<EstablishChannelCallback> > channel_requests_;
+
+ // The pending synchronization requests we need to reply to.
+ std::queue<linked_ptr<SynchronizeCallback> > synchronize_requests_;
+
+ // The pending create command buffer requests we need to reply to.
+ std::queue<linked_ptr<CreateCommandBufferCallback> >
+ create_command_buffer_requests_;
+
+ bool initialized_;
+ bool initialized_successfully_;
+
+ bool gpu_feature_flags_set_;
+ scoped_ptr<GpuBlacklist> gpu_blacklist_;
+ GpuFeatureFlags gpu_feature_flags_;
};
#endif // CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
diff --git a/chrome/browser/renderer_host/gpu_message_filter.cc b/chrome/browser/renderer_host/gpu_message_filter.cc
index 15ebf1c..4ff5357 100644
--- a/chrome/browser/renderer_host/gpu_message_filter.cc
+++ b/chrome/browser/renderer_host/gpu_message_filter.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/renderer_host/gpu_message_filter.h"
#include "base/callback.h"
-#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/common/gpu_create_command_buffer_config.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/common/render_messages.h"
@@ -19,6 +19,13 @@ GpuMessageFilter::~GpuMessageFilter() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
+void GpuMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == GpuMsgStart)
+ *thread = BrowserThread::UI;
+}
+
bool GpuMessageFilter::OnMessageReceived(
const IPC::Message& message,
bool* message_was_ok) {
@@ -56,7 +63,7 @@ class EstablishChannelCallback
void Send(const IPC::ChannelHandle& channel,
const GPUInfo& gpu_info) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ViewMsg_GpuChannelEstablished* reply =
new ViewMsg_GpuChannelEstablished(channel, gpu_info);
// If the renderer process is performing synchronous initialization,
@@ -84,7 +91,7 @@ class SynchronizeCallback : public CallbackRunner<Tuple0> {
}
void Send() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (filter_)
filter_->Send(reply_);
}
@@ -107,7 +114,7 @@ class CreateCommandBufferCallback : public CallbackRunner<Tuple1<int32> > {
}
void Send(int32 route_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply_, route_id);
if (filter_)
filter_->Send(reply_);
@@ -121,19 +128,20 @@ class CreateCommandBufferCallback : public CallbackRunner<Tuple1<int32> > {
} // namespace
void GpuMessageFilter::OnEstablishGpuChannel() {
- GpuProcessHost::Get()->EstablishGpuChannel(
+ GpuProcessHostUIShim::GetInstance()->EstablishGpuChannel(
render_process_id_, new EstablishChannelCallback(this));
}
void GpuMessageFilter::OnSynchronizeGpu(IPC::Message* reply) {
- GpuProcessHost::Get()->Synchronize(new SynchronizeCallback(this, reply));
+ GpuProcessHostUIShim::GetInstance()->
+ Synchronize(new SynchronizeCallback(this, reply));
}
void GpuMessageFilter::OnCreateViewCommandBuffer(
int32 render_view_id,
const GPUCreateCommandBufferConfig& init_params,
IPC::Message* reply) {
- GpuProcessHost::Get()->CreateViewCommandBuffer(
+ GpuProcessHostUIShim::GetInstance()->CreateViewCommandBuffer(
render_view_id, render_process_id_, init_params,
new CreateCommandBufferCallback(this, reply));
}
diff --git a/chrome/browser/renderer_host/gpu_message_filter.h b/chrome/browser/renderer_host/gpu_message_filter.h
index 8c6e83c..638464c 100644
--- a/chrome/browser/renderer_host/gpu_message_filter.h
+++ b/chrome/browser/renderer_host/gpu_message_filter.h
@@ -26,6 +26,8 @@ class GpuMessageFilter : public BrowserMessageFilter,
explicit GpuMessageFilter(int render_process_id);
// BrowserMessageFilter methods:
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok);
virtual void OnDestruct() const;