Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / gpu / gpu_process_host.cc
blob0f7a214504ecdf3a786a89efac639d46833a0244
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.
5 #include "content/browser/gpu/gpu_process_host.h"
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/service/gpu_switches.h"
39 #include "ipc/ipc_channel_handle.h"
40 #include "ipc/ipc_switches.h"
41 #include "ui/base/latency_info.h"
42 #include "ui/gl/gl_switches.h"
45 #if defined(OS_WIN)
46 #include "base/win/windows_version.h"
47 #include "content/common/sandbox_win.h"
48 #include "content/public/common/sandboxed_process_launcher_delegate.h"
49 #include "sandbox/win/src/sandbox_policy.h"
50 #include "ui/surface/accelerated_surface_win.h"
51 #endif
53 namespace content {
55 bool GpuProcessHost::gpu_enabled_ = true;
56 bool GpuProcessHost::hardware_gpu_enabled_ = true;
58 namespace {
60 enum GPUProcessLifetimeEvent {
61 LAUNCHED,
62 DIED_FIRST_TIME,
63 DIED_SECOND_TIME,
64 DIED_THIRD_TIME,
65 DIED_FOURTH_TIME,
66 GPU_PROCESS_LIFETIME_EVENT_MAX = 100
69 // Indexed by GpuProcessKind. There is one of each kind maximum. This array may
70 // only be accessed from the IO thread.
71 GpuProcessHost* g_gpu_process_hosts[GpuProcessHost::GPU_PROCESS_KIND_COUNT];
74 void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind,
75 CauseForGpuLaunch cause,
76 IPC::Message* message) {
77 GpuProcessHost* host = GpuProcessHost::Get(kind, cause);
78 if (host) {
79 host->Send(message);
80 } else {
81 delete message;
85 void AcceleratedSurfaceBuffersSwappedCompletedForGPU(int host_id,
86 int route_id,
87 bool alive) {
88 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
89 BrowserThread::PostTask(
90 BrowserThread::IO,
91 FROM_HERE,
92 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU,
93 host_id,
94 route_id,
95 alive));
96 return;
99 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
100 if (host) {
101 if (alive) {
102 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
103 ack_params.sync_point = 0;
104 host->Send(
105 new AcceleratedSurfaceMsg_BufferPresented(route_id, ack_params));
106 } else {
107 host->ForceShutdown();
112 #if defined(OS_WIN)
113 // This sends a ViewMsg_SwapBuffers_ACK directly to the renderer process
114 // (RenderWidget).
115 void AcceleratedSurfaceBuffersSwappedCompletedForRenderer(
116 int surface_id,
117 base::TimeTicks timebase,
118 base::TimeDelta interval,
119 const ui::LatencyInfo& latency_info) {
120 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
121 BrowserThread::PostTask(
122 BrowserThread::UI,
123 FROM_HERE,
124 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForRenderer,
125 surface_id, timebase, interval, latency_info));
126 return;
129 int render_process_id = 0;
130 int render_widget_id = 0;
131 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
132 surface_id, &render_process_id, &render_widget_id)) {
133 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
134 return;
136 RenderWidgetHost* rwh =
137 RenderWidgetHost::FromID(render_process_id, render_widget_id);
138 if (!rwh)
139 return;
140 RenderWidgetHostImpl::From(rwh)->AcknowledgeSwapBuffersToRenderer();
141 if (interval != base::TimeDelta())
142 RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval);
143 RenderWidgetHostImpl::From(rwh)->FrameSwapped(latency_info);
146 void AcceleratedSurfaceBuffersSwappedCompleted(
147 int host_id,
148 int route_id,
149 int surface_id,
150 bool alive,
151 base::TimeTicks timebase,
152 base::TimeDelta interval,
153 const ui::LatencyInfo& latency_info) {
154 AcceleratedSurfaceBuffersSwappedCompletedForGPU(host_id, route_id,
155 alive);
156 AcceleratedSurfaceBuffersSwappedCompletedForRenderer(surface_id, timebase,
157 interval, latency_info);
160 // NOTE: changes to this class need to be reviewed by the security team.
161 class GpuSandboxedProcessLauncherDelegate
162 : public SandboxedProcessLauncherDelegate {
163 public:
164 explicit GpuSandboxedProcessLauncherDelegate(CommandLine* cmd_line)
165 : cmd_line_(cmd_line) {}
166 virtual ~GpuSandboxedProcessLauncherDelegate() {}
168 virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE {
169 if (cmd_line_->HasSwitch(switches::kDisableGpuSandbox)) {
170 *in_sandbox = false;
171 DVLOG(1) << "GPU sandbox is disabled";
175 virtual void PreSandbox(bool* disable_default_policy,
176 base::FilePath* exposed_dir) OVERRIDE {
177 *disable_default_policy = true;
180 // For the GPU process we gotten as far as USER_LIMITED. The next level
181 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL
182 // backend. Note that the GPU process is connected to the interactive
183 // desktop.
184 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
185 bool* success) {
186 if (base::win::GetVersion() > base::win::VERSION_XP) {
187 if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) ==
188 gfx::kGLImplementationDesktopName) {
189 // Open GL path.
190 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
191 sandbox::USER_LIMITED);
192 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
193 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
194 } else {
195 if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) ==
196 gfx::kGLImplementationSwiftShaderName ||
197 cmd_line_->HasSwitch(switches::kReduceGpuSandbox) ||
198 cmd_line_->HasSwitch(switches::kDisableImageTransportSurface)) {
199 // Swiftshader path.
200 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
201 sandbox::USER_LIMITED);
202 } else {
203 // Angle + DirectX path.
204 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
205 sandbox::USER_RESTRICTED);
206 // This is a trick to keep the GPU out of low-integrity processes. It
207 // starts at low-integrity for UIPI to work, then drops below
208 // low-integrity after warm-up.
209 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
212 // UI restrictions break when we access Windows from outside our job.
213 // However, we don't want a proxy window in this process because it can
214 // introduce deadlocks where the renderer blocks on the gpu, which in
215 // turn blocks on the browser UI thread. So, instead we forgo a window
216 // message pump entirely and just add job restrictions to prevent child
217 // processes.
218 SetJobLevel(*cmd_line_,
219 sandbox::JOB_LIMITED_USER,
220 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |
221 JOB_OBJECT_UILIMIT_DESKTOP |
222 JOB_OBJECT_UILIMIT_EXITWINDOWS |
223 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS,
224 policy);
226 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
228 } else {
229 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
230 policy->SetTokenLevel(sandbox::USER_UNPROTECTED,
231 sandbox::USER_LIMITED);
234 // Allow the server side of GPU sockets, which are pipes that have
235 // the "chrome.gpu" namespace and an arbitrary suffix.
236 sandbox::ResultCode result = policy->AddRule(
237 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
238 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
239 L"\\\\.\\pipe\\chrome.gpu.*");
240 if (result != sandbox::SBOX_ALL_OK) {
241 *success = false;
242 return;
245 // Block this DLL even if it is not loaded by the browser process.
246 policy->AddDllToUnload(L"cmsetac.dll");
248 #ifdef USE_AURA
249 // GPU also needs to add sections to the browser for aura
250 // TODO(jschuh): refactor the GPU channel to remove this. crbug.com/128786
251 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
252 sandbox::TargetPolicy::HANDLES_DUP_BROKER,
253 L"Section");
254 if (result != sandbox::SBOX_ALL_OK) {
255 *success = false;
256 return;
258 #endif
260 if (cmd_line_->HasSwitch(switches::kEnableLogging)) {
261 string16 log_file_path = logging::GetLogFileFullPath();
262 if (!log_file_path.empty()) {
263 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
264 sandbox::TargetPolicy::FILES_ALLOW_ANY,
265 log_file_path.c_str());
266 if (result != sandbox::SBOX_ALL_OK) {
267 *success = false;
268 return;
274 private:
275 CommandLine* cmd_line_;
277 #endif // defined(OS_WIN)
279 } // anonymous namespace
281 // This class creates a GPU thread (instead of a GPU process), when running
282 // with --in-process-gpu or --single-process.
283 class GpuMainThread : public base::Thread {
284 public:
285 explicit GpuMainThread(const std::string& channel_id)
286 : base::Thread("Chrome_InProcGpuThread"),
287 channel_id_(channel_id),
288 gpu_process_(NULL),
289 child_thread_(NULL) {
292 virtual ~GpuMainThread() {
293 Stop();
296 protected:
297 virtual void Init() OVERRIDE {
298 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) {
299 child_thread_ = new GpuChildThread(channel_id_);
300 } else {
301 gpu_process_ = new GpuProcess();
302 // The process object takes ownership of the thread object, so do not
303 // save and delete the pointer.
304 gpu_process_->set_main_thread(new GpuChildThread(channel_id_));
308 virtual void CleanUp() OVERRIDE {
309 delete gpu_process_;
310 if (child_thread_)
311 delete child_thread_;
314 private:
315 std::string channel_id_;
316 // Deleted in CleanUp() on the gpu thread, so don't use smart pointers.
317 GpuProcess* gpu_process_;
318 GpuChildThread* child_thread_;
320 DISALLOW_COPY_AND_ASSIGN(GpuMainThread);
323 // static
324 bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
325 if (!host)
326 return false;
328 // The Gpu process is invalid if it's not using SwiftShader, the card is
329 // blacklisted, and we can kill it and start over.
330 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
331 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU) ||
332 (host->valid_ &&
333 (host->swiftshader_rendering_ ||
334 !GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()))) {
335 return true;
338 host->ForceShutdown();
339 return false;
342 // static
343 GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind,
344 CauseForGpuLaunch cause) {
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
347 // Don't grant further access to GPU if it is not allowed.
348 GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
349 DCHECK(gpu_data_manager);
350 if (!gpu_data_manager->GpuAccessAllowed(NULL))
351 return NULL;
353 if (g_gpu_process_hosts[kind] && ValidateHost(g_gpu_process_hosts[kind]))
354 return g_gpu_process_hosts[kind];
356 if (cause == CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH)
357 return NULL;
359 static int last_host_id = 0;
360 int host_id;
361 host_id = ++last_host_id;
363 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause",
364 cause,
365 CAUSE_FOR_GPU_LAUNCH_MAX_ENUM);
367 GpuProcessHost* host = new GpuProcessHost(host_id, kind);
368 if (host->Init())
369 return host;
371 delete host;
372 return NULL;
375 // static
376 void GpuProcessHost::GetProcessHandles(
377 const GpuDataManager::GetGpuProcessHandlesCallback& callback) {
378 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
379 BrowserThread::PostTask(
380 BrowserThread::IO,
381 FROM_HERE,
382 base::Bind(&GpuProcessHost::GetProcessHandles, callback));
383 return;
385 std::list<base::ProcessHandle> handles;
386 for (size_t i = 0; i < arraysize(g_gpu_process_hosts); ++i) {
387 GpuProcessHost* host = g_gpu_process_hosts[i];
388 if (host && ValidateHost(host))
389 handles.push_back(host->process_->GetHandle());
391 BrowserThread::PostTask(
392 BrowserThread::UI,
393 FROM_HERE,
394 base::Bind(callback, handles));
397 // static
398 void GpuProcessHost::SendOnIO(GpuProcessKind kind,
399 CauseForGpuLaunch cause,
400 IPC::Message* message) {
401 if (!BrowserThread::PostTask(
402 BrowserThread::IO, FROM_HERE,
403 base::Bind(
404 &SendGpuProcessMessage, kind, cause, message))) {
405 delete message;
409 // static
410 GpuProcessHost* GpuProcessHost::FromID(int host_id) {
411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
413 for (int i = 0; i < GPU_PROCESS_KIND_COUNT; ++i) {
414 GpuProcessHost* host = g_gpu_process_hosts[i];
415 if (host && host->host_id_ == host_id && ValidateHost(host))
416 return host;
419 return NULL;
422 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind)
423 : host_id_(host_id),
424 valid_(true),
425 in_process_(false),
426 swiftshader_rendering_(false),
427 kind_(kind),
428 process_launched_(false),
429 initialized_(false),
430 uma_memory_stats_received_(false) {
431 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
432 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) {
433 in_process_ = true;
436 // If the 'single GPU process' policy ever changes, we still want to maintain
437 // it for 'gpu thread' mode and only create one instance of host and thread.
438 DCHECK(!in_process_ || g_gpu_process_hosts[kind] == NULL);
440 g_gpu_process_hosts[kind] = this;
442 // Post a task to create the corresponding GpuProcessHostUIShim. The
443 // GpuProcessHostUIShim will be destroyed if either the browser exits,
444 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the
445 // GpuProcessHost is destroyed, which happens when the corresponding GPU
446 // process terminates or fails to launch.
447 BrowserThread::PostTask(
448 BrowserThread::UI,
449 FROM_HERE,
450 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id));
452 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this));
455 GpuProcessHost::~GpuProcessHost() {
456 DCHECK(CalledOnValidThread());
458 SendOutstandingReplies();
460 // Maximum number of times the gpu process is allowed to crash in a session.
461 // Once this limit is reached, any request to launch the gpu process will
462 // fail.
463 const int kGpuMaxCrashCount = 3;
465 // Number of times the gpu process has crashed in the current browser session.
466 static int gpu_crash_count = 0;
467 static int gpu_recent_crash_count = 0;
468 static base::Time last_gpu_crash_time;
469 static bool crashed_before = false;
470 static int swiftshader_crash_count = 0;
472 // Ending only acts as a failure if the GPU process was actually started and
473 // was intended for actual rendering (and not just checking caps or other
474 // options).
475 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
476 if (swiftshader_rendering_) {
477 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
478 DIED_FIRST_TIME + swiftshader_crash_count,
479 GPU_PROCESS_LIFETIME_EVENT_MAX);
481 if (++swiftshader_crash_count >= kGpuMaxCrashCount) {
482 // SwiftShader is too unstable to use. Disable it for current session.
483 gpu_enabled_ = false;
485 } else {
486 ++gpu_crash_count;
487 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
488 std::min(DIED_FIRST_TIME + gpu_crash_count,
489 GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
490 GPU_PROCESS_LIFETIME_EVENT_MAX);
492 // Allow about 1 GPU crash per hour to be removed from the crash count,
493 // so very occasional crashes won't eventually add up and prevent the
494 // GPU process from launching.
495 ++gpu_recent_crash_count;
496 base::Time current_time = base::Time::Now();
497 if (crashed_before) {
498 int hours_different = (current_time - last_gpu_crash_time).InHours();
499 gpu_recent_crash_count =
500 std::max(0, gpu_recent_crash_count - hours_different);
503 crashed_before = true;
504 last_gpu_crash_time = current_time;
506 if (gpu_recent_crash_count >= kGpuMaxCrashCount ||
507 !initialized_) {
508 #if !defined(OS_CHROMEOS)
509 // The gpu process is too unstable to use. Disable it for current
510 // session.
511 hardware_gpu_enabled_ = false;
512 GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
513 #endif
518 // In case we never started, clean up.
519 while (!queued_messages_.empty()) {
520 delete queued_messages_.front();
521 queued_messages_.pop();
524 // This is only called on the IO thread so no race against the constructor
525 // for another GpuProcessHost.
526 if (g_gpu_process_hosts[kind_] == this)
527 g_gpu_process_hosts[kind_] = NULL;
529 // If there are any remaining offscreen contexts at the point the
530 // GPU process exits, assume something went wrong, and block their
531 // URLs from accessing client 3D APIs without prompting.
532 BlockLiveOffscreenContexts();
534 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitSurfaceCount",
535 GpuSurfaceTracker::Get()->GetSurfaceCount());
536 UMA_HISTOGRAM_BOOLEAN("GPU.AtExitReceivedMemoryStats",
537 uma_memory_stats_received_);
539 if (uma_memory_stats_received_) {
540 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitManagedMemoryClientCount",
541 uma_memory_stats_.client_count);
542 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitContextGroupCount",
543 uma_memory_stats_.context_group_count);
544 UMA_HISTOGRAM_CUSTOM_COUNTS(
545 "GPU.AtExitMBytesAllocated",
546 uma_memory_stats_.bytes_allocated_current / 1024 / 1024, 1, 2000, 50);
547 UMA_HISTOGRAM_CUSTOM_COUNTS(
548 "GPU.AtExitMBytesAllocatedMax",
549 uma_memory_stats_.bytes_allocated_max / 1024 / 1024, 1, 2000, 50);
550 UMA_HISTOGRAM_CUSTOM_COUNTS(
551 "GPU.AtExitMBytesLimit",
552 uma_memory_stats_.bytes_limit / 1024 / 1024, 1, 2000, 50);
555 std::string message;
556 if (!in_process_) {
557 int exit_code;
558 base::TerminationStatus status = process_->GetTerminationStatus(&exit_code);
559 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus",
560 status,
561 base::TERMINATION_STATUS_MAX_ENUM);
563 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
564 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
565 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode",
566 exit_code,
567 RESULT_CODE_LAST_CODE);
570 switch (status) {
571 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
572 message = "The GPU process exited normally. Everything is okay.";
573 break;
574 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
575 message = base::StringPrintf(
576 "The GPU process exited with code %d.",
577 exit_code);
578 break;
579 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
580 message = "You killed the GPU process! Why?";
581 break;
582 case base::TERMINATION_STATUS_PROCESS_CRASHED:
583 message = "The GPU process crashed!";
584 break;
585 default:
586 break;
590 BrowserThread::PostTask(BrowserThread::UI,
591 FROM_HERE,
592 base::Bind(&GpuProcessHostUIShim::Destroy,
593 host_id_,
594 message));
597 bool GpuProcessHost::Init() {
598 init_start_time_ = base::TimeTicks::Now();
600 TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD);
602 std::string channel_id = process_->GetHost()->CreateChannel();
603 if (channel_id.empty())
604 return false;
606 if (in_process_) {
607 CommandLine::ForCurrentProcess()->AppendSwitch(
608 switches::kDisableGpuWatchdog);
610 in_process_gpu_thread_.reset(new GpuMainThread(channel_id));
611 in_process_gpu_thread_->Start();
613 OnProcessLaunched(); // Fake a callback that the process is ready.
614 } else if (!LaunchGpuProcess(channel_id)) {
615 return false;
618 if (!Send(new GpuMsg_Initialize()))
619 return false;
621 return true;
624 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) {
625 BrowserThread::PostTask(
626 BrowserThread::UI,
627 FROM_HERE,
628 base::Bind(&RouteToGpuProcessHostUIShimTask, host_id_, message));
631 bool GpuProcessHost::Send(IPC::Message* msg) {
632 DCHECK(CalledOnValidThread());
633 if (process_->GetHost()->IsChannelOpening()) {
634 queued_messages_.push(msg);
635 return true;
638 bool result = process_->Send(msg);
639 if (!result) {
640 // Channel is hosed, but we may not get destroyed for a while. Send
641 // outstanding channel creation failures now so that the caller can restart
642 // with a new process/channel without waiting.
643 SendOutstandingReplies();
645 return result;
648 void GpuProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
649 DCHECK(CalledOnValidThread());
650 process_->GetHost()->AddFilter(filter);
653 bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
654 DCHECK(CalledOnValidThread());
655 IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
656 IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized)
657 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
658 IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
659 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer)
660 IPC_MESSAGE_HANDLER(GpuHostMsg_ImageCreated, OnImageCreated)
661 IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext,
662 OnDidCreateOffscreenContext)
663 IPC_MESSAGE_HANDLER(GpuHostMsg_DidLoseContext, OnDidLoseContext)
664 IPC_MESSAGE_HANDLER(GpuHostMsg_DidDestroyOffscreenContext,
665 OnDidDestroyOffscreenContext)
666 IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryUmaStats,
667 OnGpuMemoryUmaStatsReceived)
668 #if defined(OS_MACOSX)
669 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
670 OnAcceleratedSurfaceBuffersSwapped)
671 #endif
672 #if defined(OS_WIN)
673 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
674 OnAcceleratedSurfaceBuffersSwapped)
675 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
676 OnAcceleratedSurfacePostSubBuffer)
677 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
678 OnAcceleratedSurfaceSuspend)
679 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
680 OnAcceleratedSurfaceRelease)
681 #endif
682 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel,
683 OnDestroyChannel)
684 IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader,
685 OnCacheShader)
687 IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message))
688 IPC_END_MESSAGE_MAP()
690 return true;
693 void GpuProcessHost::OnChannelConnected(int32 peer_pid) {
694 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelConnected");
696 while (!queued_messages_.empty()) {
697 Send(queued_messages_.front());
698 queued_messages_.pop();
702 void GpuProcessHost::EstablishGpuChannel(
703 int client_id,
704 bool share_context,
705 const EstablishChannelCallback& callback) {
706 DCHECK(CalledOnValidThread());
707 TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel");
709 // If GPU features are already blacklisted, no need to establish the channel.
710 if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) {
711 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
712 return;
715 if (Send(new GpuMsg_EstablishChannel(client_id, share_context))) {
716 channel_requests_.push(callback);
717 } else {
718 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
721 if (!CommandLine::ForCurrentProcess()->HasSwitch(
722 switches::kDisableGpuShaderDiskCache)) {
723 CreateChannelCache(client_id);
727 void GpuProcessHost::CreateViewCommandBuffer(
728 const gfx::GLSurfaceHandle& compositing_surface,
729 int surface_id,
730 int client_id,
731 const GPUCreateCommandBufferConfig& init_params,
732 const CreateCommandBufferCallback& callback) {
733 TRACE_EVENT0("gpu", "GpuProcessHost::CreateViewCommandBuffer");
735 DCHECK(CalledOnValidThread());
737 if (!compositing_surface.is_null() &&
738 Send(new GpuMsg_CreateViewCommandBuffer(
739 compositing_surface, surface_id, client_id, init_params))) {
740 create_command_buffer_requests_.push(callback);
741 surface_refs_.insert(std::make_pair(surface_id,
742 GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(surface_id)));
743 } else {
744 callback.Run(MSG_ROUTING_NONE);
748 void GpuProcessHost::CreateImage(gfx::PluginWindowHandle window,
749 int client_id,
750 int image_id,
751 const CreateImageCallback& callback) {
752 TRACE_EVENT0("gpu", "GpuProcessHost::CreateImage");
754 DCHECK(CalledOnValidThread());
756 if (Send(new GpuMsg_CreateImage(window, client_id, image_id))) {
757 create_image_requests_.push(callback);
758 } else {
759 callback.Run(gfx::Size());
763 void GpuProcessHost::DeleteImage(int client_id,
764 int image_id,
765 int sync_point) {
766 TRACE_EVENT0("gpu", "GpuProcessHost::DeleteImage");
768 DCHECK(CalledOnValidThread());
770 Send(new GpuMsg_DeleteImage(client_id, image_id, sync_point));
773 void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
774 UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", result);
775 initialized_ = result;
777 #if defined(OS_WIN)
778 if (kind_ == GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED)
779 AcceleratedPresenter::SetAdapterLUID(gpu_info.adapter_luid);
780 #endif
782 if (!initialized_)
783 GpuDataManagerImpl::GetInstance()->OnGpuProcessInitFailure();
786 void GpuProcessHost::OnChannelEstablished(
787 const IPC::ChannelHandle& channel_handle) {
788 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished");
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;
798 EstablishChannelCallback callback = channel_requests_.front();
799 channel_requests_.pop();
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;
814 callback.Run(channel_handle,
815 GpuDataManagerImpl::GetInstance()->GetGPUInfo());
818 void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) {
819 TRACE_EVENT0("gpu", "GpuProcessHost::OnCommandBufferCreated");
821 if (create_command_buffer_requests_.empty())
822 return;
824 CreateCommandBufferCallback callback =
825 create_command_buffer_requests_.front();
826 create_command_buffer_requests_.pop();
827 callback.Run(route_id);
830 void 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);
838 void GpuProcessHost::OnImageCreated(const gfx::Size size) {
839 TRACE_EVENT0("gpu", "GpuProcessHost::OnImageCreated");
841 if (create_image_requests_.empty())
842 return;
844 CreateImageCallback callback = create_image_requests_.front();
845 create_image_requests_.pop();
846 callback.Run(size);
849 void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) {
850 urls_with_live_offscreen_contexts_.insert(url);
853 void 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());
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;
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;
887 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(url, guilt);
890 void GpuProcessHost::OnDidDestroyOffscreenContext(const GURL& url) {
891 urls_with_live_offscreen_contexts_.erase(url);
894 void GpuProcessHost::OnGpuMemoryUmaStatsReceived(
895 const GPUMemoryUmaStats& stats) {
896 TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryUmaStatsReceived");
897 uma_memory_stats_received_ = true;
898 uma_memory_stats_ = stats;
901 #if defined(OS_MACOSX)
902 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
903 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
904 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped");
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;
917 base::ScopedClosureRunner scoped_completion_runner(
918 base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU,
919 host_id_, params.route_id,
920 true /* alive */));
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;
928 RenderWidgetHelper* helper =
929 RenderWidgetHelper::FromProcessHostID(render_process_id);
930 if (!helper)
931 return;
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();
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));
951 #endif // OS_MACOSX
953 #if defined(OS_WIN)
954 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
955 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
956 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped");
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()));
963 gfx::GLSurfaceHandle handle =
964 GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id);
966 if (handle.is_null())
967 return;
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;
978 // Otherwise it's the UI swap.
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;
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));
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, &copy_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));
1024 void GpuProcessHost::OnAcceleratedSurfacePostSubBuffer(
1025 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
1026 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfacePostSubBuffer");
1028 NOTIMPLEMENTED();
1031 void GpuProcessHost::OnAcceleratedSurfaceSuspend(int32 surface_id) {
1032 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceSuspend");
1034 gfx::PluginWindowHandle handle =
1035 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id).handle;
1037 if (!handle) {
1038 #if defined(USE_AURA)
1039 RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceSuspend(surface_id));
1040 #endif
1041 return;
1044 scoped_refptr<AcceleratedPresenter> presenter(
1045 AcceleratedPresenter::GetForWindow(handle));
1046 if (!presenter)
1047 return;
1049 presenter->Suspend();
1052 void GpuProcessHost::OnAcceleratedSurfaceRelease(
1053 const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
1054 TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceRelease");
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
1065 scoped_refptr<AcceleratedPresenter> presenter(
1066 AcceleratedPresenter::GetForWindow(handle));
1067 if (!presenter)
1068 return;
1070 presenter->ReleaseSurface();
1073 #endif // OS_WIN
1075 void GpuProcessHost::OnProcessLaunched() {
1076 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime",
1077 base::TimeTicks::Now() - init_start_time_);
1080 void GpuProcessHost::OnProcessCrashed(int exit_code) {
1081 SendOutstandingReplies();
1082 GpuDataManagerImpl::GetInstance()->ProcessCrashed(
1083 process_->GetTerminationStatus(NULL));
1086 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() {
1087 return kind_;
1090 void 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;
1096 process_->ForceShutdown();
1099 void GpuProcessHost::BeginFrameSubscription(
1100 int surface_id,
1101 base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) {
1102 frame_subscribers_[surface_id] = subscriber;
1105 void GpuProcessHost::EndFrameSubscription(int surface_id) {
1106 frame_subscribers_.erase(surface_id);
1109 bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
1110 if (!(gpu_enabled_ &&
1111 GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) &&
1112 !hardware_gpu_enabled_) {
1113 SendOutstandingReplies();
1114 return false;
1117 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
1119 CommandLine::StringType gpu_launcher =
1120 browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
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
1129 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
1130 if (exe_path.empty())
1131 return false;
1133 CommandLine* cmd_line = new CommandLine(exe_path);
1134 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
1135 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
1137 if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED)
1138 cmd_line->AppendSwitch(switches::kDisableGpuSandbox);
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
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);
1177 GetContentClient()->browser()->AppendExtraCommandLineSwitches(
1178 cmd_line, process_->GetData().id);
1180 GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line);
1182 if (cmd_line->HasSwitch(switches::kUseGL)) {
1183 swiftshader_rendering_ =
1184 (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader");
1187 UMA_HISTOGRAM_BOOLEAN("GPU.GPU.GPUProcessSoftwareRendering",
1188 swiftshader_rendering_);
1190 // If specified, prepend a launcher program to the command line.
1191 if (!gpu_launcher.empty())
1192 cmd_line->PrependWrapper(gpu_launcher);
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;
1204 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
1205 LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX);
1206 return true;
1209 void 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());
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);
1226 void 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);
1235 std::string GpuProcessHost::GetShaderPrefixKey() {
1236 if (shader_prefix_key_.empty()) {
1237 gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
1239 std::string in_str = GetContentClient()->GetProduct() + "-" +
1240 info.gl_vendor + "-" + info.gl_renderer + "-" +
1241 info.driver_version + "-" + info.driver_vendor;
1243 base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_);
1246 return shader_prefix_key_;
1249 void 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));
1256 void GpuProcessHost::CreateChannelCache(int32 client_id) {
1257 TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache");
1259 scoped_refptr<ShaderDiskCache> cache =
1260 ShaderCacheFactory::GetInstance()->Get(client_id);
1261 if (!cache.get())
1262 return;
1264 cache->set_host_id(host_id_);
1266 client_id_to_shader_cache_[client_id] = cache;
1269 void GpuProcessHost::OnDestroyChannel(int32 client_id) {
1270 TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyChannel");
1271 client_id_to_shader_cache_.erase(client_id);
1274 void GpuProcessHost::OnCacheShader(int32 client_id,
1275 const std::string& key,
1276 const std::string& shader) {
1277 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader");
1278 ClientIdToShaderCacheMap::iterator iter =
1279 client_id_to_shader_cache_.find(client_id);
1280 // If the cache doesn't exist then this is an off the record profile.
1281 if (iter == client_id_to_shader_cache_.end())
1282 return;
1283 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader);
1286 } // namespace content