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_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" 22 23 namespace content { 24 25 struct GpuMessageFilter::CreateViewCommandBufferRequest { 26 CreateViewCommandBufferRequest( 27 int32 surface_id, 28 const GPUCreateCommandBufferConfig& init_params, 29 scoped_ptr<IPC::Message> reply) 30 : surface_id(surface_id), 31 init_params(init_params), 32 reply(reply.Pass()) { 33 } 34 int32 surface_id; 35 GPUCreateCommandBufferConfig init_params; 36 scoped_ptr<IPC::Message> reply; 37 }; 38 39 struct GpuMessageFilter::FrameSubscription { 40 FrameSubscription( 41 int in_route_id, 42 scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber) 43 : route_id(in_route_id), 44 surface_id(0), 45 subscriber(in_subscriber.Pass()), 46 factory(subscriber.get()) { 47 } 48 49 int route_id; 50 int surface_id; 51 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber; 52 base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory; 53 }; 54 55 GpuMessageFilter::GpuMessageFilter(int render_process_id, 56 RenderWidgetHelper* render_widget_helper) 57 : BrowserMessageFilter(GpuMsgStart), 58 gpu_process_id_(0), 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); 63 } 64 65 GpuMessageFilter::~GpuMessageFilter() { 66 DCHECK_CURRENTLY_ON(BrowserThread::IO); 67 EndAllFrameSubscriptions(); 68 } 69 70 bool GpuMessageFilter::OnMessageReceived(const IPC::Message& message) { 71 bool handled = true; 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) 78 IPC_END_MESSAGE_MAP() 79 return handled; 80 } 81 82 void GpuMessageFilter::BeginFrameSubscription( 83 int route_id, 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); 89 } 90 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); 99 else 100 EndFrameSubscriptionInternal(*it); 101 } 102 } 103 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); 109 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_); 118 if (!host) { 119 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 120 cause_for_gpu_launch); 121 if (!host) { 122 reply->set_reply_error(); 123 Send(reply.release()); 124 return; 125 } 126 127 gpu_process_id_ = host->host_id(); 128 129 // Apply all frame subscriptions to the new GpuProcessHost. 130 BeginAllFrameSubscriptions(); 131 } 132 133 bool share_contexts = true; 134 host->EstablishGpuChannel( 135 render_process_id_, 136 share_contexts, 137 base::Bind(&GpuMessageFilter::EstablishChannelCallback, 138 weak_ptr_factory_.GetWeakPtr(), 139 base::Passed(&reply))); 140 } 141 142 void GpuMessageFilter::OnCreateViewCommandBuffer( 143 int32 surface_id, 144 const GPUCreateCommandBufferConfig& init_params, 145 int32 route_id, 146 IPC::Message* reply_ptr) { 147 DCHECK_CURRENTLY_ON(BrowserThread::IO); 148 scoped_ptr<IPC::Message> reply(reply_ptr); 149 150 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get(); 151 gfx::GLSurfaceHandle compositing_surface; 152 153 int renderer_id = 0; 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); 159 } else { 160 DLOG(ERROR) << "Renderer " << render_process_id_ 161 << " tried to access a surface for renderer " << renderer_id; 162 } 163 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(); 168 } 169 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()); 177 return; 178 } 179 180 host->CreateViewCommandBuffer( 181 compositing_surface, 182 surface_id, 183 render_process_id_, 184 init_params, 185 route_id, 186 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback, 187 weak_ptr_factory_.GetWeakPtr(), 188 base::Passed(&reply))); 189 } 190 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); 196 197 GpuHostMsg_EstablishGpuChannel::WriteReplyParams( 198 reply.get(), render_process_id_, channel, gpu_info); 199 Send(reply.release()); 200 } 201 202 void GpuMessageFilter::CreateCommandBufferCallback( 203 scoped_ptr<IPC::Message> reply, CreateCommandBufferResult result) { 204 DCHECK_CURRENTLY_ON(BrowserThread::IO); 205 GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), result); 206 Send(reply.release()); 207 } 208 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); 215 } 216 } 217 218 void GpuMessageFilter::EndAllFrameSubscriptions() { 219 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin(); 220 it != frame_subscription_list_.end(); ++it) { 221 EndFrameSubscriptionInternal(*it); 222 } 223 frame_subscription_list_.clear(); 224 } 225 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); 232 233 // If the surface ID cannot be found this subscription is dropped. 234 if (!subscription->surface_id) 235 return; 236 } 237 frame_subscription_list_.push_back(subscription); 238 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_); 245 if (!host) 246 return; 247 host->BeginFrameSubscription(subscription->surface_id, 248 subscription->factory.GetWeakPtr()); 249 } 250 251 void GpuMessageFilter::EndFrameSubscriptionInternal( 252 linked_ptr<FrameSubscription> subscription) { 253 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 254 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) 258 return; 259 260 // Note that GpuProcessHost here might not be the same one that frame 261 // subscription has applied. 262 host->EndFrameSubscription(subscription->surface_id); 263 } 264 265 } // namespace content 266