Upstream version 9.38.198.0
[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_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
23 namespace content {
24
25 struct 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
39 struct 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
55 GpuMessageFilter::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
65 GpuMessageFilter::~GpuMessageFilter() {
66   DCHECK_CURRENTLY_ON(BrowserThread::IO);
67   EndAllFrameSubscriptions();
68 }
69
70 bool 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
82 void 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
91 void 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
104 void 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
143 void 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
192 void 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
203 void 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
210 void 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
219 void 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
227 void 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
252 void 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