Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/debug/trace_event.h"
     12 #include "base/id_map.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "content/browser/gpu/gpu_data_manager_impl.h"
     16 #include "content/browser/gpu/gpu_process_host.h"
     17 #include "content/browser/gpu/gpu_surface_tracker.h"
     18 #include "content/browser/renderer_host/render_process_host_impl.h"
     19 #include "content/browser/renderer_host/render_view_host_impl.h"
     20 #include "content/common/gpu/gpu_messages.h"
     21 #include "content/port/browser/render_widget_host_view_port.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "ui/gl/gl_switches.h"
     24 
     25 #if defined(TOOLKIT_GTK)
     26 // These two #includes need to come after gpu_messages.h.
     27 #include "ui/base/x/x11_util.h"
     28 #include "ui/gfx/size.h"
     29 #include <gdk/gdk.h>   // NOLINT
     30 #include <gdk/gdkx.h>  // NOLINT
     31 #endif
     32 
     33 // From gl2/gl2ext.h.
     34 #ifndef GL_MAILBOX_SIZE_CHROMIUM
     35 #define GL_MAILBOX_SIZE_CHROMIUM 64
     36 #endif
     37 
     38 namespace content {
     39 
     40 namespace {
     41 
     42 // One of the linux specific headers defines this as a macro.
     43 #ifdef DestroyAll
     44 #undef DestroyAll
     45 #endif
     46 
     47 base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id =
     48     LAZY_INSTANCE_INITIALIZER;
     49 
     50 void SendOnIOThreadTask(int host_id, IPC::Message* msg) {
     51   GpuProcessHost* host = GpuProcessHost::FromID(host_id);
     52   if (host)
     53     host->Send(msg);
     54   else
     55     delete msg;
     56 }
     57 
     58 class ScopedSendOnIOThread {
     59  public:
     60   ScopedSendOnIOThread(int host_id, IPC::Message* msg)
     61       : host_id_(host_id),
     62         msg_(msg),
     63         cancelled_(false) {
     64   }
     65 
     66   ~ScopedSendOnIOThread() {
     67     if (!cancelled_) {
     68       BrowserThread::PostTask(BrowserThread::IO,
     69                               FROM_HERE,
     70                               base::Bind(&SendOnIOThreadTask,
     71                                          host_id_,
     72                                          msg_.release()));
     73     }
     74   }
     75 
     76   void Cancel() { cancelled_ = true; }
     77 
     78  private:
     79   int host_id_;
     80   scoped_ptr<IPC::Message> msg_;
     81   bool cancelled_;
     82 };
     83 
     84 RenderWidgetHostViewPort* GetRenderWidgetHostViewFromSurfaceID(
     85     int surface_id) {
     86   int render_process_id = 0;
     87   int render_widget_id = 0;
     88   if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
     89         surface_id, &render_process_id, &render_widget_id))
     90     return NULL;
     91 
     92   RenderWidgetHost* host =
     93       RenderWidgetHost::FromID(render_process_id, render_widget_id);
     94   return host ? RenderWidgetHostViewPort::FromRWHV(host->GetView()) : NULL;
     95 }
     96 
     97 }  // namespace
     98 
     99 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) {
    100   GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id);
    101   if (ui_shim)
    102     ui_shim->OnMessageReceived(msg);
    103 }
    104 
    105 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id)
    106     : host_id_(host_id) {
    107   g_hosts_by_id.Pointer()->AddWithID(this, host_id_);
    108 }
    109 
    110 // static
    111 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) {
    112   DCHECK(!FromID(host_id));
    113   return new GpuProcessHostUIShim(host_id);
    114 }
    115 
    116 // static
    117 void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) {
    118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    119 
    120   GpuDataManagerImpl::GetInstance()->AddLogMessage(
    121       logging::LOG_ERROR, "GpuProcessHostUIShim",
    122       message);
    123 
    124   delete FromID(host_id);
    125 }
    126 
    127 // static
    128 void GpuProcessHostUIShim::DestroyAll() {
    129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    130   while (!g_hosts_by_id.Pointer()->IsEmpty()) {
    131     IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
    132     delete it.GetCurrentValue();
    133   }
    134 }
    135 
    136 // static
    137 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) {
    138   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    139   return g_hosts_by_id.Pointer()->Lookup(host_id);
    140 }
    141 
    142 // static
    143 GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() {
    144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    145   if (g_hosts_by_id.Pointer()->IsEmpty())
    146     return NULL;
    147   IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
    148   return it.GetCurrentValue();
    149 }
    150 
    151 bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
    152   DCHECK(CalledOnValidThread());
    153   return BrowserThread::PostTask(BrowserThread::IO,
    154                                  FROM_HERE,
    155                                  base::Bind(&SendOnIOThreadTask,
    156                                             host_id_,
    157                                             msg));
    158 }
    159 
    160 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
    161   DCHECK(CalledOnValidThread());
    162 
    163   if (message.routing_id() != MSG_ROUTING_CONTROL)
    164     return false;
    165 
    166   return OnControlMessageReceived(message);
    167 }
    168 
    169 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
    170   Send(new GpuMsg_Clean());
    171 }
    172 
    173 void GpuProcessHostUIShim::SimulateCrash() {
    174   Send(new GpuMsg_Crash());
    175 }
    176 
    177 void GpuProcessHostUIShim::SimulateHang() {
    178   Send(new GpuMsg_Hang());
    179 }
    180 
    181 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
    182   DCHECK(CalledOnValidThread());
    183   g_hosts_by_id.Pointer()->Remove(host_id_);
    184 }
    185 
    186 bool GpuProcessHostUIShim::OnControlMessageReceived(
    187     const IPC::Message& message) {
    188   DCHECK(CalledOnValidThread());
    189 
    190   IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
    191     IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
    192                         OnLogMessage)
    193 
    194     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
    195                         OnAcceleratedSurfaceBuffersSwapped)
    196     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
    197                         OnAcceleratedSurfacePostSubBuffer)
    198     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
    199                         OnAcceleratedSurfaceSuspend)
    200     IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
    201                         OnGraphicsInfoCollected)
    202     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
    203                         OnAcceleratedSurfaceRelease)
    204     IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
    205                         OnVideoMemoryUsageStatsReceived);
    206     IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
    207                         OnUpdateVSyncParameters)
    208     IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn)
    209 
    210 #if defined(TOOLKIT_GTK) || defined(OS_WIN)
    211     IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView, OnResizeView)
    212 #endif
    213 
    214     IPC_MESSAGE_UNHANDLED_ERROR()
    215   IPC_END_MESSAGE_MAP()
    216 
    217   return true;
    218 }
    219 
    220 void GpuProcessHostUIShim::OnUpdateVSyncParameters(int surface_id,
    221                                                    base::TimeTicks timebase,
    222                                                    base::TimeDelta interval) {
    223 
    224   int render_process_id = 0;
    225   int render_widget_id = 0;
    226   if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
    227       surface_id, &render_process_id, &render_widget_id)) {
    228     return;
    229   }
    230   RenderWidgetHost* rwh =
    231       RenderWidgetHost::FromID(render_process_id, render_widget_id);
    232   if (!rwh)
    233     return;
    234   RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval);
    235 }
    236 
    237 void GpuProcessHostUIShim::OnLogMessage(
    238     int level,
    239     const std::string& header,
    240     const std::string& message) {
    241   GpuDataManagerImpl::GetInstance()->AddLogMessage(
    242       level, header, message);
    243 }
    244 
    245 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
    246     const gpu::GPUInfo& gpu_info) {
    247   // OnGraphicsInfoCollected is sent back after the GPU process successfully
    248   // initializes GL.
    249   TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
    250 
    251   GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info);
    252 }
    253 
    254 #if defined(TOOLKIT_GTK) || defined(OS_WIN)
    255 
    256 void GpuProcessHostUIShim::OnResizeView(int32 surface_id,
    257                                         int32 route_id,
    258                                         gfx::Size size) {
    259   // Always respond even if the window no longer exists. The GPU process cannot
    260   // make progress on the resizing command buffer until it receives the
    261   // response.
    262   ScopedSendOnIOThread delayed_send(
    263       host_id_,
    264       new AcceleratedSurfaceMsg_ResizeViewACK(route_id));
    265 
    266   RenderWidgetHostViewPort* view =
    267       GetRenderWidgetHostViewFromSurfaceID(surface_id);
    268   if (!view)
    269     return;
    270 
    271   gfx::GLSurfaceHandle surface = view->GetCompositingSurface();
    272 
    273   // Resize the window synchronously. The GPU process must not issue GL
    274   // calls on the command buffer until the window is the size it expects it
    275   // to be.
    276 #if defined(TOOLKIT_GTK)
    277   GdkWindow* window = reinterpret_cast<GdkWindow*>(
    278       gdk_xid_table_lookup(surface.handle));
    279   if (window) {
    280     Display* display = GDK_WINDOW_XDISPLAY(window);
    281     gdk_window_resize(window, size.width(), size.height());
    282     XSync(display, False);
    283   }
    284 #elif defined(OS_WIN)
    285   // Ensure window does not have zero area because D3D cannot create a zero
    286   // area swap chain.
    287   SetWindowPos(surface.handle,
    288       NULL,
    289       0, 0,
    290       std::max(1, size.width()),
    291       std::max(1, size.height()),
    292       SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER |
    293           SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOMOVE);
    294 #endif
    295 }
    296 
    297 #endif
    298 
    299 static base::TimeDelta GetSwapDelay() {
    300   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
    301   int delay = 0;
    302   if (cmd_line->HasSwitch(switches::kGpuSwapDelay)) {
    303     base::StringToInt(cmd_line->GetSwitchValueNative(
    304         switches::kGpuSwapDelay).c_str(), &delay);
    305   }
    306   return base::TimeDelta::FromMilliseconds(delay);
    307 }
    308 
    309 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
    310     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
    311   TRACE_EVENT0("renderer",
    312       "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
    313   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
    314   ack_params.mailbox_name = params.mailbox_name;
    315   ack_params.sync_point = 0;
    316   ScopedSendOnIOThread delayed_send(
    317       host_id_,
    318       new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
    319                                                 ack_params));
    320 
    321   if (!params.mailbox_name.empty() &&
    322       params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM)
    323     return;
    324 
    325   RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID(
    326       params.surface_id);
    327   if (!view)
    328     return;
    329 
    330   delayed_send.Cancel();
    331 
    332   static const base::TimeDelta swap_delay = GetSwapDelay();
    333   if (swap_delay.ToInternalValue())
    334     base::PlatformThread::Sleep(swap_delay);
    335 
    336   // View must send ACK message after next composite.
    337   view->AcceleratedSurfaceBuffersSwapped(params, host_id_);
    338   view->DidReceiveRendererFrame();
    339 }
    340 
    341 void GpuProcessHostUIShim::OnFrameDrawn(const ui::LatencyInfo& latency_info) {
    342   RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
    343 }
    344 
    345 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer(
    346     const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
    347   TRACE_EVENT0("renderer",
    348       "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer");
    349 
    350   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
    351   ack_params.mailbox_name = params.mailbox_name;
    352   ack_params.sync_point = 0;
    353    ScopedSendOnIOThread delayed_send(
    354       host_id_,
    355       new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
    356                                                 ack_params));
    357 
    358   if (!params.mailbox_name.empty() &&
    359       params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM)
    360     return;
    361 
    362   RenderWidgetHostViewPort* view =
    363       GetRenderWidgetHostViewFromSurfaceID(params.surface_id);
    364   if (!view)
    365     return;
    366 
    367   delayed_send.Cancel();
    368 
    369   // View must send ACK message after next composite.
    370   view->AcceleratedSurfacePostSubBuffer(params, host_id_);
    371   view->DidReceiveRendererFrame();
    372 }
    373 
    374 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) {
    375   TRACE_EVENT0("renderer",
    376       "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend");
    377 
    378   RenderWidgetHostViewPort* view =
    379       GetRenderWidgetHostViewFromSurfaceID(surface_id);
    380   if (!view)
    381     return;
    382 
    383   view->AcceleratedSurfaceSuspend();
    384 }
    385 
    386 void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease(
    387     const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
    388   RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID(
    389       params.surface_id);
    390   if (!view)
    391     return;
    392   view->AcceleratedSurfaceRelease();
    393 }
    394 
    395 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
    396     const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
    397   GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
    398       video_memory_usage_stats);
    399 }
    400 
    401 }  // namespace content
    402