diff options
author | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-08 19:32:55 +0000 |
---|---|---|
committer | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-08 19:32:55 +0000 |
commit | c0c1a3a0e7bd0d6ddcbfabfd76376770ff30d1cc (patch) | |
tree | f4f08c709b77976bd3a1267a95e5c4f280ef2f1e | |
parent | 67637b8ab2e6bef2ba134048461d14c9ecfff0c6 (diff) | |
download | chromium_src-c0c1a3a0e7bd0d6ddcbfabfd76376770ff30d1cc.zip chromium_src-c0c1a3a0e7bd0d6ddcbfabfd76376770ff30d1cc.tar.gz chromium_src-c0c1a3a0e7bd0d6ddcbfabfd76376770ff30d1cc.tar.bz2 |
Move most of GpuProcessHost processing to GpuProcessHostUIShim.
This is a refactoring to support the browser using the GPU process for drawing. Currently most of the communication with the GPU process (via GpuProcessHost) happens on the IO thread (where requests come in from the renderer). In the future, the browser will be drawing from the UI thread. Rather than have two entry points (or a lot of explicit thread hopping), I've moved GpuMessageFilter (the proxy for the renderer) to the UI thread and most of GpuProcessHost functionality to GpuProcessHostUIShim.
This cleans up some of the CVCBThreadHopping mess from an earlier commit.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6349079
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74155 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/gpu_process_host.cc | 279 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host.h | 70 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host_ui_shim.cc | 335 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host_ui_shim.h | 71 | ||||
-rw-r--r-- | chrome/browser/renderer_host/gpu_message_filter.cc | 22 | ||||
-rw-r--r-- | chrome/browser/renderer_host/gpu_message_filter.h | 2 |
6 files changed, 382 insertions, 397 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index d126a86..602f586 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; @@ -176,180 +167,10 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& 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(); -} - -void SynchronizeError( - linked_ptr<GpuProcessHost::SynchronizeCallback> callback) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableFunction(&SynchronizeCallbackDispatcher, callback)); -} - -void CreateCommandBufferCallbackDispatcher( - linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback, - int32 route_id) { - callback->Run(route_id); -} - -void CreateCommandBufferError( - linked_ptr<GpuProcessHost::CreateCommandBufferCallback> callback, - int32 route_id) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableFunction(&CreateCommandBufferCallbackDispatcher, - callback, route_id)); -} - -} // 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. @@ -359,83 +180,23 @@ bool GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { 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); - } +bool GpuProcessHost::CanShutdown() { + return true; } -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(); - } -} +namespace { -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 SendOutstandingRepliesDispatcher() { + GpuProcessHostUIShim::GetInstance()->SendOutstandingReplies(); } -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); - } +void SendOutstandingReplies() { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableFunction(&SendOutstandingRepliesDispatcher)); } -bool GpuProcessHost::CanShutdown() { - return true; -} +} // namespace void GpuProcessHost::OnChildDied() { SendOutstandingReplies(); @@ -533,21 +294,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..bb4fe9a 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(); @@ -74,17 +33,6 @@ class GpuProcessHost : public BrowserChildProcessHost, 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 +40,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; |