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