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 #include "content/browser/gpu/gpu_process_host_ui_shim.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/debug/trace_event.h" 12 #include "base/id_map.h" 13 #include "base/lazy_instance.h" 14 #include "base/strings/string_number_conversions.h" 15 #include "content/browser/gpu/gpu_data_manager_impl.h" 16 #include "content/browser/gpu/gpu_process_host.h" 17 #include "content/browser/gpu/gpu_surface_tracker.h" 18 #include "content/browser/renderer_host/render_process_host_impl.h" 19 #include "content/browser/renderer_host/render_view_host_impl.h" 20 #include "content/common/gpu/gpu_messages.h" 21 #include "content/port/browser/render_widget_host_view_port.h" 22 #include "content/public/browser/browser_thread.h" 23 #include "ui/gl/gl_switches.h" 24 25 // From gl2/gl2ext.h. 26 #ifndef GL_MAILBOX_SIZE_CHROMIUM 27 #define GL_MAILBOX_SIZE_CHROMIUM 64 28 #endif 29 30 namespace content { 31 32 namespace { 33 34 // One of the linux specific headers defines this as a macro. 35 #ifdef DestroyAll 36 #undef DestroyAll 37 #endif 38 39 base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id = 40 LAZY_INSTANCE_INITIALIZER; 41 42 void SendOnIOThreadTask(int host_id, IPC::Message* msg) { 43 GpuProcessHost* host = GpuProcessHost::FromID(host_id); 44 if (host) 45 host->Send(msg); 46 else 47 delete msg; 48 } 49 50 class ScopedSendOnIOThread { 51 public: 52 ScopedSendOnIOThread(int host_id, IPC::Message* msg) 53 : host_id_(host_id), 54 msg_(msg), 55 cancelled_(false) { 56 } 57 58 ~ScopedSendOnIOThread() { 59 if (!cancelled_) { 60 BrowserThread::PostTask(BrowserThread::IO, 61 FROM_HERE, 62 base::Bind(&SendOnIOThreadTask, 63 host_id_, 64 msg_.release())); 65 } 66 } 67 68 void Cancel() { cancelled_ = true; } 69 70 private: 71 int host_id_; 72 scoped_ptr<IPC::Message> msg_; 73 bool cancelled_; 74 }; 75 76 RenderWidgetHostViewPort* GetRenderWidgetHostViewFromSurfaceID( 77 int surface_id) { 78 int render_process_id = 0; 79 int render_widget_id = 0; 80 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( 81 surface_id, &render_process_id, &render_widget_id)) 82 return NULL; 83 84 RenderWidgetHost* host = 85 RenderWidgetHost::FromID(render_process_id, render_widget_id); 86 return host ? RenderWidgetHostViewPort::FromRWHV(host->GetView()) : NULL; 87 } 88 89 } // namespace 90 91 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) { 92 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id); 93 if (ui_shim) 94 ui_shim->OnMessageReceived(msg); 95 } 96 97 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id) 98 : host_id_(host_id) { 99 g_hosts_by_id.Pointer()->AddWithID(this, host_id_); 100 } 101 102 // static 103 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) { 104 DCHECK(!FromID(host_id)); 105 return new GpuProcessHostUIShim(host_id); 106 } 107 108 // static 109 void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) { 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 111 112 GpuDataManagerImpl::GetInstance()->AddLogMessage( 113 logging::LOG_ERROR, "GpuProcessHostUIShim", 114 message); 115 116 delete FromID(host_id); 117 } 118 119 // static 120 void GpuProcessHostUIShim::DestroyAll() { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 while (!g_hosts_by_id.Pointer()->IsEmpty()) { 123 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer()); 124 delete it.GetCurrentValue(); 125 } 126 } 127 128 // static 129 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) { 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 131 return g_hosts_by_id.Pointer()->Lookup(host_id); 132 } 133 134 // static 135 GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() { 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 137 if (g_hosts_by_id.Pointer()->IsEmpty()) 138 return NULL; 139 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer()); 140 return it.GetCurrentValue(); 141 } 142 143 bool GpuProcessHostUIShim::Send(IPC::Message* msg) { 144 DCHECK(CalledOnValidThread()); 145 return BrowserThread::PostTask(BrowserThread::IO, 146 FROM_HERE, 147 base::Bind(&SendOnIOThreadTask, 148 host_id_, 149 msg)); 150 } 151 152 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) { 153 DCHECK(CalledOnValidThread()); 154 155 if (message.routing_id() != MSG_ROUTING_CONTROL) 156 return false; 157 158 return OnControlMessageReceived(message); 159 } 160 161 void GpuProcessHostUIShim::SimulateRemoveAllContext() { 162 Send(new GpuMsg_Clean()); 163 } 164 165 void GpuProcessHostUIShim::SimulateCrash() { 166 Send(new GpuMsg_Crash()); 167 } 168 169 void GpuProcessHostUIShim::SimulateHang() { 170 Send(new GpuMsg_Hang()); 171 } 172 173 GpuProcessHostUIShim::~GpuProcessHostUIShim() { 174 DCHECK(CalledOnValidThread()); 175 g_hosts_by_id.Pointer()->Remove(host_id_); 176 } 177 178 bool GpuProcessHostUIShim::OnControlMessageReceived( 179 const IPC::Message& message) { 180 DCHECK(CalledOnValidThread()); 181 182 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message) 183 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage, 184 OnLogMessage) 185 186 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized, 187 OnAcceleratedSurfaceInitialized) 188 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, 189 OnAcceleratedSurfaceBuffersSwapped) 190 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer, 191 OnAcceleratedSurfacePostSubBuffer) 192 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend, 193 OnAcceleratedSurfaceSuspend) 194 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected, 195 OnGraphicsInfoCollected) 196 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease, 197 OnAcceleratedSurfaceRelease) 198 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats, 199 OnVideoMemoryUsageStatsReceived); 200 IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters, 201 OnUpdateVSyncParameters) 202 IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn) 203 204 IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView, OnResizeView) 205 206 IPC_MESSAGE_UNHANDLED_ERROR() 207 IPC_END_MESSAGE_MAP() 208 209 return true; 210 } 211 212 void GpuProcessHostUIShim::OnUpdateVSyncParameters(int surface_id, 213 base::TimeTicks timebase, 214 base::TimeDelta interval) { 215 216 int render_process_id = 0; 217 int render_widget_id = 0; 218 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( 219 surface_id, &render_process_id, &render_widget_id)) { 220 return; 221 } 222 RenderWidgetHost* rwh = 223 RenderWidgetHost::FromID(render_process_id, render_widget_id); 224 if (!rwh) 225 return; 226 RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval); 227 } 228 229 void GpuProcessHostUIShim::OnLogMessage( 230 int level, 231 const std::string& header, 232 const std::string& message) { 233 GpuDataManagerImpl::GetInstance()->AddLogMessage( 234 level, header, message); 235 } 236 237 void GpuProcessHostUIShim::OnGraphicsInfoCollected( 238 const gpu::GPUInfo& gpu_info) { 239 // OnGraphicsInfoCollected is sent back after the GPU process successfully 240 // initializes GL. 241 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected"); 242 243 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info); 244 } 245 246 void GpuProcessHostUIShim::OnResizeView(int32 surface_id, 247 int32 route_id, 248 gfx::Size size) { 249 // Always respond even if the window no longer exists. The GPU process cannot 250 // make progress on the resizing command buffer until it receives the 251 // response. 252 ScopedSendOnIOThread delayed_send( 253 host_id_, 254 new AcceleratedSurfaceMsg_ResizeViewACK(route_id)); 255 256 RenderWidgetHostViewPort* view = 257 GetRenderWidgetHostViewFromSurfaceID(surface_id); 258 if (!view) 259 return; 260 261 view->ResizeCompositingSurface(size); 262 } 263 264 static base::TimeDelta GetSwapDelay() { 265 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 266 int delay = 0; 267 if (cmd_line->HasSwitch(switches::kGpuSwapDelay)) { 268 base::StringToInt(cmd_line->GetSwitchValueNative( 269 switches::kGpuSwapDelay).c_str(), &delay); 270 } 271 return base::TimeDelta::FromMilliseconds(delay); 272 } 273 274 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id, 275 int32 route_id) { 276 RenderWidgetHostViewPort* view = 277 GetRenderWidgetHostViewFromSurfaceID(surface_id); 278 if (!view) 279 return; 280 view->AcceleratedSurfaceInitialized(host_id_, route_id); 281 } 282 283 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( 284 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { 285 TRACE_EVENT0("renderer", 286 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped"); 287 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; 288 ack_params.mailbox_name = params.mailbox_name; 289 ack_params.sync_point = 0; 290 ScopedSendOnIOThread delayed_send( 291 host_id_, 292 new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 293 ack_params)); 294 295 if (!params.mailbox_name.empty() && 296 params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM) 297 return; 298 299 RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID( 300 params.surface_id); 301 if (!view) 302 return; 303 304 delayed_send.Cancel(); 305 306 static const base::TimeDelta swap_delay = GetSwapDelay(); 307 if (swap_delay.ToInternalValue()) 308 base::PlatformThread::Sleep(swap_delay); 309 310 // View must send ACK message after next composite. 311 view->AcceleratedSurfaceBuffersSwapped(params, host_id_); 312 view->DidReceiveRendererFrame(); 313 } 314 315 void GpuProcessHostUIShim::OnFrameDrawn(const ui::LatencyInfo& latency_info) { 316 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info); 317 } 318 319 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer( 320 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) { 321 TRACE_EVENT0("renderer", 322 "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer"); 323 324 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; 325 ack_params.mailbox_name = params.mailbox_name; 326 ack_params.sync_point = 0; 327 ScopedSendOnIOThread delayed_send( 328 host_id_, 329 new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 330 ack_params)); 331 332 if (!params.mailbox_name.empty() && 333 params.mailbox_name.length() != GL_MAILBOX_SIZE_CHROMIUM) 334 return; 335 336 RenderWidgetHostViewPort* view = 337 GetRenderWidgetHostViewFromSurfaceID(params.surface_id); 338 if (!view) 339 return; 340 341 delayed_send.Cancel(); 342 343 // View must send ACK message after next composite. 344 view->AcceleratedSurfacePostSubBuffer(params, host_id_); 345 view->DidReceiveRendererFrame(); 346 } 347 348 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) { 349 TRACE_EVENT0("renderer", 350 "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend"); 351 352 RenderWidgetHostViewPort* view = 353 GetRenderWidgetHostViewFromSurfaceID(surface_id); 354 if (!view) 355 return; 356 357 view->AcceleratedSurfaceSuspend(); 358 } 359 360 void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease( 361 const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) { 362 RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID( 363 params.surface_id); 364 if (!view) 365 return; 366 view->AcceleratedSurfaceRelease(); 367 } 368 369 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived( 370 const GPUVideoMemoryUsageStats& video_memory_usage_stats) { 371 GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats( 372 video_memory_usage_stats); 373 } 374 375 } // namespace content 376