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/debug/trace_event.h" 11 #include "base/id_map.h" 12 #include "base/lazy_instance.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "content/browser/gpu/compositor_util.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/browser/renderer_host/render_widget_helper.h" 21 #include "content/browser/renderer_host/render_widget_host_view_base.h" 22 #include "content/common/gpu/gpu_messages.h" 23 #include "content/public/browser/browser_thread.h" 24 25 #if defined(OS_MACOSX) 26 #include "content/browser/compositor/browser_compositor_view_mac.h" 27 #endif 28 29 #if defined(USE_OZONE) 30 #include "ui/ozone/public/gpu_platform_support_host.h" 31 #include "ui/ozone/public/ozone_platform.h" 32 #endif 33 34 namespace content { 35 36 namespace { 37 38 // One of the linux specific headers defines this as a macro. 39 #ifdef DestroyAll 40 #undef DestroyAll 41 #endif 42 43 base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id = 44 LAZY_INSTANCE_INITIALIZER; 45 46 void SendOnIOThreadTask(int host_id, IPC::Message* msg) { 47 GpuProcessHost* host = GpuProcessHost::FromID(host_id); 48 if (host) 49 host->Send(msg); 50 else 51 delete msg; 52 } 53 54 class ScopedSendOnIOThread { 55 public: 56 ScopedSendOnIOThread(int host_id, IPC::Message* msg) 57 : host_id_(host_id), 58 msg_(msg), 59 cancelled_(false) { 60 } 61 62 ~ScopedSendOnIOThread() { 63 if (!cancelled_) { 64 BrowserThread::PostTask(BrowserThread::IO, 65 FROM_HERE, 66 base::Bind(&SendOnIOThreadTask, 67 host_id_, 68 msg_.release())); 69 } 70 } 71 72 void Cancel() { cancelled_ = true; } 73 74 private: 75 int host_id_; 76 scoped_ptr<IPC::Message> msg_; 77 bool cancelled_; 78 }; 79 80 RenderWidgetHostViewBase* GetRenderWidgetHostViewFromSurfaceID( 81 int surface_id) { 82 int render_process_id = 0; 83 int render_widget_id = 0; 84 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( 85 surface_id, &render_process_id, &render_widget_id)) 86 return NULL; 87 88 RenderWidgetHost* host = 89 RenderWidgetHost::FromID(render_process_id, render_widget_id); 90 return host ? static_cast<RenderWidgetHostViewBase*>(host->GetView()) : NULL; 91 } 92 93 } // namespace 94 95 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) { 96 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id); 97 if (ui_shim) 98 ui_shim->OnMessageReceived(msg); 99 } 100 101 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id) 102 : host_id_(host_id) { 103 g_hosts_by_id.Pointer()->AddWithID(this, host_id_); 104 #if defined(USE_OZONE) 105 ui::OzonePlatform::GetInstance() 106 ->GetGpuPlatformSupportHost() 107 ->OnChannelEstablished(host_id, this); 108 #endif 109 } 110 111 // static 112 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) { 113 DCHECK(!FromID(host_id)); 114 return new GpuProcessHostUIShim(host_id); 115 } 116 117 // static 118 void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) { 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 120 121 GpuDataManagerImpl::GetInstance()->AddLogMessage( 122 logging::LOG_ERROR, "GpuProcessHostUIShim", 123 message); 124 125 #if defined(USE_OZONE) 126 ui::OzonePlatform::GetInstance() 127 ->GetGpuPlatformSupportHost() 128 ->OnChannelDestroyed(host_id); 129 #endif 130 131 delete FromID(host_id); 132 } 133 134 // static 135 void GpuProcessHostUIShim::DestroyAll() { 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 137 while (!g_hosts_by_id.Pointer()->IsEmpty()) { 138 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer()); 139 delete it.GetCurrentValue(); 140 } 141 } 142 143 // static 144 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) { 145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 146 return g_hosts_by_id.Pointer()->Lookup(host_id); 147 } 148 149 // static 150 GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() { 151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 152 if (g_hosts_by_id.Pointer()->IsEmpty()) 153 return NULL; 154 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer()); 155 return it.GetCurrentValue(); 156 } 157 158 bool GpuProcessHostUIShim::Send(IPC::Message* msg) { 159 DCHECK(CalledOnValidThread()); 160 return BrowserThread::PostTask(BrowserThread::IO, 161 FROM_HERE, 162 base::Bind(&SendOnIOThreadTask, 163 host_id_, 164 msg)); 165 } 166 167 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) { 168 DCHECK(CalledOnValidThread()); 169 170 #if defined(USE_OZONE) 171 if (ui::OzonePlatform::GetInstance() 172 ->GetGpuPlatformSupportHost() 173 ->OnMessageReceived(message)) 174 return true; 175 #endif 176 177 if (message.routing_id() != MSG_ROUTING_CONTROL) 178 return false; 179 180 return OnControlMessageReceived(message); 181 } 182 183 void GpuProcessHostUIShim::SimulateRemoveAllContext() { 184 Send(new GpuMsg_Clean()); 185 } 186 187 void GpuProcessHostUIShim::SimulateCrash() { 188 Send(new GpuMsg_Crash()); 189 } 190 191 void GpuProcessHostUIShim::SimulateHang() { 192 Send(new GpuMsg_Hang()); 193 } 194 195 GpuProcessHostUIShim::~GpuProcessHostUIShim() { 196 DCHECK(CalledOnValidThread()); 197 g_hosts_by_id.Pointer()->Remove(host_id_); 198 } 199 200 bool GpuProcessHostUIShim::OnControlMessageReceived( 201 const IPC::Message& message) { 202 DCHECK(CalledOnValidThread()); 203 204 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message) 205 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage, 206 OnLogMessage) 207 208 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized, 209 OnAcceleratedSurfaceInitialized) 210 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, 211 OnAcceleratedSurfaceBuffersSwapped) 212 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer, 213 OnAcceleratedSurfacePostSubBuffer) 214 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend, 215 OnAcceleratedSurfaceSuspend) 216 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected, 217 OnGraphicsInfoCollected) 218 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease, 219 OnAcceleratedSurfaceRelease) 220 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats, 221 OnVideoMemoryUsageStatsReceived); 222 IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn) 223 224 IPC_MESSAGE_UNHANDLED_ERROR() 225 IPC_END_MESSAGE_MAP() 226 227 return true; 228 } 229 230 void GpuProcessHostUIShim::OnLogMessage( 231 int level, 232 const std::string& header, 233 const std::string& message) { 234 GpuDataManagerImpl::GetInstance()->AddLogMessage( 235 level, header, message); 236 } 237 238 void GpuProcessHostUIShim::OnGraphicsInfoCollected( 239 const gpu::GPUInfo& gpu_info) { 240 // OnGraphicsInfoCollected is sent back after the GPU process successfully 241 // initializes GL. 242 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected"); 243 244 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info); 245 } 246 247 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id, 248 int32 route_id) { 249 RenderWidgetHostViewBase* view = 250 GetRenderWidgetHostViewFromSurfaceID(surface_id); 251 if (!view) 252 return; 253 view->AcceleratedSurfaceInitialized(host_id_, route_id); 254 } 255 256 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( 257 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { 258 TRACE_EVENT0("renderer", 259 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped"); 260 if (!ui::LatencyInfo::Verify(params.latency_info, 261 "GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) 262 return; 263 264 #if defined(OS_MACOSX) 265 // On Mac with delegated rendering, accelerated surfaces are not necessarily 266 // associated with a RenderWidgetHostViewBase. 267 if (IsDelegatedRendererEnabled()) { 268 gfx::AcceleratedWidget native_widget = 269 content::GpuSurfaceTracker::Get()->AcquireNativeWidget( 270 params.surface_id); 271 BrowserCompositorViewMac::GotAcceleratedFrame( 272 native_widget, params.surface_handle, params.surface_id, 273 params.latency_info, params.size, params.scale_factor, 274 host_id_, params.route_id); 275 return; 276 } 277 #endif 278 279 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; 280 ack_params.mailbox = params.mailbox; 281 ack_params.sync_point = 0; 282 ScopedSendOnIOThread delayed_send( 283 host_id_, 284 new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 285 ack_params)); 286 287 RenderWidgetHostViewBase* view = GetRenderWidgetHostViewFromSurfaceID( 288 params.surface_id); 289 if (!view) 290 return; 291 292 delayed_send.Cancel(); 293 294 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params view_params = params; 295 296 RenderWidgetHostImpl* impl = 297 RenderWidgetHostImpl::From(view->GetRenderWidgetHost()); 298 for (size_t i = 0; i < view_params.latency_info.size(); i++) 299 impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]); 300 301 // View must send ACK message after next composite. 302 view->AcceleratedSurfaceBuffersSwapped(view_params, host_id_); 303 view->DidReceiveRendererFrame(); 304 } 305 306 void GpuProcessHostUIShim::OnFrameDrawn( 307 const std::vector<ui::LatencyInfo>& latency_info) { 308 if (!ui::LatencyInfo::Verify(latency_info, 309 "GpuProcessHostUIShim::OnFrameDrawn")) 310 return; 311 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info); 312 } 313 314 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer( 315 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) { 316 TRACE_EVENT0("renderer", 317 "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer"); 318 if (!ui::LatencyInfo::Verify(params.latency_info, 319 "GpuHostMsg_AcceleratedSurfacePostSubBuffer")) 320 return; 321 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; 322 ack_params.mailbox = params.mailbox; 323 ack_params.sync_point = 0; 324 ScopedSendOnIOThread delayed_send( 325 host_id_, 326 new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 327 ack_params)); 328 329 RenderWidgetHostViewBase* view = 330 GetRenderWidgetHostViewFromSurfaceID(params.surface_id); 331 if (!view) 332 return; 333 334 delayed_send.Cancel(); 335 336 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params view_params = params; 337 338 RenderWidgetHostImpl* impl = 339 RenderWidgetHostImpl::From(view->GetRenderWidgetHost()); 340 for (size_t i = 0; i < view_params.latency_info.size(); i++) 341 impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]); 342 343 // View must send ACK message after next composite. 344 view->AcceleratedSurfacePostSubBuffer(view_params, host_id_); 345 view->DidReceiveRendererFrame(); 346 } 347 348 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) { 349 TRACE_EVENT0("renderer", 350 "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend"); 351 352 RenderWidgetHostViewBase* 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 RenderWidgetHostViewBase* 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