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_data_manager_impl_private.h"
15#include "content/browser/gpu/gpu_process_host.h"
16#include "content/browser/gpu/gpu_surface_tracker.h"
17#include "content/browser/renderer_host/render_widget_helper.h"
18#include "content/common/gpu/gpu_messages.h"
19#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
20#include "content/public/common/content_switches.h"
21#include "gpu/command_buffer/service/gpu_switches.h"
22
23namespace content {
24
25struct GpuMessageFilter::CreateViewCommandBufferRequest {
26  CreateViewCommandBufferRequest(
27      int32 surface_id,
28      const GPUCreateCommandBufferConfig& init_params,
29      scoped_ptr<IPC::Message> reply)
30      : surface_id(surface_id),
31        init_params(init_params),
32        reply(reply.Pass()) {
33  }
34  int32 surface_id;
35  GPUCreateCommandBufferConfig init_params;
36  scoped_ptr<IPC::Message> reply;
37};
38
39struct GpuMessageFilter::FrameSubscription {
40  FrameSubscription(
41      int in_route_id,
42      scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber)
43      : route_id(in_route_id),
44        surface_id(0),
45        subscriber(in_subscriber.Pass()),
46        factory(subscriber.get()) {
47  }
48
49  int route_id;
50  int surface_id;
51  scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber;
52  base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory;
53};
54
55GpuMessageFilter::GpuMessageFilter(int render_process_id,
56                                   RenderWidgetHelper* render_widget_helper)
57    : BrowserMessageFilter(GpuMsgStart),
58      gpu_process_id_(0),
59      render_process_id_(render_process_id),
60      render_widget_helper_(render_widget_helper),
61      weak_ptr_factory_(this) {
62  DCHECK_CURRENTLY_ON(BrowserThread::UI);
63}
64
65GpuMessageFilter::~GpuMessageFilter() {
66  DCHECK_CURRENTLY_ON(BrowserThread::IO);
67  EndAllFrameSubscriptions();
68}
69
70bool GpuMessageFilter::OnMessageReceived(const IPC::Message& message) {
71  bool handled = true;
72  IPC_BEGIN_MESSAGE_MAP(GpuMessageFilter, message)
73    IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_EstablishGpuChannel,
74                                    OnEstablishGpuChannel)
75    IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_CreateViewCommandBuffer,
76                                    OnCreateViewCommandBuffer)
77    IPC_MESSAGE_UNHANDLED(handled = false)
78  IPC_END_MESSAGE_MAP()
79  return handled;
80}
81
82void GpuMessageFilter::BeginFrameSubscription(
83    int route_id,
84    scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
85  DCHECK_CURRENTLY_ON(BrowserThread::IO);
86  linked_ptr<FrameSubscription> subscription(
87      new FrameSubscription(route_id, subscriber.Pass()));
88  BeginFrameSubscriptionInternal(subscription);
89}
90
91void GpuMessageFilter::EndFrameSubscription(int route_id) {
92  DCHECK_CURRENTLY_ON(BrowserThread::IO);
93  FrameSubscriptionList frame_subscription_list;
94  frame_subscription_list.swap(frame_subscription_list_);
95  for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
96       it != frame_subscription_list.end(); ++it) {
97    if ((*it)->route_id != route_id)
98      frame_subscription_list_.push_back(*it);
99    else
100      EndFrameSubscriptionInternal(*it);
101  }
102}
103
104void GpuMessageFilter::OnEstablishGpuChannel(
105    CauseForGpuLaunch cause_for_gpu_launch,
106    IPC::Message* reply_ptr) {
107  DCHECK_CURRENTLY_ON(BrowserThread::IO);
108  scoped_ptr<IPC::Message> reply(reply_ptr);
109
110  // TODO(apatrick): Eventually, this will return the route ID of a
111  // GpuProcessStub, from which the renderer process will create a
112  // GpuProcessProxy. The renderer will use the proxy for all subsequent
113  // communication with the GPU process. This means if the GPU process
114  // terminates, the renderer process will not find itself unknowingly sending
115  // IPCs to a newly launched GPU process. Also, I will rename this function
116  // to something like OnCreateGpuProcess.
117  GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
118  if (!host) {
119    host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
120                               cause_for_gpu_launch);
121    if (!host) {
122      reply->set_reply_error();
123      Send(reply.release());
124      return;
125    }
126
127    gpu_process_id_ = host->host_id();
128
129    // Apply all frame subscriptions to the new GpuProcessHost.
130    BeginAllFrameSubscriptions();
131  }
132
133  bool share_contexts = true;
134  host->EstablishGpuChannel(
135      render_process_id_,
136      share_contexts,
137      false,
138      base::Bind(&GpuMessageFilter::EstablishChannelCallback,
139                 weak_ptr_factory_.GetWeakPtr(),
140                 base::Passed(&reply)));
141}
142
143void GpuMessageFilter::OnCreateViewCommandBuffer(
144    int32 surface_id,
145    const GPUCreateCommandBufferConfig& init_params,
146    int32 route_id,
147    IPC::Message* reply_ptr) {
148  DCHECK_CURRENTLY_ON(BrowserThread::IO);
149  scoped_ptr<IPC::Message> reply(reply_ptr);
150
151  GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
152  gfx::GLSurfaceHandle compositing_surface;
153
154  int renderer_id = 0;
155  int render_widget_id = 0;
156  bool result = surface_tracker->GetRenderWidgetIDForSurface(
157      surface_id, &renderer_id, &render_widget_id);
158  if (result && renderer_id == render_process_id_) {
159    compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);
160  } else {
161    DLOG(ERROR) << "Renderer " << render_process_id_
162                << " tried to access a surface for renderer " << renderer_id;
163  }
164
165  if (compositing_surface.parent_client_id &&
166      !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
167    // For the renderer to fall back to software also.
168    compositing_surface = gfx::GLSurfaceHandle();
169  }
170
171  GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
172  if (!host || compositing_surface.is_null()) {
173    // TODO(apatrick): Eventually, this IPC message will be routed to a
174    // GpuProcessStub with a particular routing ID. The error will be set if
175    // the GpuProcessStub with that routing ID is not in the MessageRouter.
176    reply->set_reply_error();
177    Send(reply.release());
178    return;
179  }
180
181  host->CreateViewCommandBuffer(
182      compositing_surface,
183      surface_id,
184      render_process_id_,
185      init_params,
186      route_id,
187      base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
188                 weak_ptr_factory_.GetWeakPtr(),
189                 base::Passed(&reply)));
190}
191
192void GpuMessageFilter::EstablishChannelCallback(
193    scoped_ptr<IPC::Message> reply,
194    const IPC::ChannelHandle& channel,
195    const gpu::GPUInfo& gpu_info) {
196  DCHECK_CURRENTLY_ON(BrowserThread::IO);
197
198  GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
199      reply.get(), render_process_id_, channel, gpu_info);
200  Send(reply.release());
201}
202
203void GpuMessageFilter::CreateCommandBufferCallback(
204    scoped_ptr<IPC::Message> reply, CreateCommandBufferResult result) {
205  DCHECK_CURRENTLY_ON(BrowserThread::IO);
206  GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), result);
207  Send(reply.release());
208}
209
210void GpuMessageFilter::BeginAllFrameSubscriptions() {
211  FrameSubscriptionList frame_subscription_list;
212  frame_subscription_list.swap(frame_subscription_list_);
213  for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
214       it != frame_subscription_list.end(); ++it) {
215    BeginFrameSubscriptionInternal(*it);
216  }
217}
218
219void GpuMessageFilter::EndAllFrameSubscriptions() {
220  for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
221       it != frame_subscription_list_.end(); ++it) {
222    EndFrameSubscriptionInternal(*it);
223  }
224  frame_subscription_list_.clear();
225}
226
227void GpuMessageFilter::BeginFrameSubscriptionInternal(
228    linked_ptr<FrameSubscription> subscription) {
229  if (!subscription->surface_id) {
230    GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
231    subscription->surface_id = surface_tracker->LookupSurfaceForRenderer(
232        render_process_id_, subscription->route_id);
233
234    // If the surface ID cannot be found this subscription is dropped.
235    if (!subscription->surface_id)
236      return;
237  }
238  frame_subscription_list_.push_back(subscription);
239
240  // Frame subscriber is owned by this object, but it is shared with
241  // GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing
242  // and we do not get a signal. This object can also be destroyed independent
243  // of GpuProcessHost. To ensure that GpuProcessHost does not reference a
244  // deleted frame subscriber, a weak reference is shared.
245  GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
246  if (!host)
247    return;
248  host->BeginFrameSubscription(subscription->surface_id,
249                               subscription->factory.GetWeakPtr());
250}
251
252void GpuMessageFilter::EndFrameSubscriptionInternal(
253    linked_ptr<FrameSubscription> subscription) {
254  GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
255
256  // An empty surface ID means subscription has never started in GpuProcessHost
257  // so it is not necessary to end it.
258  if (!host || !subscription->surface_id)
259    return;
260
261  // Note that GpuProcessHost here might not be the same one that frame
262  // subscription has applied.
263  host->EndFrameSubscription(subscription->surface_id);
264}
265
266}  // namespace content
267