- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / gpu / gpu_process_host.cc
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
51 namespace content {
52
53 bool GpuProcessHost::gpu_enabled_ = true;
54 bool GpuProcessHost::hardware_gpu_enabled_ = true;
55
56 namespace {
57
58 enum 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.
69 GpuProcessHost* g_gpu_process_hosts[GpuProcessHost::GPU_PROCESS_KIND_COUNT];
70
71
72 void 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
83 void 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).
122 void 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
154 void 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.
169 class 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
276 bool 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
295 GpuProcessHost* 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
328 void 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
350 void 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
361 GpuMainThreadFactoryFunction g_gpu_main_thread_factory = NULL;
362
363 void GpuProcessHost::RegisterGpuMainThreadFactory(
364     GpuMainThreadFactoryFunction create) {
365   g_gpu_main_thread_factory = create;
366 }
367
368 // static
369 GpuProcessHost* 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
381 GpuProcessHost::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
414 GpuProcessHost::~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   // Ending only acts as a failure if the GPU process was actually started and
432   // was intended for actual rendering (and not just checking caps or other
433   // options).
434   if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
435     if (swiftshader_rendering_) {
436       UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
437                                 DIED_FIRST_TIME + swiftshader_crash_count,
438                                 GPU_PROCESS_LIFETIME_EVENT_MAX);
439
440       if (++swiftshader_crash_count >= kGpuMaxCrashCount) {
441         // SwiftShader is too unstable to use. Disable it for current session.
442         gpu_enabled_ = false;
443       }
444     } else {
445       ++gpu_crash_count;
446       UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
447                                 std::min(DIED_FIRST_TIME + gpu_crash_count,
448                                          GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
449                                 GPU_PROCESS_LIFETIME_EVENT_MAX);
450
451       // Allow about 1 GPU crash per hour to be removed from the crash count,
452       // so very occasional crashes won't eventually add up and prevent the
453       // GPU process from launching.
454       ++gpu_recent_crash_count;
455       base::Time current_time = base::Time::Now();
456       if (crashed_before) {
457         int hours_different = (current_time - last_gpu_crash_time).InHours();
458         gpu_recent_crash_count =
459             std::max(0, gpu_recent_crash_count - hours_different);
460       }
461
462       crashed_before = true;
463       last_gpu_crash_time = current_time;
464
465       if (gpu_recent_crash_count >= kGpuMaxCrashCount ||
466           !initialized_) {
467 #if !defined(OS_CHROMEOS)
468         // The gpu process is too unstable to use. Disable it for current
469         // session.
470         hardware_gpu_enabled_ = false;
471         GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
472 #endif
473       }
474     }
475   }
476
477   // In case we never started, clean up.
478   while (!queued_messages_.empty()) {
479     delete queued_messages_.front();
480     queued_messages_.pop();
481   }
482
483   // This is only called on the IO thread so no race against the constructor
484   // for another GpuProcessHost.
485   if (g_gpu_process_hosts[kind_] == this)
486     g_gpu_process_hosts[kind_] = NULL;
487
488   // If there are any remaining offscreen contexts at the point the
489   // GPU process exits, assume something went wrong, and block their
490   // URLs from accessing client 3D APIs without prompting.
491   BlockLiveOffscreenContexts();
492
493   UMA_HISTOGRAM_COUNTS_100("GPU.AtExitSurfaceCount",
494                            GpuSurfaceTracker::Get()->GetSurfaceCount());
495   UMA_HISTOGRAM_BOOLEAN("GPU.AtExitReceivedMemoryStats",
496                         uma_memory_stats_received_);
497
498   if (uma_memory_stats_received_) {
499     UMA_HISTOGRAM_COUNTS_100("GPU.AtExitManagedMemoryClientCount",
500                              uma_memory_stats_.client_count);
501     UMA_HISTOGRAM_COUNTS_100("GPU.AtExitContextGroupCount",
502                              uma_memory_stats_.context_group_count);
503     UMA_HISTOGRAM_CUSTOM_COUNTS(
504         "GPU.AtExitMBytesAllocated",
505         uma_memory_stats_.bytes_allocated_current / 1024 / 1024, 1, 2000, 50);
506     UMA_HISTOGRAM_CUSTOM_COUNTS(
507         "GPU.AtExitMBytesAllocatedMax",
508         uma_memory_stats_.bytes_allocated_max / 1024 / 1024, 1, 2000, 50);
509     UMA_HISTOGRAM_CUSTOM_COUNTS(
510         "GPU.AtExitMBytesLimit",
511         uma_memory_stats_.bytes_limit / 1024 / 1024, 1, 2000, 50);
512   }
513
514   std::string message;
515   if (!in_process_) {
516     int exit_code;
517     base::TerminationStatus status = process_->GetTerminationStatus(
518         false /* known_dead */, &exit_code);
519     UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus",
520                               status,
521                               base::TERMINATION_STATUS_MAX_ENUM);
522
523     if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
524         status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
525       UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode",
526                                 exit_code,
527                                 RESULT_CODE_LAST_CODE);
528     }
529
530     switch (status) {
531       case base::TERMINATION_STATUS_NORMAL_TERMINATION:
532         message = "The GPU process exited normally. Everything is okay.";
533         break;
534       case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
535         message = base::StringPrintf(
536             "The GPU process exited with code %d.",
537             exit_code);
538         break;
539       case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
540         message = "You killed the GPU process! Why?";
541         break;
542       case base::TERMINATION_STATUS_PROCESS_CRASHED:
543         message = "The GPU process crashed!";
544         break;
545       default:
546         break;
547     }
548   }
549
550   BrowserThread::PostTask(BrowserThread::UI,
551                           FROM_HERE,
552                           base::Bind(&GpuProcessHostUIShim::Destroy,
553                                      host_id_,
554                                      message));
555 }
556
557 bool GpuProcessHost::Init() {
558   init_start_time_ = base::TimeTicks::Now();
559
560   TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD);
561
562   std::string channel_id = process_->GetHost()->CreateChannel();
563   if (channel_id.empty())
564     return false;
565
566   if (in_process_ && g_gpu_main_thread_factory) {
567     CommandLine::ForCurrentProcess()->AppendSwitch(
568         switches::kDisableGpuWatchdog);
569
570     in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id));
571     in_process_gpu_thread_->Start();
572
573     OnProcessLaunched();  // Fake a callback that the process is ready.
574   } else if (!LaunchGpuProcess(channel_id)) {
575     return false;
576   }
577
578   if (!Send(new GpuMsg_Initialize()))
579     return false;
580
581   return true;
582 }
583
584 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) {
585   BrowserThread::PostTask(
586       BrowserThread::UI,
587       FROM_HERE,
588       base::Bind(&RouteToGpuProcessHostUIShimTask, host_id_, message));
589 }
590
591 bool GpuProcessHost::Send(IPC::Message* msg) {
592   DCHECK(CalledOnValidThread());
593   if (process_->GetHost()->IsChannelOpening()) {
594     queued_messages_.push(msg);
595     return true;
596   }
597
598   bool result = process_->Send(msg);
599   if (!result) {
600     // Channel is hosed, but we may not get destroyed for a while. Send
601     // outstanding channel creation failures now so that the caller can restart
602     // with a new process/channel without waiting.
603     SendOutstandingReplies();
604   }
605   return result;
606 }
607
608 void GpuProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
609   DCHECK(CalledOnValidThread());
610   process_->GetHost()->AddFilter(filter);
611 }
612
613 bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
614   DCHECK(CalledOnValidThread());
615   IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
616     IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized)
617     IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
618     IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
619     IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer)
620     IPC_MESSAGE_HANDLER(GpuHostMsg_ImageCreated, OnImageCreated)
621     IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext,
622                         OnDidCreateOffscreenContext)
623     IPC_MESSAGE_HANDLER(GpuHostMsg_DidLoseContext, OnDidLoseContext)
624     IPC_MESSAGE_HANDLER(GpuHostMsg_DidDestroyOffscreenContext,
625                         OnDidDestroyOffscreenContext)
626     IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryUmaStats,
627                         OnGpuMemoryUmaStatsReceived)
628 #if defined(OS_MACOSX)
629     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
630                         OnAcceleratedSurfaceBuffersSwapped)
631 #endif
632 #if defined(OS_WIN)
633     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
634                         OnAcceleratedSurfaceBuffersSwapped)
635     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
636                         OnAcceleratedSurfacePostSubBuffer)
637     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
638                         OnAcceleratedSurfaceSuspend)
639     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
640                         OnAcceleratedSurfaceRelease)
641 #endif
642     IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel,
643                         OnDestroyChannel)
644     IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader,
645                         OnCacheShader)
646
647     IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message))
648   IPC_END_MESSAGE_MAP()
649
650   return true;
651 }
652
653 void GpuProcessHost::OnChannelConnected(int32 peer_pid) {
654   TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelConnected");
655
656   while (!queued_messages_.empty()) {
657     Send(queued_messages_.front());
658     queued_messages_.pop();
659   }
660 }
661
662 void GpuProcessHost::EstablishGpuChannel(
663     int client_id,
664     bool share_context,
665     const EstablishChannelCallback& callback) {
666   DCHECK(CalledOnValidThread());
667   TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel");
668
669   // If GPU features are already blacklisted, no need to establish the channel.
670   if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) {
671     callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
672     return;
673   }
674
675   if (Send(new GpuMsg_EstablishChannel(client_id, share_context))) {
676     channel_requests_.push(callback);
677   } else {
678     callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
679   }
680
681   if (!CommandLine::ForCurrentProcess()->HasSwitch(
682       switches::kDisableGpuShaderDiskCache)) {
683     CreateChannelCache(client_id);
684   }
685 }
686
687 void GpuProcessHost::CreateViewCommandBuffer(
688     const gfx::GLSurfaceHandle& compositing_surface,
689     int surface_id,
690     int client_id,
691     const GPUCreateCommandBufferConfig& init_params,
692     const CreateCommandBufferCallback& callback) {
693   TRACE_EVENT0("gpu", "GpuProcessHost::CreateViewCommandBuffer");
694
695   DCHECK(CalledOnValidThread());
696
697   if (!compositing_surface.is_null() &&
698       Send(new GpuMsg_CreateViewCommandBuffer(
699           compositing_surface, surface_id, client_id, init_params))) {
700     create_command_buffer_requests_.push(callback);
701     surface_refs_.insert(std::make_pair(surface_id,
702         GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(surface_id)));
703   } else {
704     callback.Run(MSG_ROUTING_NONE);
705   }
706 }
707
708 void GpuProcessHost::CreateImage(gfx::PluginWindowHandle window,
709                                  int client_id,
710                                  int image_id,
711                                  const CreateImageCallback& callback) {
712   TRACE_EVENT0("gpu", "GpuProcessHost::CreateImage");
713
714   DCHECK(CalledOnValidThread());
715
716   if (Send(new GpuMsg_CreateImage(window, client_id, image_id))) {
717     create_image_requests_.push(callback);
718   } else {
719     callback.Run(gfx::Size());
720   }
721 }
722
723 void GpuProcessHost::DeleteImage(int client_id,
724                                  int image_id,
725                                  int sync_point) {
726   TRACE_EVENT0("gpu", "GpuProcessHost::DeleteImage");
727
728   DCHECK(CalledOnValidThread());
729
730   Send(new GpuMsg_DeleteImage(client_id, image_id, sync_point));
731 }
732
733 void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
734   UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", result);
735   initialized_ = result;
736
737 #if defined(OS_WIN)
738   if (kind_ == GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED)
739     AcceleratedPresenter::SetAdapterLUID(gpu_info.adapter_luid);
740 #endif
741
742   if (!initialized_)
743     GpuDataManagerImpl::GetInstance()->OnGpuProcessInitFailure();
744 }
745
746 void GpuProcessHost::OnChannelEstablished(
747     const IPC::ChannelHandle& channel_handle) {
748   TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished");
749
750   if (channel_requests_.empty()) {
751     // This happens when GPU process is compromised.
752     RouteOnUIThread(GpuHostMsg_OnLogMessage(
753         logging::LOG_WARNING,
754         "WARNING",
755         "Received a ChannelEstablished message but no requests in queue."));
756     return;
757   }
758   EstablishChannelCallback callback = channel_requests_.front();
759   channel_requests_.pop();
760
761   // Currently if any of the GPU features are blacklisted, we don't establish a
762   // GPU channel.
763   if (!channel_handle.name.empty() &&
764       !GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) {
765     Send(new GpuMsg_CloseChannel(channel_handle));
766     callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
767     RouteOnUIThread(GpuHostMsg_OnLogMessage(
768         logging::LOG_WARNING,
769         "WARNING",
770         "Hardware acceleration is unavailable."));
771     return;
772   }
773
774   callback.Run(channel_handle,
775                GpuDataManagerImpl::GetInstance()->GetGPUInfo());
776 }
777
778 void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) {
779   TRACE_EVENT0("gpu", "GpuProcessHost::OnCommandBufferCreated");
780
781   if (create_command_buffer_requests_.empty())
782     return;
783
784   CreateCommandBufferCallback callback =
785       create_command_buffer_requests_.front();
786   create_command_buffer_requests_.pop();
787   callback.Run(route_id);
788 }
789
790 void GpuProcessHost::OnDestroyCommandBuffer(int32 surface_id) {
791   TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyCommandBuffer");
792   SurfaceRefMap::iterator it = surface_refs_.find(surface_id);
793   if (it != surface_refs_.end()) {
794     surface_refs_.erase(it);
795   }
796 }
797
798 void GpuProcessHost::OnImageCreated(const gfx::Size size) {
799   TRACE_EVENT0("gpu", "GpuProcessHost::OnImageCreated");
800
801   if (create_image_requests_.empty())
802     return;
803
804   CreateImageCallback callback = create_image_requests_.front();
805   create_image_requests_.pop();
806   callback.Run(size);
807 }
808
809 void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) {
810   urls_with_live_offscreen_contexts_.insert(url);
811 }
812
813 void GpuProcessHost::OnDidLoseContext(bool offscreen,
814                                       gpu::error::ContextLostReason reason,
815                                       const GURL& url) {
816   // TODO(kbr): would be nice to see the "offscreen" flag too.
817   TRACE_EVENT2("gpu", "GpuProcessHost::OnDidLoseContext",
818                "reason", reason,
819                "url",
820                url.possibly_invalid_spec());
821
822   if (!offscreen || url.is_empty()) {
823     // Assume that the loss of the compositor's or accelerated canvas'
824     // context is a serious event and blame the loss on all live
825     // offscreen contexts. This more robustly handles situations where
826     // the GPU process may not actually detect the context loss in the
827     // offscreen context.
828     BlockLiveOffscreenContexts();
829     return;
830   }
831
832   GpuDataManagerImpl::DomainGuilt guilt;
833   switch (reason) {
834     case gpu::error::kGuilty:
835       guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN;
836       break;
837     case gpu::error::kUnknown:
838       guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN;
839       break;
840     case gpu::error::kInnocent:
841       return;
842     default:
843       NOTREACHED();
844       return;
845   }
846
847   GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(url, guilt);
848 }
849
850 void GpuProcessHost::OnDidDestroyOffscreenContext(const GURL& url) {
851   urls_with_live_offscreen_contexts_.erase(url);
852 }
853
854 void GpuProcessHost::OnGpuMemoryUmaStatsReceived(
855     const GPUMemoryUmaStats& stats) {
856   TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryUmaStatsReceived");
857   uma_memory_stats_received_ = true;
858   uma_memory_stats_ = stats;
859 }
860
861 #if defined(OS_MACOSX)
862 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
863     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
864   TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped");
865
866   gfx::GLSurfaceHandle surface_handle =
867       GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id);
868   // Compositor window is always gfx::kNullPluginWindow.
869   // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
870   // plugin windows.
871   if (surface_handle.handle != gfx::kNullPluginWindow ||
872       surface_handle.transport_type == gfx::TEXTURE_TRANSPORT) {
873     RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
874     return;
875   }
876
877   base::ScopedClosureRunner scoped_completion_runner(
878       base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU,
879                  host_id_, params.route_id,
880                  true /* alive */, base::TimeTicks(), base::TimeDelta()));
881
882   int render_process_id = 0;
883   int render_widget_id = 0;
884   if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
885       params.surface_id, &render_process_id, &render_widget_id)) {
886     return;
887   }
888   RenderWidgetHelper* helper =
889       RenderWidgetHelper::FromProcessHostID(render_process_id);
890   if (!helper)
891     return;
892
893   // Pass the SwapBuffers on to the RenderWidgetHelper to wake up the UI thread
894   // if the browser is waiting for a new frame. Otherwise the RenderWidgetHelper
895   // will forward to the RenderWidgetHostView via RenderProcessHostImpl and
896   // RenderWidgetHostImpl.
897   ignore_result(scoped_completion_runner.Release());
898
899   ViewHostMsg_CompositorSurfaceBuffersSwapped_Params view_params;
900   view_params.surface_id = params.surface_id;
901   view_params.surface_handle = params.surface_handle;
902   view_params.route_id = params.route_id;
903   view_params.size = params.size;
904   view_params.scale_factor = params.scale_factor;
905   view_params.gpu_process_host_id = host_id_;
906   view_params.latency_info = params.latency_info;
907   helper->DidReceiveBackingStoreMsg(ViewHostMsg_CompositorSurfaceBuffersSwapped(
908       render_widget_id,
909       view_params));
910 }
911 #endif  // OS_MACOSX
912
913 #if defined(OS_WIN)
914 void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
915     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
916   TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped");
917
918   base::ScopedClosureRunner scoped_completion_runner(
919       base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted,
920           host_id_, params.route_id, params.surface_id,
921           true, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo()));
922
923   gfx::GLSurfaceHandle handle =
924       GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id);
925
926   if (handle.is_null())
927     return;
928
929   if (handle.transport_type == gfx::TEXTURE_TRANSPORT) {
930     TRACE_EVENT1("gpu", "SurfaceIDNotFound_RoutingToUI",
931                  "surface_id", params.surface_id);
932     // This is a content area swap, send it on to the UI thread.
933     ignore_result(scoped_completion_runner.Release());
934     RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
935     return;
936   }
937
938   // Otherwise it's the UI swap.
939
940   scoped_refptr<AcceleratedPresenter> presenter(
941       AcceleratedPresenter::GetForWindow(handle.handle));
942   if (!presenter) {
943     TRACE_EVENT1("gpu",
944                  "EarlyOut_NativeWindowNotFound",
945                  "handle",
946                  handle.handle);
947     ignore_result(scoped_completion_runner.Release());
948     AcceleratedSurfaceBuffersSwappedCompleted(host_id_,
949                                               params.route_id,
950                                               params.surface_id,
951                                               true,
952                                               base::TimeTicks(),
953                                               base::TimeDelta(),
954                                               params.latency_info);
955     return;
956   }
957
958   ignore_result(scoped_completion_runner.Release());
959   presenter->AsyncPresentAndAcknowledge(
960       params.size,
961       params.surface_handle,
962       params.latency_info,
963       base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted,
964                  host_id_,
965                  params.route_id,
966                  params.surface_id));
967
968   FrameSubscriberMap::iterator it = frame_subscribers_.find(params.surface_id);
969   if (it != frame_subscribers_.end() && it->second) {
970     const base::Time present_time = base::Time::Now();
971     scoped_refptr<media::VideoFrame> target_frame;
972     RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback copy_callback;
973     if (it->second->ShouldCaptureFrame(present_time,
974                                        &target_frame, &copy_callback)) {
975       // It is a potential improvement to do the copy in present, but we use a
976       // simpler approach for now.
977       presenter->AsyncCopyToVideoFrame(
978           gfx::Rect(params.size), target_frame,
979           base::Bind(copy_callback, present_time));
980     }
981   }
982 }
983
984 void GpuProcessHost::OnAcceleratedSurfacePostSubBuffer(
985     const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
986   TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfacePostSubBuffer");
987
988   NOTIMPLEMENTED();
989 }
990
991 void GpuProcessHost::OnAcceleratedSurfaceSuspend(int32 surface_id) {
992   TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceSuspend");
993
994   gfx::PluginWindowHandle handle =
995       GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id).handle;
996
997   if (!handle) {
998 #if defined(USE_AURA)
999     RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceSuspend(surface_id));
1000 #endif
1001     return;
1002   }
1003
1004   scoped_refptr<AcceleratedPresenter> presenter(
1005       AcceleratedPresenter::GetForWindow(handle));
1006   if (!presenter)
1007     return;
1008
1009   presenter->Suspend();
1010 }
1011
1012 void GpuProcessHost::OnAcceleratedSurfaceRelease(
1013     const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
1014   TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceRelease");
1015
1016   gfx::PluginWindowHandle handle =
1017       GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id).handle;
1018   if (!handle) {
1019 #if defined(USE_AURA)
1020     RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceRelease(params));
1021     return;
1022 #endif
1023   }
1024
1025   scoped_refptr<AcceleratedPresenter> presenter(
1026       AcceleratedPresenter::GetForWindow(handle));
1027   if (!presenter)
1028     return;
1029
1030   presenter->ReleaseSurface();
1031 }
1032
1033 #endif  // OS_WIN
1034
1035 void GpuProcessHost::OnProcessLaunched() {
1036   UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime",
1037                       base::TimeTicks::Now() - init_start_time_);
1038 }
1039
1040 void GpuProcessHost::OnProcessCrashed(int exit_code) {
1041   SendOutstandingReplies();
1042   GpuDataManagerImpl::GetInstance()->ProcessCrashed(
1043       process_->GetTerminationStatus(true /* known_dead */, NULL));
1044 }
1045
1046 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() {
1047   return kind_;
1048 }
1049
1050 void GpuProcessHost::ForceShutdown() {
1051   // This is only called on the IO thread so no race against the constructor
1052   // for another GpuProcessHost.
1053   if (g_gpu_process_hosts[kind_] == this)
1054     g_gpu_process_hosts[kind_] = NULL;
1055
1056   process_->ForceShutdown();
1057 }
1058
1059 void GpuProcessHost::BeginFrameSubscription(
1060     int surface_id,
1061     base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) {
1062   frame_subscribers_[surface_id] = subscriber;
1063 }
1064
1065 void GpuProcessHost::EndFrameSubscription(int surface_id) {
1066   frame_subscribers_.erase(surface_id);
1067 }
1068
1069 bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
1070   if (!(gpu_enabled_ &&
1071       GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) &&
1072       !hardware_gpu_enabled_) {
1073     SendOutstandingReplies();
1074     return false;
1075   }
1076
1077   const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
1078
1079   CommandLine::StringType gpu_launcher =
1080       browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
1081
1082 #if defined(OS_LINUX)
1083   int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
1084                                            ChildProcessHost::CHILD_NORMAL;
1085 #else
1086   int child_flags = ChildProcessHost::CHILD_NORMAL;
1087 #endif
1088
1089   base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
1090   if (exe_path.empty())
1091     return false;
1092
1093   CommandLine* cmd_line = new CommandLine(exe_path);
1094   cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
1095   cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
1096
1097   if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED)
1098     cmd_line->AppendSwitch(switches::kDisableGpuSandbox);
1099
1100   // Propagate relevant command line switches.
1101   static const char* const kSwitchNames[] = {
1102     switches::kDisableAcceleratedVideoDecode,
1103     switches::kDisableBreakpad,
1104     switches::kDisableGLMultisampling,
1105     switches::kDisableGpuSandbox,
1106     switches::kDisableGpuWatchdog,
1107     switches::kDisableImageTransportSurface,
1108     switches::kDisableLogging,
1109     switches::kDisableSeccompFilterSandbox,
1110     switches::kEnableLogging,
1111     switches::kEnableShareGroupAsyncTextureUpload,
1112     switches::kGpuStartupDialog,
1113     switches::kGpuSandboxAllowSysVShm,
1114     switches::kLoggingLevel,
1115     switches::kNoSandbox,
1116     switches::kReduceGpuSandbox,
1117     switches::kTestGLLib,
1118     switches::kTraceStartup,
1119     switches::kV,
1120     switches::kVModule,
1121 #if defined(OS_MACOSX)
1122     switches::kEnableSandboxLogging,
1123 #endif
1124 #if defined(USE_AURA)
1125     switches::kUIPrioritizeInGpuProcess,
1126 #endif
1127   };
1128   cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
1129                              arraysize(kSwitchNames));
1130   cmd_line->CopySwitchesFrom(
1131       browser_command_line, switches::kGpuSwitches, switches::kNumGpuSwitches);
1132   cmd_line->CopySwitchesFrom(
1133       browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost,
1134       switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches);
1135
1136   GetContentClient()->browser()->AppendExtraCommandLineSwitches(
1137       cmd_line, process_->GetData().id);
1138
1139   GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line);
1140
1141   if (cmd_line->HasSwitch(switches::kUseGL)) {
1142     swiftshader_rendering_ =
1143         (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader");
1144   }
1145
1146   UMA_HISTOGRAM_BOOLEAN("GPU.GPU.GPUProcessSoftwareRendering",
1147                         swiftshader_rendering_);
1148
1149   // If specified, prepend a launcher program to the command line.
1150   if (!gpu_launcher.empty())
1151     cmd_line->PrependWrapper(gpu_launcher);
1152
1153   process_->Launch(
1154 #if defined(OS_WIN)
1155       new GpuSandboxedProcessLauncherDelegate(cmd_line),
1156 #elif defined(OS_POSIX)
1157       false,
1158       base::EnvironmentMap(),
1159 #endif
1160       cmd_line);
1161   process_launched_ = true;
1162
1163   UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
1164                             LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX);
1165   return true;
1166 }
1167
1168 void GpuProcessHost::SendOutstandingReplies() {
1169   valid_ = false;
1170   // First send empty channel handles for all EstablishChannel requests.
1171   while (!channel_requests_.empty()) {
1172     EstablishChannelCallback callback = channel_requests_.front();
1173     channel_requests_.pop();
1174     callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
1175   }
1176
1177   while (!create_command_buffer_requests_.empty()) {
1178     CreateCommandBufferCallback callback =
1179         create_command_buffer_requests_.front();
1180     create_command_buffer_requests_.pop();
1181     callback.Run(MSG_ROUTING_NONE);
1182   }
1183 }
1184
1185 void GpuProcessHost::BlockLiveOffscreenContexts() {
1186   for (std::multiset<GURL>::iterator iter =
1187            urls_with_live_offscreen_contexts_.begin();
1188        iter != urls_with_live_offscreen_contexts_.end(); ++iter) {
1189     GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(
1190         *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
1191   }
1192 }
1193
1194 std::string GpuProcessHost::GetShaderPrefixKey() {
1195   if (shader_prefix_key_.empty()) {
1196     gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
1197
1198     std::string in_str = GetContentClient()->GetProduct() + "-" +
1199         info.gl_vendor + "-" + info.gl_renderer + "-" +
1200         info.driver_version + "-" + info.driver_vendor;
1201
1202     base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_);
1203   }
1204
1205   return shader_prefix_key_;
1206 }
1207
1208 void GpuProcessHost::LoadedShader(const std::string& key,
1209                                   const std::string& data) {
1210   std::string prefix = GetShaderPrefixKey();
1211   if (!key.compare(0, prefix.length(), prefix))
1212     Send(new GpuMsg_LoadedShader(data));
1213 }
1214
1215 void GpuProcessHost::CreateChannelCache(int32 client_id) {
1216   TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache");
1217
1218   scoped_refptr<ShaderDiskCache> cache =
1219       ShaderCacheFactory::GetInstance()->Get(client_id);
1220   if (!cache.get())
1221     return;
1222
1223   cache->set_host_id(host_id_);
1224
1225   client_id_to_shader_cache_[client_id] = cache;
1226 }
1227
1228 void GpuProcessHost::OnDestroyChannel(int32 client_id) {
1229   TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyChannel");
1230   client_id_to_shader_cache_.erase(client_id);
1231 }
1232
1233 void GpuProcessHost::OnCacheShader(int32 client_id,
1234                                    const std::string& key,
1235                                    const std::string& shader) {
1236   TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader");
1237   ClientIdToShaderCacheMap::iterator iter =
1238       client_id_to_shader_cache_.find(client_id);
1239   // If the cache doesn't exist then this is an off the record profile.
1240   if (iter == client_id_to_shader_cache_.end())
1241     return;
1242   iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader);
1243 }
1244
1245 }  // namespace content