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 23namespace content { 24 25struct 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 39struct 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 55GpuMessageFilter::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 65GpuMessageFilter::~GpuMessageFilter() { 66 DCHECK_CURRENTLY_ON(BrowserThread::IO); 67 EndAllFrameSubscriptions(); 68} 69 70bool 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 82void 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 91void 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 104void 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 false, 138 base::Bind(&GpuMessageFilter::EstablishChannelCallback, 139 weak_ptr_factory_.GetWeakPtr(), 140 base::Passed(&reply))); 141} 142 143void GpuMessageFilter::OnCreateViewCommandBuffer( 144 int32 surface_id, 145 const GPUCreateCommandBufferConfig& init_params, 146 int32 route_id, 147 IPC::Message* reply_ptr) { 148 DCHECK_CURRENTLY_ON(BrowserThread::IO); 149 scoped_ptr<IPC::Message> reply(reply_ptr); 150 151 GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get(); 152 gfx::GLSurfaceHandle compositing_surface; 153 154 int renderer_id = 0; 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); 160 } else { 161 DLOG(ERROR) << "Renderer " << render_process_id_ 162 << " tried to access a surface for renderer " << renderer_id; 163 } 164 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(); 169 } 170 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()); 178 return; 179 } 180 181 host->CreateViewCommandBuffer( 182 compositing_surface, 183 surface_id, 184 render_process_id_, 185 init_params, 186 route_id, 187 base::Bind(&GpuMessageFilter::CreateCommandBufferCallback, 188 weak_ptr_factory_.GetWeakPtr(), 189 base::Passed(&reply))); 190} 191 192void 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); 197 198 GpuHostMsg_EstablishGpuChannel::WriteReplyParams( 199 reply.get(), render_process_id_, channel, gpu_info); 200 Send(reply.release()); 201} 202 203void 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()); 208} 209 210void 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); 216 } 217} 218 219void GpuMessageFilter::EndAllFrameSubscriptions() { 220 for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin(); 221 it != frame_subscription_list_.end(); ++it) { 222 EndFrameSubscriptionInternal(*it); 223 } 224 frame_subscription_list_.clear(); 225} 226 227void 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); 233 234 // If the surface ID cannot be found this subscription is dropped. 235 if (!subscription->surface_id) 236 return; 237 } 238 frame_subscription_list_.push_back(subscription); 239 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_); 246 if (!host) 247 return; 248 host->BeginFrameSubscription(subscription->surface_id, 249 subscription->factory.GetWeakPtr()); 250} 251 252void GpuMessageFilter::EndFrameSubscriptionInternal( 253 linked_ptr<FrameSubscription> subscription) { 254 GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_); 255 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) 259 return; 260 261 // Note that GpuProcessHost here might not be the same one that frame 262 // subscription has applied. 263 host->EndFrameSubscription(subscription->surface_id); 264} 265 266} // namespace content 267