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