| // TODO(jam): move this file to src/content once we have an interface that the |
| // embedder provides. We can then use it to get the resource and resize the |
| // window. |
| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/gpu_process_host_ui_shim.h" |
| |
| #include "base/command_line.h" |
| #include "base/id_map.h" |
| #include "base/process_util.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/gpu_data_manager.h" |
| #include "chrome/browser/io_thread.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/gpu_process_host.h" |
| #include "content/browser/renderer_host/render_process_host.h" |
| #include "content/browser/renderer_host/render_view_host.h" |
| #include "content/browser/renderer_host/render_widget_host_view.h" |
| #include "content/common/content_switches.h" |
| #include "content/common/gpu_messages.h" |
| #include "gpu/common/gpu_trace_event.h" |
| |
| #if defined(OS_LINUX) |
| // These two #includes need to come after gpu_messages.h. |
| #include <gdk/gdkwindow.h> // NOLINT |
| #include <gdk/gdkx.h> // NOLINT |
| #include "ui/base/x/x11_util.h" |
| #include "ui/gfx/gtk_native_view_id_manager.h" |
| #include "ui/gfx/size.h" |
| #endif // defined(OS_LINUX) |
| namespace { |
| |
| // One of the linux specific headers defines this as a macro. |
| #ifdef DestroyAll |
| #undef DestroyAll |
| #endif |
| |
| IDMap<GpuProcessHostUIShim> g_hosts_by_id; |
| |
| class SendOnIOThreadTask : public Task { |
| public: |
| SendOnIOThreadTask(int host_id, IPC::Message* msg) |
| : host_id_(host_id), |
| msg_(msg) { |
| } |
| |
| private: |
| void Run() { |
| GpuProcessHost* host = GpuProcessHost::FromID(host_id_); |
| if (host) |
| host->Send(msg_.release()); |
| } |
| |
| int host_id_; |
| scoped_ptr<IPC::Message> msg_; |
| }; |
| |
| class UIThreadSender : public IPC::Channel::Sender { |
| public: |
| virtual bool Send(IPC::Message* msg) { |
| // The GPU process must never send a synchronous IPC message to the browser |
| // process. This could result in deadlock. Unfortunately linux does this for |
| // GpuHostMsg_ResizeXID. TODO(apatrick): fix this before issuing any GL calls |
| // on the browser process' GPU thread. |
| #if !defined(OS_LINUX) |
| DCHECK(!msg->is_sync()); |
| #endif |
| |
| // When the GpuChannelManager sends an IPC, post it to the UI thread without |
| // using IPC. |
| bool success = BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| new RouteToGpuProcessHostUIShimTask(0, *msg)); |
| |
| delete msg; |
| return success; |
| } |
| }; |
| |
| void ForwardMessageToGpuThread(GpuChannelManager* gpu_channel_manager, |
| IPC::Message* msg) { |
| bool success = gpu_channel_manager->OnMessageReceived(*msg); |
| |
| // If the message was not handled, it is likely it was intended for the |
| // GpuChildThread, which does not exist in single process and in process GPU |
| // mode. |
| DCHECK(success); |
| |
| delete msg; |
| } |
| |
| } // namespace |
| |
| RouteToGpuProcessHostUIShimTask::RouteToGpuProcessHostUIShimTask( |
| int host_id, |
| const IPC::Message& msg) |
| : host_id_(host_id), |
| msg_(msg) { |
| } |
| |
| RouteToGpuProcessHostUIShimTask::~RouteToGpuProcessHostUIShimTask() { |
| } |
| |
| void RouteToGpuProcessHostUIShimTask::Run() { |
| GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id_); |
| if (ui_shim) |
| ui_shim->OnMessageReceived(msg_); |
| } |
| |
| GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id) |
| : host_id_(host_id), |
| gpu_channel_manager_(NULL), |
| ui_thread_sender_(NULL) { |
| g_hosts_by_id.AddWithID(this, host_id_); |
| if (host_id == 0) { |
| ui_thread_sender_ = new UIThreadSender; |
| gpu_channel_manager_ = new GpuChannelManager( |
| ui_thread_sender_, |
| NULL, |
| g_browser_process->io_thread()->message_loop(), |
| g_browser_process->shutdown_event()); |
| } |
| } |
| |
| // static |
| GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) { |
| DCHECK(!FromID(host_id)); |
| return new GpuProcessHostUIShim(host_id); |
| } |
| |
| // static |
| void GpuProcessHostUIShim::Destroy(int host_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| delete FromID(host_id); |
| } |
| |
| // static |
| void GpuProcessHostUIShim::DestroyAll() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| while (!g_hosts_by_id.IsEmpty()) { |
| IDMap<GpuProcessHostUIShim>::iterator it(&g_hosts_by_id); |
| delete it.GetCurrentValue(); |
| } |
| } |
| |
| // static |
| GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| return g_hosts_by_id.Lookup(host_id); |
| } |
| |
| bool GpuProcessHostUIShim::Send(IPC::Message* msg) { |
| DCHECK(CalledOnValidThread()); |
| |
| bool success; |
| |
| if (host_id_ == 0) { |
| success = BrowserThread::PostTask( |
| BrowserThread::GPU, |
| FROM_HERE, |
| NewRunnableFunction(ForwardMessageToGpuThread, |
| gpu_channel_manager_, |
| msg)); |
| } else { |
| success = BrowserThread::PostTask( |
| BrowserThread::IO, |
| FROM_HERE, |
| new SendOnIOThreadTask(host_id_, msg)); |
| } |
| |
| return success; |
| } |
| |
| bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) { |
| DCHECK(CalledOnValidThread()); |
| |
| if (message.routing_id() != MSG_ROUTING_CONTROL) |
| return false; |
| |
| return OnControlMessageReceived(message); |
| } |
| |
| #if defined(OS_MACOSX) |
| |
| void GpuProcessHostUIShim::DidDestroyAcceleratedSurface(int renderer_id, |
| int render_view_id) { |
| // Destroy the command buffer that owns the accelerated surface. |
| Send(new GpuMsg_DestroyCommandBuffer(renderer_id, render_view_id)); |
| } |
| |
| void GpuProcessHostUIShim::SendToGpuHost(int host_id, IPC::Message* msg) { |
| GpuProcessHostUIShim* ui_shim = FromID(host_id); |
| if (!ui_shim) |
| return; |
| |
| ui_shim->Send(msg); |
| } |
| |
| #endif |
| |
| GpuProcessHostUIShim::~GpuProcessHostUIShim() { |
| DCHECK(CalledOnValidThread()); |
| g_hosts_by_id.Remove(host_id_); |
| |
| // Ensure these are destroyed on the GPU thread. |
| if (gpu_channel_manager_) { |
| BrowserThread::DeleteSoon(BrowserThread::GPU, |
| FROM_HERE, |
| gpu_channel_manager_); |
| gpu_channel_manager_ = NULL; |
| } |
| if (ui_thread_sender_) { |
| BrowserThread::DeleteSoon(BrowserThread::GPU, |
| FROM_HERE, |
| ui_thread_sender_); |
| ui_thread_sender_ = NULL; |
| } |
| } |
| |
| bool GpuProcessHostUIShim::OnControlMessageReceived( |
| const IPC::Message& message) { |
| DCHECK(CalledOnValidThread()); |
| |
| IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message) |
| IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage, |
| OnLogMessage) |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) || defined(OS_WIN) |
| IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView, OnResizeView) |
| #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::OnLogMessage( |
| int level, |
| const std::string& header, |
| const std::string& message) { |
| DictionaryValue* dict = new DictionaryValue(); |
| dict->SetInteger("level", level); |
| dict->SetString("header", header); |
| dict->SetString("message", message); |
| GpuDataManager::GetInstance()->AddLogMessage(dict); |
| } |
| |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) || defined(OS_WIN) |
| |
| void GpuProcessHostUIShim::OnResizeView(int32 renderer_id, |
| int32 render_view_id, |
| int32 command_buffer_route_id, |
| gfx::Size size) { |
| RenderViewHost* host = RenderViewHost::FromID(renderer_id, render_view_id); |
| if (host) { |
| RenderWidgetHostView* view = host->view(); |
| if (view) { |
| gfx::PluginWindowHandle handle = view->GetCompositingSurface(); |
| |
| // Resize the window synchronously. The GPU process must not issue GL |
| // calls on the command buffer until the window is the size it expects it |
| // to be. |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) |
| GdkWindow* window = reinterpret_cast<GdkWindow*>( |
| gdk_xid_table_lookup(handle)); |
| if (window) { |
| Display* display = GDK_WINDOW_XDISPLAY(window); |
| gdk_window_resize(window, size.width(), size.height()); |
| XSync(display, False); |
| } |
| #elif defined(OS_WIN) |
| SetWindowPos(handle, |
| NULL, |
| 0, 0, |
| size.width(), |
| size.height(), |
| SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | |
| SWP_NOACTIVATE | SWP_DEFERERASE); |
| #endif |
| } |
| } |
| |
| // Always respond even if the window no longer exists. The GPU process cannot |
| // make progress on the resizing command buffer until it receives the |
| // response. |
| Send(new GpuMsg_ResizeViewACK(renderer_id, command_buffer_route_id)); |
| } |
| |
| #elif defined(OS_MACOSX) |
| |
| void GpuProcessHostUIShim::OnAcceleratedSurfaceSetIOSurface( |
| const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params) { |
| RenderViewHost* host = RenderViewHost::FromID(params.renderer_id, |
| params.render_view_id); |
| if (!host) |
| return; |
| RenderWidgetHostView* view = host->view(); |
| if (!view) |
| return; |
| view->AcceleratedSurfaceSetIOSurface(params.window, |
| params.width, |
| params.height, |
| params.identifier); |
| } |
| |
| void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( |
| const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { |
| RenderViewHost* host = RenderViewHost::FromID(params.renderer_id, |
| params.render_view_id); |
| if (!host) |
| return; |
| RenderWidgetHostView* view = host->view(); |
| if (!view) |
| return; |
| view->AcceleratedSurfaceBuffersSwapped( |
| // Parameters needed to swap the IOSurface. |
| params.window, |
| params.surface_id, |
| // Parameters needed to formulate an acknowledgment. |
| params.renderer_id, |
| params.route_id, |
| host_id_, |
| params.swap_buffers_count); |
| } |
| |
| #endif |
| |
| #if defined(OS_WIN) |
| |
| void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id, |
| int render_view_id) { |
| RenderViewHost* host = RenderViewHost::FromID(renderer_id, |
| render_view_id); |
| if (!host) { |
| return; |
| } |
| host->ScheduleComposite(); |
| } |
| |
| #endif |