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       scoped_ptr<IPC::Message> reply)
     29       : surface_id(surface_id),
     30         init_params(init_params),
     31         reply(reply.Pass()) {
     32   }
     33   int32 surface_id;
     34   GPUCreateCommandBufferConfig init_params;
     35   scoped_ptr<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.release());
    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_ptr) {
    140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    141   scoped_ptr<IPC::Message> reply(reply_ptr);
    142 
    143   // TODO(apatrick): Eventually, this will return the route ID of a
    144   // GpuProcessStub, from which the renderer process will create a
    145   // GpuProcessProxy. The renderer will use the proxy for all subsequent
    146   // communication with the GPU process. This means if the GPU process
    147   // terminates, the renderer process will not find itself unknowingly sending
    148   // IPCs to a newly launched GPU process. Also, I will rename this function
    149   // to something like OnCreateGpuProcess.
    150   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    151   if (!host) {
    152     host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    153                                cause_for_gpu_launch);
    154     if (!host) {
    155       reply->set_reply_error();
    156       Send(reply.release());
    157       return;
    158     }
    159 
    160     gpu_process_id_ = host->host_id();
    161 
    162     // Apply all frame subscriptions to the new GpuProcessHost.
    163     BeginAllFrameSubscriptions();
    164   }
    165 
    166   host->EstablishGpuChannel(
    167       render_process_id_,
    168       share_contexts_,
    169       base::Bind(&GpuMessageFilter::EstablishChannelCallback,
    170                  weak_ptr_factory_.GetWeakPtr(),
    171                  base::Passed(&reply)));
    172 }
    173 
    174 void GpuMessageFilter::OnCreateViewCommandBuffer(
    175     int32 surface_id,
    176     const GPUCreateCommandBufferConfig& init_params,
    177     IPC::Message* reply_ptr) {
    178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    179   scoped_ptr<IPC::Message> reply(reply_ptr);
    180 
    181   GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
    182   gfx::GLSurfaceHandle compositing_surface;
    183 
    184   int renderer_id = 0;
    185   int render_widget_id = 0;
    186   bool result = surface_tracker->GetRenderWidgetIDForSurface(
    187       surface_id, &renderer_id, &render_widget_id);
    188   if (result && renderer_id == render_process_id_) {
    189     compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);
    190   } else {
    191     DLOG(ERROR) << "Renderer " << render_process_id_
    192                 << " tried to access a surface for renderer " << renderer_id;
    193   }
    194 
    195   if (compositing_surface.parent_gpu_process_id &&
    196       compositing_surface.parent_gpu_process_id != gpu_process_id_) {
    197     // If the current handle for the surface is using a different (older) gpu
    198     // host, it means the GPU process died and we need to wait until the UI
    199     // re-allocates the surface in the new process.
    200     linked_ptr<CreateViewCommandBufferRequest> request(
    201         new CreateViewCommandBufferRequest(
    202             surface_id, init_params, reply.Pass()));
    203     pending_requests_.push_back(request);
    204     return;
    205   }
    206 
    207   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    208   if (!host || compositing_surface.is_null()) {
    209     // TODO(apatrick): Eventually, this IPC message will be routed to a
    210     // GpuProcessStub with a particular routing ID. The error will be set if
    211     // the GpuProcessStub with that routing ID is not in the MessageRouter.
    212     reply->set_reply_error();
    213     Send(reply.release());
    214     return;
    215   }
    216 
    217   host->CreateViewCommandBuffer(
    218       compositing_surface,
    219       surface_id,
    220       render_process_id_,
    221       init_params,
    222       base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
    223                  weak_ptr_factory_.GetWeakPtr(),
    224                  base::Passed(&reply)));
    225 }
    226 
    227 void GpuMessageFilter::EstablishChannelCallback(
    228     scoped_ptr<IPC::Message> reply,
    229     const IPC::ChannelHandle& channel,
    230     const gpu::GPUInfo& gpu_info) {
    231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    232 
    233   GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
    234       reply.get(), render_process_id_, channel, gpu_info);
    235   Send(reply.release());
    236 }
    237 
    238 void GpuMessageFilter::CreateCommandBufferCallback(
    239     scoped_ptr<IPC::Message> reply, int32 route_id) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    241   GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), route_id);
    242   Send(reply.release());
    243 }
    244 
    245 void GpuMessageFilter::BeginAllFrameSubscriptions() {
    246   FrameSubscriptionList frame_subscription_list;
    247   frame_subscription_list.swap(frame_subscription_list_);
    248   for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
    249        it != frame_subscription_list.end(); ++it) {
    250     BeginFrameSubscriptionInternal(*it);
    251   }
    252 }
    253 
    254 void GpuMessageFilter::EndAllFrameSubscriptions() {
    255   for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
    256        it != frame_subscription_list_.end(); ++it) {
    257     EndFrameSubscriptionInternal(*it);
    258   }
    259   frame_subscription_list_.clear();
    260 }
    261 
    262 void GpuMessageFilter::BeginFrameSubscriptionInternal(
    263     linked_ptr<FrameSubscription> subscription) {
    264   if (!subscription->surface_id) {
    265     GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
    266     subscription->surface_id = surface_tracker->LookupSurfaceForRenderer(
    267         render_process_id_, subscription->route_id);
    268 
    269     // If the surface ID cannot be found this subscription is dropped.
    270     if (!subscription->surface_id)
    271       return;
    272   }
    273   frame_subscription_list_.push_back(subscription);
    274 
    275   // Frame subscriber is owned by this object, but it is shared with
    276   // GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing
    277   // and we do not get a signal. This object can also be destroyed independent
    278   // of GpuProcessHost. To ensure that GpuProcessHost does not reference a
    279   // deleted frame subscriber, a weak reference is shared.
    280   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    281   if (!host)
    282     return;
    283   host->BeginFrameSubscription(subscription->surface_id,
    284                                subscription->factory.GetWeakPtr());
    285 }
    286 
    287 void GpuMessageFilter::EndFrameSubscriptionInternal(
    288     linked_ptr<FrameSubscription> subscription) {
    289   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
    290 
    291   // An empty surface ID means subscription has never started in GpuProcessHost
    292   // so it is not necessary to end it.
    293   if (!host || !subscription->surface_id)
    294     return;
    295 
    296   // Note that GpuProcessHost here might not be the same one that frame
    297   // subscription has applied.
    298   host->EndFrameSubscription(subscription->surface_id);
    299 }
    300 
    301 }  // namespace content
    302