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_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" 21 22 namespace content { 23 24 struct GpuMessageFilter::CreateViewCommandBufferRequest { 25 CreateViewCommandBufferRequest( 26 int32 surface_id, 27 const GPUCreateCommandBufferConfig& init_params, 28 scoped_ptr<IPC::Message> reply) 29 : surface_id(surface_id), 30 init_params(init_params), 31 reply(reply.Pass()) { 32 } 33 int32 surface_id; 34 GPUCreateCommandBufferConfig init_params; 35 scoped_ptr<IPC::Message> reply; 36 }; 37 38 struct GpuMessageFilter::FrameSubscription { 39 FrameSubscription( 40 int in_route_id, 41 scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber) 42 : route_id(in_route_id), 43 surface_id(0), 44 subscriber(in_subscriber.Pass()), 45 factory(subscriber.get()) { 46 } 47 48 int route_id; 49 int surface_id; 50 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber; 51 base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory; 52 }; 53 54 GpuMessageFilter::GpuMessageFilter(int render_process_id, 55 RenderWidgetHelper* render_widget_helper) 56 : gpu_process_id_(0), 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)); 62 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; 67 #else 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; 75 #endif 76 } 77 78 GpuMessageFilter::~GpuMessageFilter() { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 80 EndAllFrameSubscriptions(); 81 } 82 83 bool GpuMessageFilter::OnMessageReceived( 84 const IPC::Message& message, 85 bool* message_was_ok) { 86 bool handled = true; 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() 94 return handled; 95 } 96 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); 106 } else { 107 linked_ptr<CreateViewCommandBufferRequest> request = *it; 108 OnCreateViewCommandBuffer(request->surface_id, 109 request->init_params, 110 request->reply.release()); 111 } 112 } 113 } 114 115 void GpuMessageFilter::BeginFrameSubscription( 116 int route_id, 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); 122 } 123 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); 132 else 133 EndFrameSubscriptionInternal(*it); 134 } 135 } 136 137 void GpuMessageFilter::OnEstablishGpuChannel( 138 CauseForGpuLaunch cause_for_gpu_launch, 139 IPC::Message* reply_ptr) { 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 141 scoped_ptr<IPC::Message> reply(reply_ptr); 142 143 // TODO(apatrick): Eventually, this will return the route ID of a 144 // GpuProcessStub, from which the renderer process will create a 145 // GpuProcessProxy. The renderer will use the proxy for all subsequent 146 // communication with the GPU process. This means if the GPU process 147 // terminates, the renderer process will not find itself unknowingly sending 148 // IPCs to a newly launched GPU process. Also, I will rename this function 149 // to something like OnCreateGpuProcess. 150 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 151 if (!host) { 152 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 153 cause_for_gpu_launch); 154 if (!host) { 155 reply->set_reply_error(); 156 Send(reply.release()); 157 return; 158 } 159 160 gpu_process_id_ = host->host_id(); 161 162 // Apply all frame subscriptions to the new GpuProcessHost. 163 BeginAllFrameSubscriptions(); 164 } 165 166 host->EstablishGpuChannel( 167 render_process_id_, 168 share_contexts_, 169 base::Bind(&GpuMessageFilter::EstablishChannelCallback, 170 weak_ptr_factory_.GetWeakPtr(), 171 base::Passed(&reply))); 172 } 173 174 void GpuMessageFilter::OnCreateViewCommandBuffer( 175 int32 surface_id, 176 const GPUCreateCommandBufferConfig& init_params, 177 IPC::Message* reply_ptr) { 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 179 scoped_ptr<IPC::Message> reply(reply_ptr); 180 181 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get(); 182 gfx::GLSurfaceHandle compositing_surface; 183 184 int renderer_id = 0; 185 int render_widget_id = 0; 186 bool result = surface_tracker->GetRenderWidgetIDForSurface( 187 surface_id, &renderer_id, &render_widget_id); 188 if (result && renderer_id == render_process_id_) { 189 compositing_surface = surface_tracker->GetSurfaceHandle(surface_id); 190 } else { 191 DLOG(ERROR) << "Renderer " << render_process_id_ 192 << " tried to access a surface for renderer " << renderer_id; 193 } 194 195 if (compositing_surface.parent_gpu_process_id && 196 compositing_surface.parent_gpu_process_id != gpu_process_id_) { 197 // If the current handle for the surface is using a different (older) gpu 198 // host, it means the GPU process died and we need to wait until the UI 199 // re-allocates the surface in the new process. 200 linked_ptr<CreateViewCommandBufferRequest> request( 201 new CreateViewCommandBufferRequest( 202 surface_id, init_params, reply.Pass())); 203 pending_requests_.push_back(request); 204 return; 205 } 206 207 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 208 if (!host || compositing_surface.is_null()) { 209 // TODO(apatrick): Eventually, this IPC message will be routed to a 210 // GpuProcessStub with a particular routing ID. The error will be set if 211 // the GpuProcessStub with that routing ID is not in the MessageRouter. 212 reply->set_reply_error(); 213 Send(reply.release()); 214 return; 215 } 216 217 host->CreateViewCommandBuffer( 218 compositing_surface, 219 surface_id, 220 render_process_id_, 221 init_params, 222 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback, 223 weak_ptr_factory_.GetWeakPtr(), 224 base::Passed(&reply))); 225 } 226 227 void GpuMessageFilter::EstablishChannelCallback( 228 scoped_ptr<IPC::Message> reply, 229 const IPC::ChannelHandle& channel, 230 const gpu::GPUInfo& gpu_info) { 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 232 233 GpuHostMsg_EstablishGpuChannel::WriteReplyParams( 234 reply.get(), render_process_id_, channel, gpu_info); 235 Send(reply.release()); 236 } 237 238 void GpuMessageFilter::CreateCommandBufferCallback( 239 scoped_ptr<IPC::Message> reply, int32 route_id) { 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 241 GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), route_id); 242 Send(reply.release()); 243 } 244 245 void GpuMessageFilter::BeginAllFrameSubscriptions() { 246 FrameSubscriptionList frame_subscription_list; 247 frame_subscription_list.swap(frame_subscription_list_); 248 for (FrameSubscriptionList::iterator it = frame_subscription_list.begin(); 249 it != frame_subscription_list.end(); ++it) { 250 BeginFrameSubscriptionInternal(*it); 251 } 252 } 253 254 void GpuMessageFilter::EndAllFrameSubscriptions() { 255 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin(); 256 it != frame_subscription_list_.end(); ++it) { 257 EndFrameSubscriptionInternal(*it); 258 } 259 frame_subscription_list_.clear(); 260 } 261 262 void GpuMessageFilter::BeginFrameSubscriptionInternal( 263 linked_ptr<FrameSubscription> subscription) { 264 if (!subscription->surface_id) { 265 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get(); 266 subscription->surface_id = surface_tracker->LookupSurfaceForRenderer( 267 render_process_id_, subscription->route_id); 268 269 // If the surface ID cannot be found this subscription is dropped. 270 if (!subscription->surface_id) 271 return; 272 } 273 frame_subscription_list_.push_back(subscription); 274 275 // Frame subscriber is owned by this object, but it is shared with 276 // GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing 277 // and we do not get a signal. This object can also be destroyed independent 278 // of GpuProcessHost. To ensure that GpuProcessHost does not reference a 279 // deleted frame subscriber, a weak reference is shared. 280 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 281 if (!host) 282 return; 283 host->BeginFrameSubscription(subscription->surface_id, 284 subscription->factory.GetWeakPtr()); 285 } 286 287 void GpuMessageFilter::EndFrameSubscriptionInternal( 288 linked_ptr<FrameSubscription> subscription) { 289 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 290 291 // An empty surface ID means subscription has never started in GpuProcessHost 292 // so it is not necessary to end it. 293 if (!host || !subscription->surface_id) 294 return; 295 296 // Note that GpuProcessHost here might not be the same one that frame 297 // subscription has applied. 298 host->EndFrameSubscription(subscription->surface_id); 299 } 300 301 } // namespace content 302