3c2295657ccd2a808477298c74d84fb52a03d14d
[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       base::Bind(&GpuMessageFilter::EstablishChannelCallback,
138                  weak_ptr_factory_.GetWeakPtr(),
139                  base::Passed(&reply)));
140 }
141
142 void GpuMessageFilter::OnCreateViewCommandBuffer(
143     int32 surface_id,
144     const GPUCreateCommandBufferConfig& init_params,
145     int32 route_id,
146     IPC::Message* reply_ptr) {
147   DCHECK_CURRENTLY_ON(BrowserThread::IO);
148   scoped_ptr<IPC::Message> reply(reply_ptr);
149
150   GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
151   gfx::GLSurfaceHandle compositing_surface;
152
153   int renderer_id = 0;
154   int render_widget_id = 0;
155   bool result = surface_tracker->GetRenderWidgetIDForSurface(
156       surface_id, &renderer_id, &render_widget_id);
157   if (result && renderer_id == render_process_id_) {
158     compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);
159   } else {
160     DLOG(ERROR) << "Renderer " << render_process_id_
161                 << " tried to access a surface for renderer " << renderer_id;
162   }
163
164   if (compositing_surface.parent_client_id &&
165       !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
166     // For the renderer to fall back to software also.
167     compositing_surface = gfx::GLSurfaceHandle();
168   }
169
170   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
171   if (!host || compositing_surface.is_null()) {
172     // TODO(apatrick): Eventually, this IPC message will be routed to a
173     // GpuProcessStub with a particular routing ID. The error will be set if
174     // the GpuProcessStub with that routing ID is not in the MessageRouter.
175     reply->set_reply_error();
176     Send(reply.release());
177     return;
178   }
179
180   host->CreateViewCommandBuffer(
181       compositing_surface,
182       surface_id,
183       render_process_id_,
184       init_params,
185       route_id,
186       base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
187                  weak_ptr_factory_.GetWeakPtr(),
188                  base::Passed(&reply)));
189 }
190
191 void GpuMessageFilter::EstablishChannelCallback(
192     scoped_ptr<IPC::Message> reply,
193     const IPC::ChannelHandle& channel,
194     const gpu::GPUInfo& gpu_info) {
195   DCHECK_CURRENTLY_ON(BrowserThread::IO);
196
197   GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
198       reply.get(), render_process_id_, channel, gpu_info);
199   Send(reply.release());
200 }
201
202 void GpuMessageFilter::CreateCommandBufferCallback(
203     scoped_ptr<IPC::Message> reply, bool succeeded) {
204   DCHECK_CURRENTLY_ON(BrowserThread::IO);
205   GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), succeeded);
206   Send(reply.release());
207 }
208
209 void GpuMessageFilter::BeginAllFrameSubscriptions() {
210   FrameSubscriptionList frame_subscription_list;
211   frame_subscription_list.swap(frame_subscription_list_);
212   for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
213        it != frame_subscription_list.end(); ++it) {
214     BeginFrameSubscriptionInternal(*it);
215   }
216 }
217
218 void GpuMessageFilter::EndAllFrameSubscriptions() {
219   for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
220        it != frame_subscription_list_.end(); ++it) {
221     EndFrameSubscriptionInternal(*it);
222   }
223   frame_subscription_list_.clear();
224 }
225
226 void GpuMessageFilter::BeginFrameSubscriptionInternal(
227     linked_ptr<FrameSubscription> subscription) {
228   if (!subscription->surface_id) {
229     GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
230     subscription->surface_id = surface_tracker->LookupSurfaceForRenderer(
231         render_process_id_, subscription->route_id);
232
233     // If the surface ID cannot be found this subscription is dropped.
234     if (!subscription->surface_id)
235       return;
236   }
237   frame_subscription_list_.push_back(subscription);
238
239   // Frame subscriber is owned by this object, but it is shared with
240   // GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing
241   // and we do not get a signal. This object can also be destroyed independent
242   // of GpuProcessHost. To ensure that GpuProcessHost does not reference a
243   // deleted frame subscriber, a weak reference is shared.
244   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
245   if (!host)
246     return;
247   host->BeginFrameSubscription(subscription->surface_id,
248                                subscription->factory.GetWeakPtr());
249 }
250
251 void GpuMessageFilter::EndFrameSubscriptionInternal(
252     linked_ptr<FrameSubscription> subscription) {
253   GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
254
255   // An empty surface ID means subscription has never started in GpuProcessHost
256   // so it is not necessary to end it.
257   if (!host || !subscription->surface_id)
258     return;
259
260   // Note that GpuProcessHost here might not be the same one that frame
261   // subscription has applied.
262   host->EndFrameSubscription(subscription->surface_id);
263 }
264
265 }  // namespace content