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