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(
138 base::Bind(&GpuMessageFilter::EstablishChannelCallback,
139 weak_ptr_factory_.GetWeakPtr(),
140 base::Passed(&reply)));
143 void GpuMessageFilter::OnCreateViewCommandBuffer(
145 const GPUCreateCommandBufferConfig& init_params,
147 IPC::Message* reply_ptr) {
148 DCHECK_CURRENTLY_ON(BrowserThread::IO);
149 scoped_ptr<IPC::Message> reply(reply_ptr);
151 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
152 gfx::GLSurfaceHandle compositing_surface;
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);
161 DLOG(ERROR) << "Renderer " << render_process_id_
162 << " tried to access a surface for renderer " << renderer_id;
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();
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());
181 host->CreateViewCommandBuffer(
187 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
188 weak_ptr_factory_.GetWeakPtr(),
189 base::Passed(&reply)));
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);
198 GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
199 reply.get(), render_process_id_, channel, gpu_info);
200 Send(reply.release());
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());
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);
219 void GpuMessageFilter::EndAllFrameSubscriptions() {
220 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
221 it != frame_subscription_list_.end(); ++it) {
222 EndFrameSubscriptionInternal(*it);
224 frame_subscription_list_.clear();
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);
234 // If the surface ID cannot be found this subscription is dropped.
235 if (!subscription->surface_id)
238 frame_subscription_list_.push_back(subscription);
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_);
248 host->BeginFrameSubscription(subscription->surface_id,
249 subscription->factory.GetWeakPtr());
252 void GpuMessageFilter::EndFrameSubscriptionInternal(
253 linked_ptr<FrameSubscription> subscription) {
254 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
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)
261 // Note that GpuProcessHost here might not be the same one that frame
262 // subscription has applied.
263 host->EndFrameSubscription(subscription->surface_id);
266 } // namespace content