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.
9 #include "content/browser/renderer_host/gpu_message_filter.h"
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"
25 struct GpuMessageFilter::CreateViewCommandBufferRequest {
26 CreateViewCommandBufferRequest(
28 const GPUCreateCommandBufferConfig& init_params,
29 scoped_ptr<IPC::Message> reply)
30 : surface_id(surface_id),
31 init_params(init_params),
35 GPUCreateCommandBufferConfig init_params;
36 scoped_ptr<IPC::Message> reply;
39 struct GpuMessageFilter::FrameSubscription {
42 scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber)
43 : route_id(in_route_id),
45 subscriber(in_subscriber.Pass()),
46 factory(subscriber.get()) {
51 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber;
52 base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory;
55 GpuMessageFilter::GpuMessageFilter(int render_process_id,
56 RenderWidgetHelper* render_widget_helper)
57 : BrowserMessageFilter(GpuMsgStart),
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);
65 GpuMessageFilter::~GpuMessageFilter() {
66 DCHECK_CURRENTLY_ON(BrowserThread::IO);
67 EndAllFrameSubscriptions();
70 bool GpuMessageFilter::OnMessageReceived(const IPC::Message& message) {
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)
82 void GpuMessageFilter::BeginFrameSubscription(
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);
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);
100 EndFrameSubscriptionInternal(*it);
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);
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_);
119 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
120 cause_for_gpu_launch);
122 reply->set_reply_error();
123 Send(reply.release());
127 gpu_process_id_ = host->host_id();
129 // Apply all frame subscriptions to the new GpuProcessHost.
130 BeginAllFrameSubscriptions();
133 bool share_contexts = true;
134 host->EstablishGpuChannel(
137 base::Bind(&GpuMessageFilter::EstablishChannelCallback,
138 weak_ptr_factory_.GetWeakPtr(),
139 base::Passed(&reply)));
142 void GpuMessageFilter::OnCreateViewCommandBuffer(
144 const GPUCreateCommandBufferConfig& init_params,
146 IPC::Message* reply_ptr) {
147 DCHECK_CURRENTLY_ON(BrowserThread::IO);
148 scoped_ptr<IPC::Message> reply(reply_ptr);
150 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
151 gfx::GLSurfaceHandle compositing_surface;
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);
160 DLOG(ERROR) << "Renderer " << render_process_id_
161 << " tried to access a surface for renderer " << renderer_id;
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();
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());
180 host->CreateViewCommandBuffer(
186 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
187 weak_ptr_factory_.GetWeakPtr(),
188 base::Passed(&reply)));
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);
197 GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
198 reply.get(), render_process_id_, channel, gpu_info);
199 Send(reply.release());
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());
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);
218 void GpuMessageFilter::EndAllFrameSubscriptions() {
219 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
220 it != frame_subscription_list_.end(); ++it) {
221 EndFrameSubscriptionInternal(*it);
223 frame_subscription_list_.clear();
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);
233 // If the surface ID cannot be found this subscription is dropped.
234 if (!subscription->surface_id)
237 frame_subscription_list_.push_back(subscription);
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_);
247 host->BeginFrameSubscription(subscription->surface_id,
248 subscription->factory.GetWeakPtr());
251 void GpuMessageFilter::EndFrameSubscriptionInternal(
252 linked_ptr<FrameSubscription> subscription) {
253 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
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)
260 // Note that GpuProcessHost here might not be the same one that frame
261 // subscription has applied.
262 host->EndFrameSubscription(subscription->surface_id);
265 } // namespace content