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 // From gl2/gl2ext.h.
     26 #ifndef GL_MAILBOX_SIZE_CHROMIUM
     27 #define GL_MAILBOX_SIZE_CHROMIUM 64
     28 #endif
     29 
     30 namespace content {
     31 
     32 namespace {
     33 
     34 // One of the linux specific headers defines this as a macro.
     35 #ifdef DestroyAll
     36 #undef DestroyAll
     37 #endif
     38 
     39 base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id =
     40     LAZY_INSTANCE_INITIALIZER;
     41 
     42 void SendOnIOThreadTask(int host_id, IPC::Message* msg) {
     43   GpuProcessHost* host = GpuProcessHost::FromID(host_id);
     44   if (host)
     45     host->Send(msg);
     46   else
     47     delete msg;
     48 }
     49 
     50 class ScopedSendOnIOThread {
     51  public:
     52   ScopedSendOnIOThread(int host_id, IPC::Message* msg)
     53       : host_id_(host_id),
     54         msg_(msg),
     55         cancelled_(false) {
     56   }
     57 
     58   ~ScopedSendOnIOThread() {
     59     if (!cancelled_) {
     60       BrowserThread::PostTask(BrowserThread::IO,
     61                               FROM_HERE,
     62                               base::Bind(&SendOnIOThreadTask,
     63                                          host_id_,
     64                                          msg_.release()));
     65     }
     66   }
     67 
     68   void Cancel() { cancelled_ = true; }
     69 
     70  private:
     71   int host_id_;
     72   scoped_ptr<IPC::Message> msg_;
     73   bool cancelled_;
     74 };
     75 
     76 RenderWidgetHostViewPort* GetRenderWidgetHostViewFromSurfaceID(
     77     int surface_id) {
     78   int render_process_id = 0;
     79   int render_widget_id = 0;
     80   if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
     81         surface_id, &render_process_id, &render_widget_id))
     82     return NULL;
     83 
     84   RenderWidgetHost* host =
     85       RenderWidgetHost::FromID(render_process_id, render_widget_id);
     86   return host ? RenderWidgetHostViewPort::FromRWHV(host->GetView()) : NULL;
     87 }
     88 
     89 }  // namespace
     90 
     91 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) {
     92   GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id);
     93   if (ui_shim)
     94     ui_shim->OnMessageReceived(msg);
     95 }
     96 
     97 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id)
     98     : host_id_(host_id) {
     99   g_hosts_by_id.Pointer()->AddWithID(this, host_id_);
    100 }
    101 
    102 // static
    103 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) {
    104   DCHECK(!FromID(host_id));
    105   return new GpuProcessHostUIShim(host_id);
    106 }
    107 
    108 // static
    109 void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) {
    110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    111 
    112   GpuDataManagerImpl::GetInstance()->AddLogMessage(
    113       logging::LOG_ERROR, "GpuProcessHostUIShim",
    114       message);
    115 
    116   delete FromID(host_id);
    117 }
    118 
    119 // static
    120 void GpuProcessHostUIShim::DestroyAll() {
    121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    122   while (!g_hosts_by_id.Pointer()->IsEmpty()) {
    123     IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
    124     delete it.GetCurrentValue();
    125   }
    126 }
    127 
    128 // static
    129 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) {
    130   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    131   return g_hosts_by_id.Pointer()->Lookup(host_id);
    132 }
    133 
    134 // static
    135 GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() {
    136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    137   if (g_hosts_by_id.Pointer()->IsEmpty())
    138     return NULL;
    139   IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
    140   return it.GetCurrentValue();
    141 }
    142 
    143 bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
    144   DCHECK(CalledOnValidThread());
    145   return BrowserThread::PostTask(BrowserThread::IO,
    146                                  FROM_HERE,
    147                                  base::Bind(&SendOnIOThreadTask,
    148                                             host_id_,
    149                                             msg));
    150 }
    151 
    152 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
    153   DCHECK(CalledOnValidThread());
    154 
    155   if (message.routing_id() != MSG_ROUTING_CONTROL)
    156     return false;
    157 
    158   return OnControlMessageReceived(message);
    159 }
    160 
    161 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
    162   Send(new GpuMsg_Clean());
    163 }
    164 
    165 void GpuProcessHostUIShim::SimulateCrash() {
    166   Send(new GpuMsg_Crash());
    167 }
    168 
    169 void GpuProcessHostUIShim::SimulateHang() {
    170   Send(new GpuMsg_Hang());
    171 }
    172 
    173 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
    174   DCHECK(CalledOnValidThread());
    175   g_hosts_by_id.Pointer()->Remove(host_id_);
    176 }
    177 
    178 bool GpuProcessHostUIShim::OnControlMessageReceived(
    179     const IPC::Message& message) {
    180   DCHECK(CalledOnValidThread());
    181 
    182   IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
    183     IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
    184                         OnLogMessage)
    185 
    186     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized,
    187                         OnAcceleratedSurfaceInitialized)
    188     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
    189                         OnAcceleratedSurfaceBuffersSwapped)
    190     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
    191                         OnAcceleratedSurfacePostSubBuffer)
    192     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
    193                         OnAcceleratedSurfaceSuspend)
    194     IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
    195                         OnGraphicsInfoCollected)
    196     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
    197                         OnAcceleratedSurfaceRelease)
    198     IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
    199                         OnVideoMemoryUsageStatsReceived);
    200     IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
    201                         OnUpdateVSyncParameters)
    202     IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn)
    203 
    204     IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView, OnResizeView)
    205 
    206     IPC_MESSAGE_UNHANDLED_ERROR()
    207   IPC_END_MESSAGE_MAP()
    208 
    209   return true;
    210 }
    211 
    212 void GpuProcessHostUIShim::OnUpdateVSyncParameters(int surface_id,
    213                                                    base::TimeTicks timebase,
    214                                                    base::TimeDelta interval) {
    215 
    216   int render_process_id = 0;
    217   int render_widget_id = 0;
    218   if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
    219       surface_id, &render_process_id, &render_widget_id)) {
    220     return;
    221   }
    222   RenderWidgetHost* rwh =
    223       RenderWidgetHost::FromID(render_process_id, render_widget_id);
    224   if (!rwh)
    225     return;
    226   RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval);
    227 }
    228 
    229 void GpuProcessHostUIShim::OnLogMessage(
    230     int level,
    231     const std::string& header,
    232     const std::string& message) {
    233   GpuDataManagerImpl::GetInstance()->AddLogMessage(
    234       level, header, message);
    235 }
    236 
    237 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
    238     const gpu::GPUInfo& gpu_info) {
    239   // OnGraphicsInfoCollected is sent back after the GPU process successfully
    240   // initializes GL.
    241   TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
    242 
    243   GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info);
    244 }
    245 
    246 void GpuProcessHostUIShim::OnResizeView(int32 surface_id,
    247                                         int32 route_id,
    248                                         gfx::Size size) {
    249   // Always respond even if the window no longer exists. The GPU process cannot
    250   // make progress on the resizing command buffer until it receives the
    251   // response.
    252   ScopedSendOnIOThread delayed_send(
    253       host_id_,
    254       new AcceleratedSurfaceMsg_ResizeViewACK(route_id));
    255 
    256   RenderWidgetHostViewPort* view =
    257       GetRenderWidgetHostViewFromSurfaceID(surface_id);
    258   if (!view)
    259     return;
    260 
    261   view->ResizeCompositingSurface(size);
    262 }
    263 
    264 static base::TimeDelta GetSwapDelay() {
    265   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
    266   int delay = 0;
    267   if (cmd_line->HasSwitch(switches::kGpuSwapDelay)) {
    268     base::StringToInt(cmd_line->GetSwitchValueNative(
    269         switches::kGpuSwapDelay).c_str(), &delay);
    270   }
    271   return base::TimeDelta::FromMilliseconds(delay);
    272 }
    273 
    274 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id,
    275                                                            int32 route_id) {
    276   RenderWidgetHostViewPort* view =
    277       GetRenderWidgetHostViewFromSurfaceID(surface_id);
    278   if (!view)
    279     return;
    280   view->AcceleratedSurfaceInitialized(host_id_, route_id);
    281 }
    282 
    283 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
    284     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
    285   TRACE_EVENT0("renderer",
    286       "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
    287   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
    288   ack_params.mailbox_name = params.mailbox_name;
    289   ack_params.sync_point = 0;
    290   ScopedSendOnIOThread delayed_send(
    291       host_id_,
    292       new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
    293                                                 ack_params));
    294 
    295   if (!params.mailbox_name.empty() &&
    296       params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM)
    297     return;
    298 
    299   RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID(
    300       params.surface_id);
    301   if (!view)
    302     return;
    303 
    304   delayed_send.Cancel();
    305 
    306   static const base::TimeDelta swap_delay = GetSwapDelay();
    307   if (swap_delay.ToInternalValue())
    308     base::PlatformThread::Sleep(swap_delay);
    309 
    310   // View must send ACK message after next composite.
    311   view->AcceleratedSurfaceBuffersSwapped(params, host_id_);
    312   view->DidReceiveRendererFrame();
    313 }
    314 
    315 void GpuProcessHostUIShim::OnFrameDrawn(const ui::LatencyInfo& latency_info) {
    316   RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
    317 }
    318 
    319 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer(
    320     const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
    321   TRACE_EVENT0("renderer",
    322       "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer");
    323 
    324   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
    325   ack_params.mailbox_name = params.mailbox_name;
    326   ack_params.sync_point = 0;
    327    ScopedSendOnIOThread delayed_send(
    328       host_id_,
    329       new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
    330                                                 ack_params));
    331 
    332   if (!params.mailbox_name.empty() &&
    333       params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM)
    334     return;
    335 
    336   RenderWidgetHostViewPort* view =
    337       GetRenderWidgetHostViewFromSurfaceID(params.surface_id);
    338   if (!view)
    339     return;
    340 
    341   delayed_send.Cancel();
    342 
    343   // View must send ACK message after next composite.
    344   view->AcceleratedSurfacePostSubBuffer(params, host_id_);
    345   view->DidReceiveRendererFrame();
    346 }
    347 
    348 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) {
    349   TRACE_EVENT0("renderer",
    350       "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend");
    351 
    352   RenderWidgetHostViewPort* view =
    353       GetRenderWidgetHostViewFromSurfaceID(surface_id);
    354   if (!view)
    355     return;
    356 
    357   view->AcceleratedSurfaceSuspend();
    358 }
    359 
    360 void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease(
    361     const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
    362   RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID(
    363       params.surface_id);
    364   if (!view)
    365     return;
    366   view->AcceleratedSurfaceRelease();
    367 }
    368 
    369 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
    370     const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
    371   GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
    372       video_memory_usage_stats);
    373 }
    374 
    375 }  // namespace content
    376