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.h" 6 7 #include "base/base64.h" 8 #include "base/base_switches.h" 9 #include "base/basictypes.h" 10 #include "base/bind.h" 11 #include "base/callback_helpers.h" 12 #include "base/command_line.h" 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/metrics/histogram.h" 17 #include "base/sha1.h" 18 #include "base/threading/thread.h" 19 #include "content/browser/browser_child_process_host_impl.h" 20 #include "content/browser/gpu/gpu_data_manager_impl.h" 21 #include "content/browser/gpu/gpu_process_host_ui_shim.h" 22 #include "content/browser/gpu/shader_disk_cache.h" 23 #include "content/browser/renderer_host/render_widget_helper.h" 24 #include "content/browser/renderer_host/render_widget_host_impl.h" 25 #include "content/common/child_process_host_impl.h" 26 #include "content/common/gpu/gpu_messages.h" 27 #include "content/common/view_messages.h" 28 #include "content/port/browser/render_widget_host_view_frame_subscriber.h" 29 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/content_browser_client.h" 31 #include "content/public/browser/render_process_host.h" 32 #include "content/public/browser/render_widget_host_view.h" 33 #include "content/public/common/content_client.h" 34 #include "content/public/common/content_switches.h" 35 #include "content/public/common/result_codes.h" 36 #include "gpu/command_buffer/service/gpu_switches.h" 37 #include "ipc/ipc_channel_handle.h" 38 #include "ipc/ipc_switches.h" 39 #include "ui/events/latency_info.h" 40 #include "ui/gl/gl_switches.h" 41 42 43 #if defined(OS_WIN) 44 #include "base/win/windows_version.h" 45 #include "content/common/sandbox_win.h" 46 #include "content/public/common/sandboxed_process_launcher_delegate.h" 47 #include "sandbox/win/src/sandbox_policy.h" 48 #include "ui/surface/accelerated_surface_win.h" 49 #endif 50 51 #if defined(USE_OZONE) 52 #include "ui/ozone/ozone_switches.h" 53 #endif 54 55 namespace content { 56 57 bool GpuProcessHost::gpu_enabled_ = true; 58 bool GpuProcessHost::hardware_gpu_enabled_ = true; 59 60 namespace { 61 62 enum GPUProcessLifetimeEvent { 63 LAUNCHED, 64 DIED_FIRST_TIME, 65 DIED_SECOND_TIME, 66 DIED_THIRD_TIME, 67 DIED_FOURTH_TIME, 68 GPU_PROCESS_LIFETIME_EVENT_MAX = 100 69 }; 70 71 // Indexed by GpuProcessKind. There is one of each kind maximum. This array may 72 // only be accessed from the IO thread. 73 GpuProcessHost* g_gpu_process_hosts[GpuProcessHost::GPU_PROCESS_KIND_COUNT]; 74 75 76 void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind, 77 CauseForGpuLaunch cause, 78 IPC::Message* message) { 79 GpuProcessHost* host = GpuProcessHost::Get(kind, cause); 80 if (host) { 81 host->Send(message); 82 } else { 83 delete message; 84 } 85 } 86 87 void AcceleratedSurfaceBuffersSwappedCompletedForGPU( 88 int host_id, 89 int route_id, 90 bool alive, 91 base::TimeTicks vsync_timebase, 92 base::TimeDelta vsync_interval) { 93 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 94 BrowserThread::PostTask( 95 BrowserThread::IO, 96 FROM_HERE, 97 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, 98 host_id, 99 route_id, 100 alive, 101 vsync_timebase, 102 vsync_interval)); 103 return; 104 } 105 106 GpuProcessHost* host = GpuProcessHost::FromID(host_id); 107 if (host) { 108 if (alive) { 109 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; 110 ack_params.sync_point = 0; 111 #if defined(OS_WIN) 112 ack_params.vsync_timebase = vsync_timebase; 113 ack_params.vsync_interval = vsync_interval; 114 #endif 115 host->Send( 116 new AcceleratedSurfaceMsg_BufferPresented(route_id, ack_params)); 117 } else { 118 host->ForceShutdown(); 119 } 120 } 121 } 122 123 #if defined(OS_WIN) 124 // This sends a ViewMsg_SwapBuffers_ACK directly to the renderer process 125 // (RenderWidget). 126 void AcceleratedSurfaceBuffersSwappedCompletedForRenderer( 127 int surface_id, 128 base::TimeTicks timebase, 129 base::TimeDelta interval, 130 const ui::LatencyInfo& latency_info) { 131 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 132 BrowserThread::PostTask( 133 BrowserThread::UI, 134 FROM_HERE, 135 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForRenderer, 136 surface_id, timebase, interval, latency_info)); 137 return; 138 } 139 140 int render_process_id = 0; 141 int render_widget_id = 0; 142 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( 143 surface_id, &render_process_id, &render_widget_id)) { 144 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info); 145 return; 146 } 147 RenderWidgetHost* rwh = 148 RenderWidgetHost::FromID(render_process_id, render_widget_id); 149 if (!rwh) 150 return; 151 RenderWidgetHostImpl::From(rwh)->AcknowledgeSwapBuffersToRenderer(); 152 if (interval != base::TimeDelta()) 153 RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval); 154 RenderWidgetHostImpl::From(rwh)->FrameSwapped(latency_info); 155 RenderWidgetHostImpl::From(rwh)->DidReceiveRendererFrame(); 156 } 157 158 void AcceleratedSurfaceBuffersSwappedCompleted( 159 int host_id, 160 int route_id, 161 int surface_id, 162 bool alive, 163 base::TimeTicks timebase, 164 base::TimeDelta interval, 165 const ui::LatencyInfo& latency_info) { 166 AcceleratedSurfaceBuffersSwappedCompletedForGPU( 167 host_id, route_id, alive, timebase, interval); 168 AcceleratedSurfaceBuffersSwappedCompletedForRenderer( 169 surface_id, timebase, interval, latency_info); 170 } 171 172 // NOTE: changes to this class need to be reviewed by the security team. 173 class GpuSandboxedProcessLauncherDelegate 174 : public SandboxedProcessLauncherDelegate { 175 public: 176 explicit GpuSandboxedProcessLauncherDelegate(CommandLine* cmd_line) 177 : cmd_line_(cmd_line) {} 178 virtual ~GpuSandboxedProcessLauncherDelegate() {} 179 180 virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE { 181 if (cmd_line_->HasSwitch(switches::kDisableGpuSandbox)) { 182 *in_sandbox = false; 183 DVLOG(1) << "GPU sandbox is disabled"; 184 } 185 } 186 187 virtual void PreSandbox(bool* disable_default_policy, 188 base::FilePath* exposed_dir) OVERRIDE { 189 *disable_default_policy = true; 190 } 191 192 // For the GPU process we gotten as far as USER_LIMITED. The next level 193 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL 194 // backend. Note that the GPU process is connected to the interactive 195 // desktop. 196 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy, 197 bool* success) { 198 if (base::win::GetVersion() > base::win::VERSION_XP) { 199 if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) == 200 gfx::kGLImplementationDesktopName) { 201 // Open GL path. 202 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 203 sandbox::USER_LIMITED); 204 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); 205 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 206 } else { 207 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 208 sandbox::USER_LIMITED); 209 210 // UI restrictions break when we access Windows from outside our job. 211 // However, we don't want a proxy window in this process because it can 212 // introduce deadlocks where the renderer blocks on the gpu, which in 213 // turn blocks on the browser UI thread. So, instead we forgo a window 214 // message pump entirely and just add job restrictions to prevent child 215 // processes. 216 SetJobLevel(*cmd_line_, 217 sandbox::JOB_LIMITED_USER, 218 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | 219 JOB_OBJECT_UILIMIT_DESKTOP | 220 JOB_OBJECT_UILIMIT_EXITWINDOWS | 221 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS, 222 policy); 223 224 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 225 } 226 } else { 227 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); 228 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, 229 sandbox::USER_LIMITED); 230 } 231 232 // Allow the server side of GPU sockets, which are pipes that have 233 // the "chrome.gpu" namespace and an arbitrary suffix. 234 sandbox::ResultCode result = policy->AddRule( 235 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 236 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 237 L"\\\\.\\pipe\\chrome.gpu.*"); 238 if (result != sandbox::SBOX_ALL_OK) { 239 *success = false; 240 return; 241 } 242 243 // Block this DLL even if it is not loaded by the browser process. 244 policy->AddDllToUnload(L"cmsetac.dll"); 245 246 #ifdef USE_AURA 247 // GPU also needs to add sections to the browser for aura 248 // TODO(jschuh): refactor the GPU channel to remove this. crbug.com/128786 249 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES, 250 sandbox::TargetPolicy::HANDLES_DUP_BROKER, 251 L"Section"); 252 if (result != sandbox::SBOX_ALL_OK) { 253 *success = false; 254 return; 255 } 256 #endif 257 258 if (cmd_line_->HasSwitch(switches::kEnableLogging)) { 259 base::string16 log_file_path = logging::GetLogFileFullPath(); 260 if (!log_file_path.empty()) { 261 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 262 sandbox::TargetPolicy::FILES_ALLOW_ANY, 263 log_file_path.c_str()); 264 if (result != sandbox::SBOX_ALL_OK) { 265 *success = false; 266 return; 267 } 268 } 269 } 270 } 271 272 private: 273 CommandLine* cmd_line_; 274 }; 275 #endif // defined(OS_WIN) 276 277 } // anonymous namespace 278 279 // static 280 bool GpuProcessHost::ValidateHost(GpuProcessHost* host) { 281 if (!host) 282 return false; 283 284 // The Gpu process is invalid if it's not using SwiftShader, the card is 285 // blacklisted, and we can kill it and start over. 286 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || 287 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU) || 288 (host->valid_ && 289 (host->swiftshader_rendering_ || 290 !GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()))) { 291 return true; 292 } 293 294 host->ForceShutdown(); 295 return false; 296 } 297 298 // static 299 GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind, 300 CauseForGpuLaunch cause) { 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 302 303 // Don't grant further access to GPU if it is not allowed. 304 GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance(); 305 DCHECK(gpu_data_manager); 306 if (!gpu_data_manager->GpuAccessAllowed(NULL)) 307 return NULL; 308 309 if (g_gpu_process_hosts[kind] && ValidateHost(g_gpu_process_hosts[kind])) 310 return g_gpu_process_hosts[kind]; 311 312 if (cause == CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) 313 return NULL; 314 315 static int last_host_id = 0; 316 int host_id; 317 host_id = ++last_host_id; 318 319 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", 320 cause, 321 CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); 322 323 GpuProcessHost* host = new GpuProcessHost(host_id, kind); 324 if (host->Init()) 325 return host; 326 327 delete host; 328 return NULL; 329 } 330 331 // static 332 void GpuProcessHost::GetProcessHandles( 333 const GpuDataManager::GetGpuProcessHandlesCallback& callback) { 334 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 335 BrowserThread::PostTask( 336 BrowserThread::IO, 337 FROM_HERE, 338 base::Bind(&GpuProcessHost::GetProcessHandles, callback)); 339 return; 340 } 341 std::list<base::ProcessHandle> handles; 342 for (size_t i = 0; i < arraysize(g_gpu_process_hosts); ++i) { 343 GpuProcessHost* host = g_gpu_process_hosts[i]; 344 if (host && ValidateHost(host)) 345 handles.push_back(host->process_->GetHandle()); 346 } 347 BrowserThread::PostTask( 348 BrowserThread::UI, 349 FROM_HERE, 350 base::Bind(callback, handles)); 351 } 352 353 // static 354 void GpuProcessHost::SendOnIO(GpuProcessKind kind, 355 CauseForGpuLaunch cause, 356 IPC::Message* message) { 357 if (!BrowserThread::PostTask( 358 BrowserThread::IO, FROM_HERE, 359 base::Bind( 360 &SendGpuProcessMessage, kind, cause, message))) { 361 delete message; 362 } 363 } 364 365 GpuMainThreadFactoryFunction g_gpu_main_thread_factory = NULL; 366 367 void GpuProcessHost::RegisterGpuMainThreadFactory( 368 GpuMainThreadFactoryFunction create) { 369 g_gpu_main_thread_factory = create; 370 } 371 372 // static 373 GpuProcessHost* GpuProcessHost::FromID(int host_id) { 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 375 376 for (int i = 0; i < GPU_PROCESS_KIND_COUNT; ++i) { 377 GpuProcessHost* host = g_gpu_process_hosts[i]; 378 if (host && host->host_id_ == host_id && ValidateHost(host)) 379 return host; 380 } 381 382 return NULL; 383 } 384 385 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) 386 : host_id_(host_id), 387 valid_(true), 388 in_process_(false), 389 swiftshader_rendering_(false), 390 kind_(kind), 391 process_launched_(false), 392 initialized_(false), 393 uma_memory_stats_received_(false) { 394 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || 395 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) { 396 in_process_ = true; 397 } 398 399 // If the 'single GPU process' policy ever changes, we still want to maintain 400 // it for 'gpu thread' mode and only create one instance of host and thread. 401 DCHECK(!in_process_ || g_gpu_process_hosts[kind] == NULL); 402 403 g_gpu_process_hosts[kind] = this; 404 405 // Post a task to create the corresponding GpuProcessHostUIShim. The 406 // GpuProcessHostUIShim will be destroyed if either the browser exits, 407 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the 408 // GpuProcessHost is destroyed, which happens when the corresponding GPU 409 // process terminates or fails to launch. 410 BrowserThread::PostTask( 411 BrowserThread::UI, 412 FROM_HERE, 413 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); 414 415 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); 416 } 417 418 GpuProcessHost::~GpuProcessHost() { 419 DCHECK(CalledOnValidThread()); 420 421 SendOutstandingReplies(); 422 423 // Maximum number of times the gpu process is allowed to crash in a session. 424 // Once this limit is reached, any request to launch the gpu process will 425 // fail. 426 const int kGpuMaxCrashCount = 3; 427 428 // Number of times the gpu process has crashed in the current browser session. 429 static int gpu_crash_count = 0; 430 static int gpu_recent_crash_count = 0; 431 static base::Time last_gpu_crash_time; 432 static bool crashed_before = false; 433 static int swiftshader_crash_count = 0; 434 435 bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch( 436 switches::kDisableGpuProcessCrashLimit); 437 438 // Ending only acts as a failure if the GPU process was actually started and 439 // was intended for actual rendering (and not just checking caps or other 440 // options). 441 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { 442 if (swiftshader_rendering_) { 443 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", 444 DIED_FIRST_TIME + swiftshader_crash_count, 445 GPU_PROCESS_LIFETIME_EVENT_MAX); 446 447 if (++swiftshader_crash_count >= kGpuMaxCrashCount && 448 !disable_crash_limit) { 449 // SwiftShader is too unstable to use. Disable it for current session. 450 gpu_enabled_ = false; 451 } 452 } else { 453 ++gpu_crash_count; 454 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", 455 std::min(DIED_FIRST_TIME + gpu_crash_count, 456 GPU_PROCESS_LIFETIME_EVENT_MAX - 1), 457 GPU_PROCESS_LIFETIME_EVENT_MAX); 458 459 // Allow about 1 GPU crash per hour to be removed from the crash count, 460 // so very occasional crashes won't eventually add up and prevent the 461 // GPU process from launching. 462 ++gpu_recent_crash_count; 463 base::Time current_time = base::Time::Now(); 464 if (crashed_before) { 465 int hours_different = (current_time - last_gpu_crash_time).InHours(); 466 gpu_recent_crash_count = 467 std::max(0, gpu_recent_crash_count - hours_different); 468 } 469 470 crashed_before = true; 471 last_gpu_crash_time = current_time; 472 473 if ((gpu_recent_crash_count >= kGpuMaxCrashCount && !disable_crash_limit) 474 || !initialized_) { 475 #if !defined(OS_CHROMEOS) 476 // The gpu process is too unstable to use. Disable it for current 477 // session. 478 hardware_gpu_enabled_ = false; 479 GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration(); 480 #endif 481 } 482 } 483 } 484 485 // In case we never started, clean up. 486 while (!queued_messages_.empty()) { 487 delete queued_messages_.front(); 488 queued_messages_.pop(); 489 } 490 491 // This is only called on the IO thread so no race against the constructor 492 // for another GpuProcessHost. 493 if (g_gpu_process_hosts[kind_] == this) 494 g_gpu_process_hosts[kind_] = NULL; 495 496 // If there are any remaining offscreen contexts at the point the 497 // GPU process exits, assume something went wrong, and block their 498 // URLs from accessing client 3D APIs without prompting. 499 BlockLiveOffscreenContexts(); 500 501 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitSurfaceCount", 502 GpuSurfaceTracker::Get()->GetSurfaceCount()); 503 UMA_HISTOGRAM_BOOLEAN("GPU.AtExitReceivedMemoryStats", 504 uma_memory_stats_received_); 505 506 if (uma_memory_stats_received_) { 507 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitManagedMemoryClientCount", 508 uma_memory_stats_.client_count); 509 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitContextGroupCount", 510 uma_memory_stats_.context_group_count); 511 UMA_HISTOGRAM_CUSTOM_COUNTS( 512 "GPU.AtExitMBytesAllocated", 513 uma_memory_stats_.bytes_allocated_current / 1024 / 1024, 1, 2000, 50); 514 UMA_HISTOGRAM_CUSTOM_COUNTS( 515 "GPU.AtExitMBytesAllocatedMax", 516 uma_memory_stats_.bytes_allocated_max / 1024 / 1024, 1, 2000, 50); 517 UMA_HISTOGRAM_CUSTOM_COUNTS( 518 "GPU.AtExitMBytesLimit", 519 uma_memory_stats_.bytes_limit / 1024 / 1024, 1, 2000, 50); 520 } 521 522 std::string message; 523 if (!in_process_) { 524 int exit_code; 525 base::TerminationStatus status = process_->GetTerminationStatus( 526 false /* known_dead */, &exit_code); 527 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus", 528 status, 529 base::TERMINATION_STATUS_MAX_ENUM); 530 531 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || 532 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { 533 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode", 534 exit_code, 535 RESULT_CODE_LAST_CODE); 536 } 537 538 switch (status) { 539 case base::TERMINATION_STATUS_NORMAL_TERMINATION: 540 message = "The GPU process exited normally. Everything is okay."; 541 break; 542 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: 543 message = base::StringPrintf( 544 "The GPU process exited with code %d.", 545 exit_code); 546 break; 547 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 548 message = "You killed the GPU process! Why?"; 549 break; 550 case base::TERMINATION_STATUS_PROCESS_CRASHED: 551 message = "The GPU process crashed!"; 552 break; 553 default: 554 break; 555 } 556 } 557 558 BrowserThread::PostTask(BrowserThread::UI, 559 FROM_HERE, 560 base::Bind(&GpuProcessHostUIShim::Destroy, 561 host_id_, 562 message)); 563 } 564 565 bool GpuProcessHost::Init() { 566 init_start_time_ = base::TimeTicks::Now(); 567 568 TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD); 569 570 std::string channel_id = process_->GetHost()->CreateChannel(); 571 if (channel_id.empty()) 572 return false; 573 574 if (in_process_) { 575 DCHECK(g_gpu_main_thread_factory); 576 CommandLine::ForCurrentProcess()->AppendSwitch( 577 switches::kDisableGpuWatchdog); 578 579 in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id)); 580 in_process_gpu_thread_->Start(); 581 582 OnProcessLaunched(); // Fake a callback that the process is ready. 583 } else if (!LaunchGpuProcess(channel_id)) { 584 return false; 585 } 586 587 if (!Send(new GpuMsg_Initialize())) 588 return false; 589 590 return true; 591 } 592 593 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { 594 BrowserThread::PostTask( 595 BrowserThread::UI, 596 FROM_HERE, 597 base::Bind(&RouteToGpuProcessHostUIShimTask, host_id_, message)); 598 } 599 600 bool GpuProcessHost::Send(IPC::Message* msg) { 601 DCHECK(CalledOnValidThread()); 602 if (process_->GetHost()->IsChannelOpening()) { 603 queued_messages_.push(msg); 604 return true; 605 } 606 607 bool result = process_->Send(msg); 608 if (!result) { 609 // Channel is hosed, but we may not get destroyed for a while. Send 610 // outstanding channel creation failures now so that the caller can restart 611 // with a new process/channel without waiting. 612 SendOutstandingReplies(); 613 } 614 return result; 615 } 616 617 void GpuProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { 618 DCHECK(CalledOnValidThread()); 619 process_->GetHost()->AddFilter(filter); 620 } 621 622 bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) { 623 DCHECK(CalledOnValidThread()); 624 IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) 625 IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized) 626 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) 627 IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated) 628 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer) 629 IPC_MESSAGE_HANDLER(GpuHostMsg_ImageCreated, OnImageCreated) 630 IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext, 631 OnDidCreateOffscreenContext) 632 IPC_MESSAGE_HANDLER(GpuHostMsg_DidLoseContext, OnDidLoseContext) 633 IPC_MESSAGE_HANDLER(GpuHostMsg_DidDestroyOffscreenContext, 634 OnDidDestroyOffscreenContext) 635 IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryUmaStats, 636 OnGpuMemoryUmaStatsReceived) 637 #if defined(OS_MACOSX) 638 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, 639 OnAcceleratedSurfaceBuffersSwapped) 640 #endif 641 #if defined(OS_WIN) 642 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, 643 OnAcceleratedSurfaceBuffersSwapped) 644 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer, 645 OnAcceleratedSurfacePostSubBuffer) 646 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend, 647 OnAcceleratedSurfaceSuspend) 648 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease, 649 OnAcceleratedSurfaceRelease) 650 #endif 651 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel, 652 OnDestroyChannel) 653 IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader, 654 OnCacheShader) 655 656 IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message)) 657 IPC_END_MESSAGE_MAP() 658 659 return true; 660 } 661 662 void GpuProcessHost::OnChannelConnected(int32 peer_pid) { 663 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelConnected"); 664 665 while (!queued_messages_.empty()) { 666 Send(queued_messages_.front()); 667 queued_messages_.pop(); 668 } 669 } 670 671 void GpuProcessHost::EstablishGpuChannel( 672 int client_id, 673 bool share_context, 674 const EstablishChannelCallback& callback) { 675 DCHECK(CalledOnValidThread()); 676 TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel"); 677 678 // If GPU features are already blacklisted, no need to establish the channel. 679 if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) { 680 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 681 return; 682 } 683 684 if (Send(new GpuMsg_EstablishChannel(client_id, share_context))) { 685 channel_requests_.push(callback); 686 } else { 687 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 688 } 689 690 if (!CommandLine::ForCurrentProcess()->HasSwitch( 691 switches::kDisableGpuShaderDiskCache)) { 692 CreateChannelCache(client_id); 693 } 694 } 695 696 void GpuProcessHost::CreateViewCommandBuffer( 697 const gfx::GLSurfaceHandle& compositing_surface, 698 int surface_id, 699 int client_id, 700 const GPUCreateCommandBufferConfig& init_params, 701 const CreateCommandBufferCallback& callback) { 702 TRACE_EVENT0("gpu", "GpuProcessHost::CreateViewCommandBuffer"); 703 704 DCHECK(CalledOnValidThread()); 705 706 if (!compositing_surface.is_null() && 707 Send(new GpuMsg_CreateViewCommandBuffer( 708 compositing_surface, surface_id, client_id, init_params))) { 709 create_command_buffer_requests_.push(callback); 710 surface_refs_.insert(std::make_pair(surface_id, 711 GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(surface_id))); 712 } else { 713 callback.Run(MSG_ROUTING_NONE); 714 } 715 } 716 717 void GpuProcessHost::CreateImage(gfx::PluginWindowHandle window, 718 int client_id, 719 int image_id, 720 const CreateImageCallback& callback) { 721 TRACE_EVENT0("gpu", "GpuProcessHost::CreateImage"); 722 723 DCHECK(CalledOnValidThread()); 724 725 if (Send(new GpuMsg_CreateImage(window, client_id, image_id))) { 726 create_image_requests_.push(callback); 727 } else { 728 callback.Run(gfx::Size()); 729 } 730 } 731 732 void GpuProcessHost::DeleteImage(int client_id, 733 int image_id, 734 int sync_point) { 735 TRACE_EVENT0("gpu", "GpuProcessHost::DeleteImage"); 736 737 DCHECK(CalledOnValidThread()); 738 739 Send(new GpuMsg_DeleteImage(client_id, image_id, sync_point)); 740 } 741 742 void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) { 743 UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", result); 744 initialized_ = result; 745 746 #if defined(OS_WIN) 747 if (kind_ == GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED) 748 AcceleratedPresenter::SetAdapterLUID(gpu_info.adapter_luid); 749 #endif 750 751 if (!initialized_) 752 GpuDataManagerImpl::GetInstance()->OnGpuProcessInitFailure(); 753 } 754 755 void GpuProcessHost::OnChannelEstablished( 756 const IPC::ChannelHandle& channel_handle) { 757 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished"); 758 759 if (channel_requests_.empty()) { 760 // This happens when GPU process is compromised. 761 RouteOnUIThread(GpuHostMsg_OnLogMessage( 762 logging::LOG_WARNING, 763 "WARNING", 764 "Received a ChannelEstablished message but no requests in queue.")); 765 return; 766 } 767 EstablishChannelCallback callback = channel_requests_.front(); 768 channel_requests_.pop(); 769 770 // Currently if any of the GPU features are blacklisted, we don't establish a 771 // GPU channel. 772 if (!channel_handle.name.empty() && 773 !GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) { 774 Send(new GpuMsg_CloseChannel(channel_handle)); 775 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 776 RouteOnUIThread(GpuHostMsg_OnLogMessage( 777 logging::LOG_WARNING, 778 "WARNING", 779 "Hardware acceleration is unavailable.")); 780 return; 781 } 782 783 callback.Run(channel_handle, 784 GpuDataManagerImpl::GetInstance()->GetGPUInfo()); 785 } 786 787 void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) { 788 TRACE_EVENT0("gpu", "GpuProcessHost::OnCommandBufferCreated"); 789 790 if (create_command_buffer_requests_.empty()) 791 return; 792 793 CreateCommandBufferCallback callback = 794 create_command_buffer_requests_.front(); 795 create_command_buffer_requests_.pop(); 796 callback.Run(route_id); 797 } 798 799 void GpuProcessHost::OnDestroyCommandBuffer(int32 surface_id) { 800 TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyCommandBuffer"); 801 SurfaceRefMap::iterator it = surface_refs_.find(surface_id); 802 if (it != surface_refs_.end()) { 803 surface_refs_.erase(it); 804 } 805 } 806 807 void GpuProcessHost::OnImageCreated(const gfx::Size size) { 808 TRACE_EVENT0("gpu", "GpuProcessHost::OnImageCreated"); 809 810 if (create_image_requests_.empty()) 811 return; 812 813 CreateImageCallback callback = create_image_requests_.front(); 814 create_image_requests_.pop(); 815 callback.Run(size); 816 } 817 818 void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) { 819 urls_with_live_offscreen_contexts_.insert(url); 820 } 821 822 void GpuProcessHost::OnDidLoseContext(bool offscreen, 823 gpu::error::ContextLostReason reason, 824 const GURL& url) { 825 // TODO(kbr): would be nice to see the "offscreen" flag too. 826 TRACE_EVENT2("gpu", "GpuProcessHost::OnDidLoseContext", 827 "reason", reason, 828 "url", 829 url.possibly_invalid_spec()); 830 831 if (!offscreen || url.is_empty()) { 832 // Assume that the loss of the compositor's or accelerated canvas' 833 // context is a serious event and blame the loss on all live 834 // offscreen contexts. This more robustly handles situations where 835 // the GPU process may not actually detect the context loss in the 836 // offscreen context. 837 BlockLiveOffscreenContexts(); 838 return; 839 } 840 841 GpuDataManagerImpl::DomainGuilt guilt; 842 switch (reason) { 843 case gpu::error::kGuilty: 844 guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN; 845 break; 846 case gpu::error::kUnknown: 847 guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN; 848 break; 849 case gpu::error::kInnocent: 850 return; 851 default: 852 NOTREACHED(); 853 return; 854 } 855 856 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(url, guilt); 857 } 858 859 void GpuProcessHost::OnDidDestroyOffscreenContext(const GURL& url) { 860 urls_with_live_offscreen_contexts_.erase(url); 861 } 862 863 void GpuProcessHost::OnGpuMemoryUmaStatsReceived( 864 const GPUMemoryUmaStats& stats) { 865 TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryUmaStatsReceived"); 866 uma_memory_stats_received_ = true; 867 uma_memory_stats_ = stats; 868 } 869 870 #if defined(OS_MACOSX) 871 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( 872 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { 873 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped"); 874 875 gfx::GLSurfaceHandle surface_handle = 876 GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id); 877 // Compositor window is always gfx::kNullPluginWindow. 878 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no 879 // plugin windows. 880 if (surface_handle.handle != gfx::kNullPluginWindow || 881 surface_handle.transport_type == gfx::TEXTURE_TRANSPORT) { 882 RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); 883 return; 884 } 885 886 base::ScopedClosureRunner scoped_completion_runner( 887 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, 888 host_id_, params.route_id, 889 true /* alive */, base::TimeTicks(), base::TimeDelta())); 890 891 int render_process_id = 0; 892 int render_widget_id = 0; 893 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( 894 params.surface_id, &render_process_id, &render_widget_id)) { 895 return; 896 } 897 RenderWidgetHelper* helper = 898 RenderWidgetHelper::FromProcessHostID(render_process_id); 899 if (!helper) 900 return; 901 902 // Pass the SwapBuffers on to the RenderWidgetHelper to wake up the UI thread 903 // if the browser is waiting for a new frame. Otherwise the RenderWidgetHelper 904 // will forward to the RenderWidgetHostView via RenderProcessHostImpl and 905 // RenderWidgetHostImpl. 906 ignore_result(scoped_completion_runner.Release()); 907 908 ViewHostMsg_CompositorSurfaceBuffersSwapped_Params view_params; 909 view_params.surface_id = params.surface_id; 910 view_params.surface_handle = params.surface_handle; 911 view_params.route_id = params.route_id; 912 view_params.size = params.size; 913 view_params.scale_factor = params.scale_factor; 914 view_params.gpu_process_host_id = host_id_; 915 view_params.latency_info = params.latency_info; 916 helper->DidReceiveBackingStoreMsg(ViewHostMsg_CompositorSurfaceBuffersSwapped( 917 render_widget_id, 918 view_params)); 919 } 920 #endif // OS_MACOSX 921 922 #if defined(OS_WIN) 923 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( 924 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { 925 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped"); 926 927 base::ScopedClosureRunner scoped_completion_runner( 928 base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, 929 host_id_, params.route_id, params.surface_id, 930 true, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo())); 931 932 gfx::GLSurfaceHandle handle = 933 GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id); 934 935 if (handle.is_null()) 936 return; 937 938 if (handle.transport_type == gfx::TEXTURE_TRANSPORT) { 939 TRACE_EVENT1("gpu", "SurfaceIDNotFound_RoutingToUI", 940 "surface_id", params.surface_id); 941 // This is a content area swap, send it on to the UI thread. 942 ignore_result(scoped_completion_runner.Release()); 943 RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); 944 return; 945 } 946 947 // Otherwise it's the UI swap. 948 949 scoped_refptr<AcceleratedPresenter> presenter( 950 AcceleratedPresenter::GetForWindow(handle.handle)); 951 if (!presenter) { 952 TRACE_EVENT1("gpu", 953 "EarlyOut_NativeWindowNotFound", 954 "handle", 955 handle.handle); 956 ignore_result(scoped_completion_runner.Release()); 957 AcceleratedSurfaceBuffersSwappedCompleted(host_id_, 958 params.route_id, 959 params.surface_id, 960 true, 961 base::TimeTicks(), 962 base::TimeDelta(), 963 params.latency_info); 964 return; 965 } 966 967 ignore_result(scoped_completion_runner.Release()); 968 presenter->AsyncPresentAndAcknowledge( 969 params.size, 970 params.surface_handle, 971 params.latency_info, 972 base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, 973 host_id_, 974 params.route_id, 975 params.surface_id)); 976 977 FrameSubscriberMap::iterator it = frame_subscribers_.find(params.surface_id); 978 if (it != frame_subscribers_.end() && it->second) { 979 const base::Time present_time = base::Time::Now(); 980 scoped_refptr<media::VideoFrame> target_frame; 981 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback copy_callback; 982 if (it->second->ShouldCaptureFrame(present_time, 983 &target_frame, ©_callback)) { 984 // It is a potential improvement to do the copy in present, but we use a 985 // simpler approach for now. 986 presenter->AsyncCopyToVideoFrame( 987 gfx::Rect(params.size), target_frame, 988 base::Bind(copy_callback, present_time)); 989 } 990 } 991 } 992 993 void GpuProcessHost::OnAcceleratedSurfacePostSubBuffer( 994 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) { 995 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfacePostSubBuffer"); 996 997 NOTIMPLEMENTED(); 998 } 999 1000 void GpuProcessHost::OnAcceleratedSurfaceSuspend(int32 surface_id) { 1001 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceSuspend"); 1002 1003 gfx::PluginWindowHandle handle = 1004 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id).handle; 1005 1006 if (!handle) { 1007 #if defined(USE_AURA) 1008 RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceSuspend(surface_id)); 1009 #endif 1010 return; 1011 } 1012 1013 scoped_refptr<AcceleratedPresenter> presenter( 1014 AcceleratedPresenter::GetForWindow(handle)); 1015 if (!presenter) 1016 return; 1017 1018 presenter->Suspend(); 1019 } 1020 1021 void GpuProcessHost::OnAcceleratedSurfaceRelease( 1022 const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) { 1023 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceRelease"); 1024 1025 gfx::PluginWindowHandle handle = 1026 GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id).handle; 1027 if (!handle) { 1028 #if defined(USE_AURA) 1029 RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceRelease(params)); 1030 return; 1031 #endif 1032 } 1033 1034 scoped_refptr<AcceleratedPresenter> presenter( 1035 AcceleratedPresenter::GetForWindow(handle)); 1036 if (!presenter) 1037 return; 1038 1039 presenter->ReleaseSurface(); 1040 } 1041 1042 #endif // OS_WIN 1043 1044 void GpuProcessHost::OnProcessLaunched() { 1045 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", 1046 base::TimeTicks::Now() - init_start_time_); 1047 } 1048 1049 void GpuProcessHost::OnProcessCrashed(int exit_code) { 1050 SendOutstandingReplies(); 1051 GpuDataManagerImpl::GetInstance()->ProcessCrashed( 1052 process_->GetTerminationStatus(true /* known_dead */, NULL)); 1053 } 1054 1055 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { 1056 return kind_; 1057 } 1058 1059 void GpuProcessHost::ForceShutdown() { 1060 // This is only called on the IO thread so no race against the constructor 1061 // for another GpuProcessHost. 1062 if (g_gpu_process_hosts[kind_] == this) 1063 g_gpu_process_hosts[kind_] = NULL; 1064 1065 process_->ForceShutdown(); 1066 } 1067 1068 void GpuProcessHost::BeginFrameSubscription( 1069 int surface_id, 1070 base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) { 1071 frame_subscribers_[surface_id] = subscriber; 1072 } 1073 1074 void GpuProcessHost::EndFrameSubscription(int surface_id) { 1075 frame_subscribers_.erase(surface_id); 1076 } 1077 1078 bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { 1079 if (!(gpu_enabled_ && 1080 GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) && 1081 !hardware_gpu_enabled_) { 1082 SendOutstandingReplies(); 1083 return false; 1084 } 1085 1086 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 1087 1088 CommandLine::StringType gpu_launcher = 1089 browser_command_line.GetSwitchValueNative(switches::kGpuLauncher); 1090 1091 #if defined(OS_LINUX) 1092 int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : 1093 ChildProcessHost::CHILD_NORMAL; 1094 #else 1095 int child_flags = ChildProcessHost::CHILD_NORMAL; 1096 #endif 1097 1098 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags); 1099 if (exe_path.empty()) 1100 return false; 1101 1102 CommandLine* cmd_line = new CommandLine(exe_path); 1103 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); 1104 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); 1105 1106 if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED) 1107 cmd_line->AppendSwitch(switches::kDisableGpuSandbox); 1108 1109 // Propagate relevant command line switches. 1110 static const char* const kSwitchNames[] = { 1111 switches::kDisableAcceleratedVideoDecode, 1112 switches::kDisableBreakpad, 1113 switches::kDisableGLMultisampling, 1114 switches::kDisableGpuSandbox, 1115 switches::kDisableGpuWatchdog, 1116 switches::kDisableImageTransportSurface, 1117 switches::kDisableLogging, 1118 switches::kDisableSeccompFilterSandbox, 1119 #if defined(ENABLE_WEBRTC) 1120 switches::kDisableWebRtcHWEncoding, 1121 #endif 1122 switches::kEnableLogging, 1123 switches::kEnableShareGroupAsyncTextureUpload, 1124 switches::kGpuStartupDialog, 1125 switches::kGpuSandboxAllowSysVShm, 1126 switches::kLoggingLevel, 1127 switches::kNoSandbox, 1128 switches::kReduceGpuSandbox, 1129 switches::kTestGLLib, 1130 switches::kTraceStartup, 1131 switches::kV, 1132 switches::kVModule, 1133 #if defined(OS_MACOSX) 1134 switches::kEnableSandboxLogging, 1135 #endif 1136 #if defined(USE_AURA) 1137 switches::kUIPrioritizeInGpuProcess, 1138 #endif 1139 #if defined(USE_OZONE) 1140 switches::kOzonePlatform, 1141 #endif 1142 }; 1143 cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames, 1144 arraysize(kSwitchNames)); 1145 cmd_line->CopySwitchesFrom( 1146 browser_command_line, switches::kGpuSwitches, switches::kNumGpuSwitches); 1147 cmd_line->CopySwitchesFrom( 1148 browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost, 1149 switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches); 1150 1151 GetContentClient()->browser()->AppendExtraCommandLineSwitches( 1152 cmd_line, process_->GetData().id); 1153 1154 GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line); 1155 1156 if (cmd_line->HasSwitch(switches::kUseGL)) { 1157 swiftshader_rendering_ = 1158 (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"); 1159 } 1160 1161 UMA_HISTOGRAM_BOOLEAN("GPU.GPU.GPUProcessSoftwareRendering", 1162 swiftshader_rendering_); 1163 1164 // If specified, prepend a launcher program to the command line. 1165 if (!gpu_launcher.empty()) 1166 cmd_line->PrependWrapper(gpu_launcher); 1167 1168 process_->Launch( 1169 #if defined(OS_WIN) 1170 new GpuSandboxedProcessLauncherDelegate(cmd_line), 1171 #elif defined(OS_POSIX) 1172 false, 1173 base::EnvironmentMap(), 1174 #endif 1175 cmd_line); 1176 process_launched_ = true; 1177 1178 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", 1179 LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX); 1180 return true; 1181 } 1182 1183 void GpuProcessHost::SendOutstandingReplies() { 1184 valid_ = false; 1185 // First send empty channel handles for all EstablishChannel requests. 1186 while (!channel_requests_.empty()) { 1187 EstablishChannelCallback callback = channel_requests_.front(); 1188 channel_requests_.pop(); 1189 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 1190 } 1191 1192 while (!create_command_buffer_requests_.empty()) { 1193 CreateCommandBufferCallback callback = 1194 create_command_buffer_requests_.front(); 1195 create_command_buffer_requests_.pop(); 1196 callback.Run(MSG_ROUTING_NONE); 1197 } 1198 } 1199 1200 void GpuProcessHost::BlockLiveOffscreenContexts() { 1201 for (std::multiset<GURL>::iterator iter = 1202 urls_with_live_offscreen_contexts_.begin(); 1203 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { 1204 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( 1205 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); 1206 } 1207 } 1208 1209 std::string GpuProcessHost::GetShaderPrefixKey() { 1210 if (shader_prefix_key_.empty()) { 1211 gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); 1212 1213 std::string in_str = GetContentClient()->GetProduct() + "-" + 1214 info.gl_vendor + "-" + info.gl_renderer + "-" + 1215 info.driver_version + "-" + info.driver_vendor; 1216 1217 base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_); 1218 } 1219 1220 return shader_prefix_key_; 1221 } 1222 1223 void GpuProcessHost::LoadedShader(const std::string& key, 1224 const std::string& data) { 1225 std::string prefix = GetShaderPrefixKey(); 1226 if (!key.compare(0, prefix.length(), prefix)) 1227 Send(new GpuMsg_LoadedShader(data)); 1228 } 1229 1230 void GpuProcessHost::CreateChannelCache(int32 client_id) { 1231 TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache"); 1232 1233 scoped_refptr<ShaderDiskCache> cache = 1234 ShaderCacheFactory::GetInstance()->Get(client_id); 1235 if (!cache.get()) 1236 return; 1237 1238 cache->set_host_id(host_id_); 1239 1240 client_id_to_shader_cache_[client_id] = cache; 1241 } 1242 1243 void GpuProcessHost::OnDestroyChannel(int32 client_id) { 1244 TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyChannel"); 1245 client_id_to_shader_cache_.erase(client_id); 1246 } 1247 1248 void GpuProcessHost::OnCacheShader(int32 client_id, 1249 const std::string& key, 1250 const std::string& shader) { 1251 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); 1252 ClientIdToShaderCacheMap::iterator iter = 1253 client_id_to_shader_cache_.find(client_id); 1254 // If the cache doesn't exist then this is an off the record profile. 1255 if (iter == client_id_to_shader_cache_.end()) 1256 return; 1257 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); 1258 } 1259 1260 } // namespace content 1261