diff options
-rw-r--r-- | chrome/browser/gpu_process_host.cc | 292 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host.h | 72 | ||||
-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, 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; |