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 IPC::Message* reply_) 29 : surface_id(surface_id_), 30 init_params(init_params_), 31 reply(reply_) { 32 } 33 int32 surface_id; 34 GPUCreateCommandBufferConfig init_params; 35 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); 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) { 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 141 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_); 150 if (!host) { 151 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 152 cause_for_gpu_launch); 153 if (!host) { 154 reply->set_reply_error(); 155 Send(reply); 156 return; 157 } 158 159 gpu_process_id_ = host->host_id(); 160 161 // Apply all frame subscriptions to the new GpuProcessHost. 162 BeginAllFrameSubscriptions(); 163 } 164 165 host->EstablishGpuChannel( 166 render_process_id_, 167 share_contexts_, 168 base::Bind(&GpuMessageFilter::EstablishChannelCallback, 169 weak_ptr_factory_.GetWeakPtr(), 170 reply)); 171 } 172 173 void GpuMessageFilter::OnCreateViewCommandBuffer( 174 int32 surface_id, 175 const GPUCreateCommandBufferConfig& init_params, 176 IPC::Message* reply) { 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 178 179 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get(); 180 gfx::GLSurfaceHandle compositing_surface; 181 182 int renderer_id = 0; 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); 188 } else { 189 DLOG(ERROR) << "Renderer " << render_process_id_ 190 << " tried to access a surface for renderer " << renderer_id; 191 } 192 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); 201 return; 202 } 203 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(); 210 Send(reply); 211 return; 212 } 213 214 host->CreateViewCommandBuffer( 215 compositing_surface, 216 surface_id, 217 render_process_id_, 218 init_params, 219 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback, 220 weak_ptr_factory_.GetWeakPtr(), 221 reply)); 222 } 223 224 void GpuMessageFilter::EstablishChannelCallback( 225 IPC::Message* reply, 226 const IPC::ChannelHandle& channel, 227 const gpu::GPUInfo& gpu_info) { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 229 230 GpuHostMsg_EstablishGpuChannel::WriteReplyParams( 231 reply, render_process_id_, channel, gpu_info); 232 Send(reply); 233 } 234 235 void GpuMessageFilter::CreateCommandBufferCallback( 236 IPC::Message* reply, int32 route_id) { 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 238 GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply, route_id); 239 Send(reply); 240 } 241 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); 248 } 249 } 250 251 void GpuMessageFilter::EndAllFrameSubscriptions() { 252 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin(); 253 it != frame_subscription_list_.end(); ++it) { 254 EndFrameSubscriptionInternal(*it); 255 } 256 frame_subscription_list_.clear(); 257 } 258 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); 265 266 // If the surface ID cannot be found this subscription is dropped. 267 if (!subscription->surface_id) 268 return; 269 } 270 frame_subscription_list_.push_back(subscription); 271 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_); 278 if (!host) 279 return; 280 host->BeginFrameSubscription(subscription->surface_id, 281 subscription->factory.GetWeakPtr()); 282 } 283 284 void GpuMessageFilter::EndFrameSubscriptionInternal( 285 linked_ptr<FrameSubscription> subscription) { 286 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 287 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) 291 return; 292 293 // Note that GpuProcessHost here might not be the same one that frame 294 // subscription has applied. 295 host->EndFrameSubscription(subscription->surface_id); 296 } 297 298 } // namespace content 299