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