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, &copy_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