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