Home | History | Annotate | Download | only in browser
      1 // TODO(jam): move this file to src/content once we have an interface that the
      2 // embedder provides.  We can then use it to get the resource and resize the
      3 // window.
      4 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      5 // Use of this source code is governed by a BSD-style license that can be
      6 // found in the LICENSE file.
      7 
      8 #include "chrome/browser/gpu_process_host_ui_shim.h"
      9 
     10 #include "base/command_line.h"
     11 #include "base/id_map.h"
     12 #include "base/process_util.h"
     13 #include "chrome/browser/browser_process.h"
     14 #include "chrome/browser/gpu_data_manager.h"
     15 #include "chrome/browser/io_thread.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "content/browser/gpu_process_host.h"
     18 #include "content/browser/renderer_host/render_process_host.h"
     19 #include "content/browser/renderer_host/render_view_host.h"
     20 #include "content/browser/renderer_host/render_widget_host_view.h"
     21 #include "content/common/content_switches.h"
     22 #include "content/common/gpu_messages.h"
     23 #include "gpu/common/gpu_trace_event.h"
     24 
     25 #if defined(OS_LINUX)
     26 // These two #includes need to come after gpu_messages.h.
     27 #include <gdk/gdkwindow.h>  // NOLINT
     28 #include <gdk/gdkx.h>  // NOLINT
     29 #include "ui/base/x/x11_util.h"
     30 #include "ui/gfx/gtk_native_view_id_manager.h"
     31 #include "ui/gfx/size.h"
     32 #endif  // defined(OS_LINUX)
     33 namespace {
     34 
     35 // One of the linux specific headers defines this as a macro.
     36 #ifdef DestroyAll
     37 #undef DestroyAll
     38 #endif
     39 
     40 IDMap<GpuProcessHostUIShim> g_hosts_by_id;
     41 
     42 class SendOnIOThreadTask : public Task {
     43  public:
     44   SendOnIOThreadTask(int host_id, IPC::Message* msg)
     45       : host_id_(host_id),
     46         msg_(msg) {
     47   }
     48 
     49  private:
     50   void Run() {
     51     GpuProcessHost* host = GpuProcessHost::FromID(host_id_);
     52     if (host)
     53       host->Send(msg_.release());
     54   }
     55 
     56   int host_id_;
     57   scoped_ptr<IPC::Message> msg_;
     58 };
     59 
     60 class UIThreadSender : public IPC::Channel::Sender {
     61  public:
     62   virtual bool Send(IPC::Message* msg) {
     63   // The GPU process must never send a synchronous IPC message to the browser
     64   // process. This could result in deadlock. Unfortunately linux does this for
     65   // GpuHostMsg_ResizeXID. TODO(apatrick): fix this before issuing any GL calls
     66   // on the browser process' GPU thread.
     67 #if !defined(OS_LINUX)
     68     DCHECK(!msg->is_sync());
     69 #endif
     70 
     71     // When the GpuChannelManager sends an IPC, post it to the UI thread without
     72     // using IPC.
     73     bool success = BrowserThread::PostTask(
     74         BrowserThread::UI,
     75         FROM_HERE,
     76         new RouteToGpuProcessHostUIShimTask(0, *msg));
     77 
     78     delete msg;
     79     return success;
     80   }
     81 };
     82 
     83 void ForwardMessageToGpuThread(GpuChannelManager* gpu_channel_manager,
     84                                IPC::Message* msg) {
     85   bool success = gpu_channel_manager->OnMessageReceived(*msg);
     86 
     87   // If the message was not handled, it is likely it was intended for the
     88   // GpuChildThread, which does not exist in single process and in process GPU
     89   // mode.
     90   DCHECK(success);
     91 
     92   delete msg;
     93 }
     94 
     95 }  // namespace
     96 
     97 RouteToGpuProcessHostUIShimTask::RouteToGpuProcessHostUIShimTask(
     98     int host_id,
     99     const IPC::Message& msg)
    100   : host_id_(host_id),
    101     msg_(msg) {
    102 }
    103 
    104 RouteToGpuProcessHostUIShimTask::~RouteToGpuProcessHostUIShimTask() {
    105 }
    106 
    107 void RouteToGpuProcessHostUIShimTask::Run() {
    108   GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id_);
    109   if (ui_shim)
    110     ui_shim->OnMessageReceived(msg_);
    111 }
    112 
    113 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id)
    114     : host_id_(host_id),
    115       gpu_channel_manager_(NULL),
    116       ui_thread_sender_(NULL) {
    117   g_hosts_by_id.AddWithID(this, host_id_);
    118   if (host_id == 0) {
    119     ui_thread_sender_ = new UIThreadSender;
    120     gpu_channel_manager_ = new GpuChannelManager(
    121         ui_thread_sender_,
    122         NULL,
    123         g_browser_process->io_thread()->message_loop(),
    124         g_browser_process->shutdown_event());
    125   }
    126 }
    127 
    128 // static
    129 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) {
    130   DCHECK(!FromID(host_id));
    131   return new GpuProcessHostUIShim(host_id);
    132 }
    133 
    134 // static
    135 void GpuProcessHostUIShim::Destroy(int host_id) {
    136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    137   delete FromID(host_id);
    138 }
    139 
    140 // static
    141 void GpuProcessHostUIShim::DestroyAll() {
    142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    143   while (!g_hosts_by_id.IsEmpty()) {
    144     IDMap<GpuProcessHostUIShim>::iterator it(&g_hosts_by_id);
    145     delete it.GetCurrentValue();
    146   }
    147 }
    148 
    149 // static
    150 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) {
    151   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    152   return g_hosts_by_id.Lookup(host_id);
    153 }
    154 
    155 bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
    156   DCHECK(CalledOnValidThread());
    157 
    158   bool success;
    159 
    160   if (host_id_ == 0) {
    161     success = BrowserThread::PostTask(
    162         BrowserThread::GPU,
    163         FROM_HERE,
    164         NewRunnableFunction(ForwardMessageToGpuThread,
    165                             gpu_channel_manager_,
    166                             msg));
    167   } else {
    168     success = BrowserThread::PostTask(
    169         BrowserThread::IO,
    170         FROM_HERE,
    171         new SendOnIOThreadTask(host_id_, msg));
    172   }
    173 
    174   return success;
    175 }
    176 
    177 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
    178   DCHECK(CalledOnValidThread());
    179 
    180   if (message.routing_id() != MSG_ROUTING_CONTROL)
    181     return false;
    182 
    183   return OnControlMessageReceived(message);
    184 }
    185 
    186 #if defined(OS_MACOSX)
    187 
    188 void GpuProcessHostUIShim::DidDestroyAcceleratedSurface(int renderer_id,
    189                                                         int render_view_id) {
    190   // Destroy the command buffer that owns the accelerated surface.
    191   Send(new GpuMsg_DestroyCommandBuffer(renderer_id, render_view_id));
    192 }
    193 
    194 void GpuProcessHostUIShim::SendToGpuHost(int host_id, IPC::Message* msg) {
    195   GpuProcessHostUIShim* ui_shim = FromID(host_id);
    196   if (!ui_shim)
    197     return;
    198 
    199   ui_shim->Send(msg);
    200 }
    201 
    202 #endif
    203 
    204 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
    205   DCHECK(CalledOnValidThread());
    206   g_hosts_by_id.Remove(host_id_);
    207 
    208   // Ensure these are destroyed on the GPU thread.
    209   if (gpu_channel_manager_) {
    210     BrowserThread::DeleteSoon(BrowserThread::GPU,
    211                               FROM_HERE,
    212                               gpu_channel_manager_);
    213     gpu_channel_manager_ = NULL;
    214   }
    215   if (ui_thread_sender_) {
    216     BrowserThread::DeleteSoon(BrowserThread::GPU,
    217                               FROM_HERE,
    218                               ui_thread_sender_);
    219     ui_thread_sender_ = NULL;
    220   }
    221 }
    222 
    223 bool GpuProcessHostUIShim::OnControlMessageReceived(
    224     const IPC::Message& message) {
    225   DCHECK(CalledOnValidThread());
    226 
    227   IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
    228     IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
    229                         OnLogMessage)
    230 #if defined(OS_LINUX) && !defined(TOUCH_UI) || defined(OS_WIN)
    231     IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView, OnResizeView)
    232 #elif defined(OS_MACOSX)
    233     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
    234                         OnAcceleratedSurfaceSetIOSurface)
    235     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
    236                         OnAcceleratedSurfaceBuffersSwapped)
    237 #elif defined(OS_WIN)
    238     IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite, OnScheduleComposite);
    239 #endif
    240     IPC_MESSAGE_UNHANDLED_ERROR()
    241   IPC_END_MESSAGE_MAP()
    242 
    243   return true;
    244 }
    245 
    246 void GpuProcessHostUIShim::OnLogMessage(
    247     int level,
    248     const std::string& header,
    249     const std::string& message) {
    250   DictionaryValue* dict = new DictionaryValue();
    251   dict->SetInteger("level", level);
    252   dict->SetString("header", header);
    253   dict->SetString("message", message);
    254   GpuDataManager::GetInstance()->AddLogMessage(dict);
    255 }
    256 
    257 #if defined(OS_LINUX) && !defined(TOUCH_UI) || defined(OS_WIN)
    258 
    259 void GpuProcessHostUIShim::OnResizeView(int32 renderer_id,
    260                                         int32 render_view_id,
    261                                         int32 command_buffer_route_id,
    262                                         gfx::Size size) {
    263   RenderViewHost* host = RenderViewHost::FromID(renderer_id, render_view_id);
    264   if (host) {
    265     RenderWidgetHostView* view = host->view();
    266     if (view) {
    267       gfx::PluginWindowHandle handle = view->GetCompositingSurface();
    268 
    269       // Resize the window synchronously. The GPU process must not issue GL
    270       // calls on the command buffer until the window is the size it expects it
    271       // to be.
    272 #if defined(OS_LINUX) && !defined(TOUCH_UI)
    273       GdkWindow* window = reinterpret_cast<GdkWindow*>(
    274           gdk_xid_table_lookup(handle));
    275       if (window) {
    276         Display* display = GDK_WINDOW_XDISPLAY(window);
    277         gdk_window_resize(window, size.width(), size.height());
    278         XSync(display, False);
    279       }
    280 #elif defined(OS_WIN)
    281       SetWindowPos(handle,
    282           NULL,
    283           0, 0,
    284           size.width(),
    285           size.height(),
    286           SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER |
    287               SWP_NOACTIVATE | SWP_DEFERERASE);
    288 #endif
    289     }
    290   }
    291 
    292   // Always respond even if the window no longer exists. The GPU process cannot
    293   // make progress on the resizing command buffer until it receives the
    294   // response.
    295   Send(new GpuMsg_ResizeViewACK(renderer_id, command_buffer_route_id));
    296 }
    297 
    298 #elif defined(OS_MACOSX)
    299 
    300 void GpuProcessHostUIShim::OnAcceleratedSurfaceSetIOSurface(
    301     const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params) {
    302   RenderViewHost* host = RenderViewHost::FromID(params.renderer_id,
    303                                                 params.render_view_id);
    304   if (!host)
    305     return;
    306   RenderWidgetHostView* view = host->view();
    307   if (!view)
    308     return;
    309   view->AcceleratedSurfaceSetIOSurface(params.window,
    310                                        params.width,
    311                                        params.height,
    312                                        params.identifier);
    313 }
    314 
    315 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
    316     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
    317   RenderViewHost* host = RenderViewHost::FromID(params.renderer_id,
    318                                                 params.render_view_id);
    319   if (!host)
    320     return;
    321   RenderWidgetHostView* view = host->view();
    322   if (!view)
    323     return;
    324   view->AcceleratedSurfaceBuffersSwapped(
    325       // Parameters needed to swap the IOSurface.
    326       params.window,
    327       params.surface_id,
    328       // Parameters needed to formulate an acknowledgment.
    329       params.renderer_id,
    330       params.route_id,
    331       host_id_,
    332       params.swap_buffers_count);
    333 }
    334 
    335 #endif
    336 
    337 #if defined(OS_WIN)
    338 
    339 void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
    340     int render_view_id) {
    341   RenderViewHost* host = RenderViewHost::FromID(renderer_id,
    342                                                 render_view_id);
    343   if (!host) {
    344     return;
    345   }
    346   host->ScheduleComposite();
    347 }
    348 
    349 #endif
    350