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_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"
24 struct GpuMessageFilter::CreateViewCommandBufferRequest {
25 CreateViewCommandBufferRequest(
27 const GPUCreateCommandBufferConfig& init_params_,
29 : surface_id(surface_id_),
30 init_params(init_params_),
34 GPUCreateCommandBufferConfig init_params;
38 struct GpuMessageFilter::FrameSubscription {
41 scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber)
42 : route_id(in_route_id),
44 subscriber(in_subscriber.Pass()),
45 factory(subscriber.get()) {
50 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber;
51 base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory;
54 GpuMessageFilter::GpuMessageFilter(int render_process_id,
55 RenderWidgetHelper* render_widget_helper)
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));
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;
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;
78 GpuMessageFilter::~GpuMessageFilter() {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
80 EndAllFrameSubscriptions();
83 bool GpuMessageFilter::OnMessageReceived(
84 const IPC::Message& message,
85 bool* message_was_ok) {
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()
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);
107 linked_ptr<CreateViewCommandBufferRequest> request = *it;
108 OnCreateViewCommandBuffer(request->surface_id,
109 request->init_params,
115 void GpuMessageFilter::BeginFrameSubscription(
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);
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);
133 EndFrameSubscriptionInternal(*it);
137 void GpuMessageFilter::OnEstablishGpuChannel(
138 CauseForGpuLaunch cause_for_gpu_launch,
139 IPC::Message* reply) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
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_);
151 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
152 cause_for_gpu_launch);
154 reply->set_reply_error();
159 gpu_process_id_ = host->host_id();
161 // Apply all frame subscriptions to the new GpuProcessHost.
162 BeginAllFrameSubscriptions();
165 host->EstablishGpuChannel(
168 base::Bind(&GpuMessageFilter::EstablishChannelCallback,
169 weak_ptr_factory_.GetWeakPtr(),
173 void GpuMessageFilter::OnCreateViewCommandBuffer(
175 const GPUCreateCommandBufferConfig& init_params,
176 IPC::Message* reply) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
179 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
180 gfx::GLSurfaceHandle compositing_surface;
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);
189 DLOG(ERROR) << "Renderer " << render_process_id_
190 << " tried to access a surface for renderer " << renderer_id;
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);
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();
214 host->CreateViewCommandBuffer(
219 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
220 weak_ptr_factory_.GetWeakPtr(),
224 void GpuMessageFilter::EstablishChannelCallback(
226 const IPC::ChannelHandle& channel,
227 const gpu::GPUInfo& gpu_info) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
230 GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
231 reply, render_process_id_, channel, gpu_info);
235 void GpuMessageFilter::CreateCommandBufferCallback(
236 IPC::Message* reply, int32 route_id) {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
238 GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply, route_id);
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);
251 void GpuMessageFilter::EndAllFrameSubscriptions() {
252 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
253 it != frame_subscription_list_.end(); ++it) {
254 EndFrameSubscriptionInternal(*it);
256 frame_subscription_list_.clear();
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);
266 // If the surface ID cannot be found this subscription is dropped.
267 if (!subscription->surface_id)
270 frame_subscription_list_.push_back(subscription);
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_);
280 host->BeginFrameSubscription(subscription->surface_id,
281 subscription->factory.GetWeakPtr());
284 void GpuMessageFilter::EndFrameSubscriptionInternal(
285 linked_ptr<FrameSubscription> subscription) {
286 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
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)
293 // Note that GpuProcessHost here might not be the same one that frame
294 // subscription has applied.
295 host->EndFrameSubscription(subscription->surface_id);
298 } // namespace content