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