- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / gpu_message_filter.cc
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