Home | History | Annotate | Download | only in renderer_host
      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 #if defined(OS_WIN)
      6 #include <windows.h>
      7 #endif
      8 
      9 #include "content/browser/renderer_host/gpu_message_filter.h"
     10 
     11 #include "base/bind.h"
     12 #include "base/command_line.h"
     13 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
     14 #include "content/browser/gpu/gpu_process_host.h"
     15 #include "content/browser/gpu/gpu_surface_tracker.h"
     16 #include "content/browser/renderer_host/render_widget_helper.h"
     17 #include "content/common/gpu/gpu_messages.h"
     18 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
     19 #include "content/public/common/content_switches.h"
     20 #include "gpu/command_buffer/service/gpu_switches.h"
     21 
     22 namespace content {
     23 
     24 struct GpuMessageFilter::CreateViewCommandBufferRequest {
     25   CreateViewCommandBufferRequest(
     26       int32 surface_id_,
     27       const GPUCreateCommandBufferConfig& init_params_,
     28       IPC::Message* reply_)
     29       : surface_id(surface_id_),
     30         init_params(init_params_),
     31         reply(reply_) {
     32   }
     33   int32 surface_id;
     34   GPUCreateCommandBufferConfig init_params;
     35   IPC::Message* reply;
     36 };
     37 
     38 struct GpuMessageFilter::FrameSubscription {
     39   FrameSubscription(
     40       int in_route_id,
     41       scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber)
     42       : route_id(in_route_id),
     43         surface_id(0),
     44         subscriber(in_subscriber.Pass()),
     45         factory(subscriber.get()) {
     46   }
     47 
     48   int route_id;
     49   int surface_id;
     50   scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber;
     51   base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory;
     52 };
     53 
     54 GpuMessageFilter::GpuMessageFilter(int render_process_id,
     55                                    RenderWidgetHelper* render_widget_helper)
     56     : gpu_process_id_(0),
     57       render_process_id_(render_process_id),
     58       share_contexts_(false),
     59       render_widget_helper_(render_widget_helper),
     60       weak_ptr_factory_(this) {
     61   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     62 
     63 #if defined(USE_AURA) || defined(OS_ANDROID)
     64   // We use the GPU process for UI on Aura, and we need to share renderer GL
     65   // contexts with the compositor context.
     66   share_contexts_ = true;
     67 #else
     68   // Share contexts when compositing webview plugin or using share groups
     69   // for asynchronous texture uploads.
     70   if (!CommandLine::ForCurrentProcess()->HasSwitch(
     71           switches::kDisableBrowserPluginCompositing) ||
     72       CommandLine::ForCurrentProcess()->HasSwitch(
     73           switches::kEnableShareGroupAsyncTextureUpload))
     74     share_contexts_ = true;
     75 #endif
     76 }
     77 
     78 GpuMessageFilter::~GpuMessageFilter() {
     79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     80   EndAllFrameSubscriptions();
     81 }
     82 
     83 bool GpuMessageFilter::OnMessageReceived(
     84     const IPC::Message& message,
     85     bool* message_was_ok) {
     86   bool handled = true;
     87   IPC_BEGIN_MESSAGE_MAP_EX(GpuMessageFilter, message, *message_was_ok)
     88     IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_EstablishGpuChannel,
     89                                     OnEstablishGpuChannel)
     90     IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_CreateViewCommandBuffer,
     91                                     OnCreateViewCommandBuffer)
     92     IPC_MESSAGE_UNHANDLED(handled = false)
     93   IPC_END_MESSAGE_MAP_EX()
     94   return handled;
     95 }
     96 
     97 void GpuMessageFilter::SurfaceUpdated(int32 surface_id) {
     98   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     99   typedef std::vector<linked_ptr<CreateViewCommandBufferRequest> > RequestList;
    100   RequestList retry_requests;
    101   retry_requests.swap(pending_requests_);
    102   for (RequestList::iterator it = retry_requests.begin();
    103       it != retry_requests.end(); ++it) {
    104     if ((*it)->surface_id != surface_id) {
    105       pending_requests_.push_back(*it);
    106     } else {
    107       linked_ptr<CreateViewCommandBufferRequest> request = *it;
    108       OnCreateViewCommandBuffer(request->surface_id,
    109                                 request->init_params,
    110                                 request->reply);
    111     }
    112   }
    113 }
    114 
    115 void GpuMessageFilter::BeginFrameSubscription(
    116     int route_id,
    117     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
    118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    119   linked_ptr<FrameSubscription> subscription(
    120       new FrameSubscription(route_id, subscriber.Pass()));
    121   BeginFrameSubscriptionInternal(subscription);
    122 }
    123 
    124 void GpuMessageFilter::EndFrameSubscription(int route_id) {
    125   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    126   FrameSubscriptionList frame_subscription_list;
    127   frame_subscription_list.swap(frame_subscription_list_);
    128   for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
    129        it != frame_subscription_list.end(); ++it) {
    130     if ((*it)->route_id != route_id)
    131       frame_subscription_list_.push_back(*it);
    132     else
    133       EndFrameSubscriptionInternal(*it);
    134   }
    135 }
    136 
    137 void GpuMessageFilter::OnEstablishGpuChannel(
    138     CauseForGpuLaunch cause_for_gpu_launch,
    139     IPC::Message* reply) {
    140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    141 
    142   // TODO(apatrick): Eventually, this will return the route ID of a
    143   // GpuProcessStub, from which the renderer process will create a
    144   // GpuProcessProxy. The renderer will use the proxy for all subsequent
    145   // communication with the GPU process. This means if the GPU process
    146   // terminates, the renderer process will not find itself unknowingly sending
    147   // IPCs to a newly launched GPU process. Also, I will rename this function
    148   // to something like OnCreateGpuProcess.
    149   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    150   if (!host) {
    151     host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    152                                cause_for_gpu_launch);
    153     if (!host) {
    154       reply->set_reply_error();
    155       Send(reply);
    156       return;
    157     }
    158 
    159     gpu_process_id_ = host->host_id();
    160 
    161     // Apply all frame subscriptions to the new GpuProcessHost.
    162     BeginAllFrameSubscriptions();
    163   }
    164 
    165   host->EstablishGpuChannel(
    166       render_process_id_,
    167       share_contexts_,
    168       base::Bind(&GpuMessageFilter::EstablishChannelCallback,
    169                  weak_ptr_factory_.GetWeakPtr(),
    170                  reply));
    171 }
    172 
    173 void GpuMessageFilter::OnCreateViewCommandBuffer(
    174     int32 surface_id,
    175     const GPUCreateCommandBufferConfig& init_params,
    176     IPC::Message* reply) {
    177   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    178 
    179   GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
    180   gfx::GLSurfaceHandle compositing_surface;
    181 
    182   int renderer_id = 0;
    183   int render_widget_id = 0;
    184   bool result = surface_tracker->GetRenderWidgetIDForSurface(
    185       surface_id, &renderer_id, &render_widget_id);
    186   if (result && renderer_id == render_process_id_) {
    187     compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);
    188   } else {
    189     DLOG(ERROR) << "Renderer " << render_process_id_
    190                 << " tried to access a surface for renderer " << renderer_id;
    191   }
    192 
    193   if (compositing_surface.parent_gpu_process_id &&
    194       compositing_surface.parent_gpu_process_id != gpu_process_id_) {
    195     // If the current handle for the surface is using a different (older) gpu
    196     // host, it means the GPU process died and we need to wait until the UI
    197     // re-allocates the surface in the new process.
    198     linked_ptr<CreateViewCommandBufferRequest> request(
    199         new CreateViewCommandBufferRequest(surface_id, init_params, reply));
    200     pending_requests_.push_back(request);
    201     return;
    202   }
    203 
    204   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    205   if (!host || compositing_surface.is_null()) {
    206     // TODO(apatrick): Eventually, this IPC message will be routed to a
    207     // GpuProcessStub with a particular routing ID. The error will be set if
    208     // the GpuProcessStub with that routing ID is not in the MessageRouter.
    209     reply->set_reply_error();
    210     Send(reply);
    211     return;
    212   }
    213 
    214   host->CreateViewCommandBuffer(
    215       compositing_surface,
    216       surface_id,
    217       render_process_id_,
    218       init_params,
    219       base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
    220                  weak_ptr_factory_.GetWeakPtr(),
    221                  reply));
    222 }
    223 
    224 void GpuMessageFilter::EstablishChannelCallback(
    225     IPC::Message* reply,
    226     const IPC::ChannelHandle& channel,
    227     const gpu::GPUInfo& gpu_info) {
    228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    229 
    230   GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
    231       reply, render_process_id_, channel, gpu_info);
    232   Send(reply);
    233 }
    234 
    235 void GpuMessageFilter::CreateCommandBufferCallback(
    236     IPC::Message* reply, int32 route_id) {
    237   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    238   GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply, route_id);
    239   Send(reply);
    240 }
    241 
    242 void GpuMessageFilter::BeginAllFrameSubscriptions() {
    243   FrameSubscriptionList frame_subscription_list;
    244   frame_subscription_list.swap(frame_subscription_list_);
    245   for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
    246        it != frame_subscription_list.end(); ++it) {
    247     BeginFrameSubscriptionInternal(*it);
    248   }
    249 }
    250 
    251 void GpuMessageFilter::EndAllFrameSubscriptions() {
    252   for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
    253        it != frame_subscription_list_.end(); ++it) {
    254     EndFrameSubscriptionInternal(*it);
    255   }
    256   frame_subscription_list_.clear();
    257 }
    258 
    259 void GpuMessageFilter::BeginFrameSubscriptionInternal(
    260     linked_ptr<FrameSubscription> subscription) {
    261   if (!subscription->surface_id) {
    262     GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
    263     subscription->surface_id = surface_tracker->LookupSurfaceForRenderer(
    264         render_process_id_, subscription->route_id);
    265 
    266     // If the surface ID cannot be found this subscription is dropped.
    267     if (!subscription->surface_id)
    268       return;
    269   }
    270   frame_subscription_list_.push_back(subscription);
    271 
    272   // Frame subscriber is owned by this object, but it is shared with
    273   // GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing
    274   // and we do not get a signal. This object can also be destroyed independent
    275   // of GpuProcessHost. To ensure that GpuProcessHost does not reference a
    276   // deleted frame subscriber, a weak reference is shared.
    277   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    278   if (!host)
    279     return;
    280   host->BeginFrameSubscription(subscription->surface_id,
    281                                subscription->factory.GetWeakPtr());
    282 }
    283 
    284 void GpuMessageFilter::EndFrameSubscriptionInternal(
    285     linked_ptr<FrameSubscription> subscription) {
    286   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    287 
    288   // An empty surface ID means subscription has never started in GpuProcessHost
    289   // so it is not necessary to end it.
    290   if (!host || !subscription->surface_id)
    291     return;
    292 
    293   // Note that GpuProcessHost here might not be the same one that frame
    294   // subscription has applied.
    295   host->EndFrameSubscription(subscription->surface_id);
    296 }
    297 
    298 }  // namespace content
    299