1// Copyright (c) 2013 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_data_manager_impl_private.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/command_line.h"
10#include "base/debug/trace_event.h"
11#include "base/metrics/field_trial.h"
12#include "base/metrics/histogram.h"
13#include "base/metrics/sparse_histogram.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/stringprintf.h"
16#include "base/sys_info.h"
17#include "base/version.h"
18#include "cc/base/switches.h"
19#include "content/browser/gpu/gpu_process_host.h"
20#include "content/common/gpu/gpu_messages.h"
21#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/gpu_data_manager_observer.h"
23#include "content/public/common/content_client.h"
24#include "content/public/common/content_constants.h"
25#include "content/public/common/content_switches.h"
26#include "content/public/common/web_preferences.h"
27#include "gpu/command_buffer/service/gpu_switches.h"
28#include "gpu/config/gpu_control_list_jsons.h"
29#include "gpu/config/gpu_driver_bug_workaround_type.h"
30#include "gpu/config/gpu_feature_type.h"
31#include "gpu/config/gpu_info_collector.h"
32#include "gpu/config/gpu_util.h"
33#include "ui/base/ui_base_switches.h"
34#include "ui/gl/gl_implementation.h"
35#include "ui/gl/gl_switches.h"
36#include "ui/gl/gpu_switching_manager.h"
37
38#if defined(OS_MACOSX)
39#include <ApplicationServices/ApplicationServices.h>
40#endif  // OS_MACOSX
41#if defined(OS_WIN)
42#include "base/win/windows_version.h"
43#endif  // OS_WIN
44#if defined(OS_ANDROID)
45#include "ui/gfx/android/device_display_info.h"
46#endif  // OS_ANDROID
47
48namespace content {
49
50namespace {
51
52enum GpuFeatureStatus {
53    kGpuFeatureEnabled = 0,
54    kGpuFeatureBlacklisted = 1,
55    kGpuFeatureDisabled = 2,  // disabled by user but not blacklisted
56    kGpuFeatureNumStatus
57};
58
59#if defined(OS_WIN)
60
61enum WinSubVersion {
62  kWinOthers = 0,
63  kWinXP,
64  kWinVista,
65  kWin7,
66  kWin8,
67  kNumWinSubVersions
68};
69
70int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) {
71  static WinSubVersion sub_version = kNumWinSubVersions;
72  if (sub_version == kNumWinSubVersions) {
73    sub_version = kWinOthers;
74    std::string version_str = base::SysInfo::OperatingSystemVersion();
75    size_t pos = version_str.find_first_not_of("0123456789.");
76    if (pos != std::string::npos)
77      version_str = version_str.substr(0, pos);
78    Version os_version(version_str);
79    if (os_version.IsValid() && os_version.components().size() >= 2) {
80      const std::vector<uint16>& version_numbers = os_version.components();
81      if (version_numbers[0] == 5)
82        sub_version = kWinXP;
83      else if (version_numbers[0] == 6 && version_numbers[1] == 0)
84        sub_version = kWinVista;
85      else if (version_numbers[0] == 6 && version_numbers[1] == 1)
86        sub_version = kWin7;
87      else if (version_numbers[0] == 6 && version_numbers[1] == 2)
88        sub_version = kWin8;
89    }
90  }
91  int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus;
92  switch (status) {
93    case kGpuFeatureEnabled:
94      break;
95    case kGpuFeatureBlacklisted:
96      entry_index++;
97      break;
98    case kGpuFeatureDisabled:
99      entry_index += 2;
100      break;
101  }
102  return entry_index;
103}
104#endif  // OS_WIN
105
106// Send UMA histograms about the enabled features and GPU properties.
107void UpdateStats(const gpu::GPUInfo& gpu_info,
108                 const gpu::GpuBlacklist* blacklist,
109                 const std::set<int>& blacklisted_features) {
110  uint32 max_entry_id = blacklist->max_entry_id();
111  if (max_entry_id == 0) {
112    // GPU Blacklist was not loaded.  No need to go further.
113    return;
114  }
115
116  const base::CommandLine& command_line =
117      *base::CommandLine::ForCurrentProcess();
118  bool disabled = false;
119
120  // Use entry 0 to capture the total number of times that data
121  // was recorded in this histogram in order to have a convenient
122  // denominator to compute blacklist percentages for the rest of the
123  // entries.
124  UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
125      0, max_entry_id + 1);
126
127  if (blacklisted_features.size() != 0) {
128    std::vector<uint32> flag_entries;
129    blacklist->GetDecisionEntries(&flag_entries, disabled);
130    DCHECK_GT(flag_entries.size(), 0u);
131    for (size_t i = 0; i < flag_entries.size(); ++i) {
132      UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
133          flag_entries[i], max_entry_id + 1);
134    }
135  }
136
137  // This counts how many users are affected by a disabled entry - this allows
138  // us to understand the impact of an entry before enable it.
139  std::vector<uint32> flag_disabled_entries;
140  disabled = true;
141  blacklist->GetDecisionEntries(&flag_disabled_entries, disabled);
142  for (uint32 disabled_entry : flag_disabled_entries) {
143    UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
144        disabled_entry, max_entry_id + 1);
145  }
146
147  const gpu::GpuFeatureType kGpuFeatures[] = {
148      gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS,
149      gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING, gpu::GPU_FEATURE_TYPE_WEBGL};
150  const std::string kGpuBlacklistFeatureHistogramNames[] = {
151      "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas",
152      "GPU.BlacklistFeatureTestResults.GpuCompositing",
153      "GPU.BlacklistFeatureTestResults.Webgl", };
154  const bool kGpuFeatureUserFlags[] = {
155      command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
156      command_line.HasSwitch(switches::kDisableGpu),
157      command_line.HasSwitch(switches::kDisableExperimentalWebGL), };
158#if defined(OS_WIN)
159  const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
160      "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
161      "GPU.BlacklistFeatureTestResultsWindows.GpuCompositing",
162      "GPU.BlacklistFeatureTestResultsWindows.Webgl", };
163#endif
164  const size_t kNumFeatures =
165      sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType);
166  for (size_t i = 0; i < kNumFeatures; ++i) {
167    // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is
168    // expected if the macro is used within a loop.
169    GpuFeatureStatus value = kGpuFeatureEnabled;
170    if (blacklisted_features.count(kGpuFeatures[i]))
171      value = kGpuFeatureBlacklisted;
172    else if (kGpuFeatureUserFlags[i])
173      value = kGpuFeatureDisabled;
174    base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
175        kGpuBlacklistFeatureHistogramNames[i],
176        1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1,
177        base::HistogramBase::kUmaTargetedHistogramFlag);
178    histogram_pointer->Add(value);
179#if defined(OS_WIN)
180    histogram_pointer = base::LinearHistogram::FactoryGet(
181        kGpuBlacklistFeatureHistogramNamesWin[i],
182        1, kNumWinSubVersions * kGpuFeatureNumStatus,
183        kNumWinSubVersions * kGpuFeatureNumStatus + 1,
184        base::HistogramBase::kUmaTargetedHistogramFlag);
185    histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value));
186#endif
187  }
188
189  UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
190      gpu_info.gl_reset_notification_strategy);
191}
192
193// Combine the integers into a string, seperated by ','.
194std::string IntSetToString(const std::set<int>& list) {
195  std::string rt;
196  for (std::set<int>::const_iterator it = list.begin();
197       it != list.end(); ++it) {
198    if (!rt.empty())
199      rt += ",";
200    rt += base::IntToString(*it);
201  }
202  return rt;
203}
204
205#if defined(OS_MACOSX)
206void DisplayReconfigCallback(CGDirectDisplayID display,
207                             CGDisplayChangeSummaryFlags flags,
208                             void* gpu_data_manager) {
209  if (flags == kCGDisplayBeginConfigurationFlag)
210    return; // This call contains no information about the display change
211
212  GpuDataManagerImpl* manager =
213      reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
214  DCHECK(manager);
215
216  // Display change.
217  bool display_changed = false;
218  uint32_t displayCount;
219  CGGetActiveDisplayList(0, NULL, &displayCount);
220  if (displayCount != manager->GetDisplayCount()) {
221    manager->SetDisplayCount(displayCount);
222    display_changed = true;
223  }
224
225  // Gpu change.
226  bool gpu_changed = false;
227  if (flags & kCGDisplayAddFlag) {
228    uint32 vendor_id, device_id;
229    if (gpu::CollectGpuID(&vendor_id, &device_id) == gpu::kCollectInfoSuccess) {
230      gpu_changed = manager->UpdateActiveGpu(vendor_id, device_id);
231    }
232  }
233
234  if (display_changed || gpu_changed)
235    manager->HandleGpuSwitch();
236}
237#endif  // OS_MACOSX
238
239// Block all domains' use of 3D APIs for this many milliseconds if
240// approaching a threshold where system stability might be compromised.
241const int64 kBlockAllDomainsMs = 10000;
242const int kNumResetsWithinDuration = 1;
243
244// Enums for UMA histograms.
245enum BlockStatusHistogram {
246  BLOCK_STATUS_NOT_BLOCKED,
247  BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
248  BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
249  BLOCK_STATUS_MAX
250};
251
252}  // namespace anonymous
253
254void GpuDataManagerImplPrivate::InitializeForTesting(
255    const std::string& gpu_blacklist_json,
256    const gpu::GPUInfo& gpu_info) {
257  // This function is for testing only, so disable histograms.
258  update_histograms_ = false;
259
260  // Prevent all further initialization.
261  finalized_ = true;
262
263  InitializeImpl(gpu_blacklist_json, std::string(), gpu_info);
264}
265
266bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
267#if defined(OS_CHROMEOS)
268  if (feature == gpu::GPU_FEATURE_TYPE_PANEL_FITTING &&
269      base::CommandLine::ForCurrentProcess()->HasSwitch(
270          switches::kDisablePanelFitting)) {
271    return true;
272  }
273#endif  // OS_CHROMEOS
274  if (use_swiftshader_ || ShouldUseWarp()) {
275    // Skia's software rendering is probably more efficient than going through
276    // software emulation of the GPU, so use that.
277    if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
278      return true;
279    return false;
280  }
281
282  return (blacklisted_features_.count(feature) == 1);
283}
284
285bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
286  return (gpu_driver_bugs_.count(feature) == 1);
287}
288
289size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
290  if (use_swiftshader_ || ShouldUseWarp())
291    return 1;
292  return blacklisted_features_.size();
293}
294
295void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
296  display_count_ = display_count;
297}
298
299unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
300  return display_count_;
301}
302
303gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
304  return gpu_info_;
305}
306
307void GpuDataManagerImplPrivate::GetGpuProcessHandles(
308    const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
309  GpuProcessHost::GetProcessHandles(callback);
310}
311
312bool GpuDataManagerImplPrivate::GpuAccessAllowed(
313    std::string* reason) const {
314  if (use_swiftshader_ || ShouldUseWarp())
315    return true;
316
317  if (!gpu_process_accessible_) {
318    if (reason) {
319      *reason = "GPU process launch failed.";
320    }
321    return false;
322  }
323
324  if (card_blacklisted_) {
325    if (reason) {
326      *reason = "GPU access is disabled ";
327      base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
328      if (command_line->HasSwitch(switches::kDisableGpu))
329        *reason += "through commandline switch --disable-gpu.";
330      else
331        *reason += "in chrome://settings.";
332    }
333    return false;
334  }
335
336  // We only need to block GPU process if more features are disallowed other
337  // than those in the preliminary gpu feature flags because the latter work
338  // through renderer commandline switches.
339  std::set<int> features = preliminary_blacklisted_features_;
340  gpu::MergeFeatureSets(&features, blacklisted_features_);
341  if (features.size() > preliminary_blacklisted_features_.size()) {
342    if (reason) {
343      *reason = "Features are disabled upon full but not preliminary GPU info.";
344    }
345    return false;
346  }
347
348  if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) {
349    // On Linux, we use cached GL strings to make blacklist decsions at browser
350    // startup time. We need to launch the GPU process to validate these
351    // strings even if all features are blacklisted. If all GPU features are
352    // disabled, the GPU process will only initialize GL bindings, create a GL
353    // context, and collect full GPU info.
354#if !defined(OS_LINUX)
355    if (reason) {
356      *reason = "All GPU features are blacklisted.";
357    }
358    return false;
359#endif
360  }
361
362  return true;
363}
364
365void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
366  if (complete_gpu_info_already_requested_ || IsCompleteGpuInfoAvailable())
367    return;
368  complete_gpu_info_already_requested_ = true;
369
370  GpuProcessHost::SendOnIO(
371#if defined(OS_WIN)
372      GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
373#else
374      GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
375#endif
376      CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
377      new GpuMsg_CollectGraphicsInfo());
378}
379
380bool GpuDataManagerImplPrivate::IsEssentialGpuInfoAvailable() const {
381  if (gpu_info_.basic_info_state == gpu::kCollectInfoNone ||
382      gpu_info_.context_info_state == gpu::kCollectInfoNone) {
383    return false;
384  }
385  return true;
386}
387
388bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
389#if defined(OS_WIN)
390  if (gpu_info_.dx_diagnostics_info_state == gpu::kCollectInfoNone)
391    return false;
392#endif
393  return IsEssentialGpuInfoAvailable();
394}
395
396void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
397  GpuProcessHost::SendOnIO(
398      GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
399      CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
400      new GpuMsg_GetVideoMemoryUsageStats());
401}
402
403bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
404  return use_swiftshader_;
405}
406
407void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
408    const base::FilePath& path) {
409  swiftshader_path_ = path;
410  EnableSwiftShaderIfNecessary();
411}
412
413bool GpuDataManagerImplPrivate::ShouldUseWarp() const {
414  return use_warp_ ||
415      CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp);
416}
417
418void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
419  GpuDataManagerImpl::UnlockedSession session(owner_);
420  observer_list_->AddObserver(observer);
421}
422
423void GpuDataManagerImplPrivate::RemoveObserver(
424    GpuDataManagerObserver* observer) {
425  GpuDataManagerImpl::UnlockedSession session(owner_);
426  observer_list_->RemoveObserver(observer);
427}
428
429void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
430  // This method must do two things:
431  //
432  //  1. If the specific domain is blocked, then unblock it.
433  //
434  //  2. Reset our notion of how many GPU resets have occurred recently.
435  //     This is necessary even if the specific domain was blocked.
436  //     Otherwise, if we call Are3DAPIsBlocked with the same domain right
437  //     after unblocking it, it will probably still be blocked because of
438  //     the recent GPU reset caused by that domain.
439  //
440  // These policies could be refined, but at a certain point the behavior
441  // will become difficult to explain.
442  std::string domain = GetDomainFromURL(url);
443
444  blocked_domains_.erase(domain);
445  timestamps_of_gpu_resets_.clear();
446}
447
448void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
449  GpuProcessHost::SendOnIO(
450      GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
451      CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
452      new GpuMsg_DisableWatchdog);
453}
454
455void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
456                                             const std::string& gl_renderer,
457                                             const std::string& gl_version) {
458  if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
459    return;
460
461  // If GPUInfo already got GL strings, do nothing.  This is for the rare
462  // situation where GPU process collected GL strings before this call.
463  if (!gpu_info_.gl_vendor.empty() ||
464      !gpu_info_.gl_renderer.empty() ||
465      !gpu_info_.gl_version.empty())
466    return;
467
468  gpu::GPUInfo gpu_info = gpu_info_;
469
470  gpu_info.gl_vendor = gl_vendor;
471  gpu_info.gl_renderer = gl_renderer;
472  gpu_info.gl_version = gl_version;
473
474  gpu::CollectDriverInfoGL(&gpu_info);
475
476  UpdateGpuInfo(gpu_info);
477  UpdateGpuSwitchingManager(gpu_info);
478  UpdatePreliminaryBlacklistedFeatures();
479}
480
481void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
482                                             std::string* gl_renderer,
483                                             std::string* gl_version) {
484  DCHECK(gl_vendor && gl_renderer && gl_version);
485
486  *gl_vendor = gpu_info_.gl_vendor;
487  *gl_renderer = gpu_info_.gl_renderer;
488  *gl_version = gpu_info_.gl_version;
489}
490
491void GpuDataManagerImplPrivate::Initialize() {
492  TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
493  if (finalized_) {
494    DVLOG(0) << "GpuDataManagerImpl marked as finalized; skipping Initialize";
495    return;
496  }
497
498  const base::CommandLine* command_line =
499      base::CommandLine::ForCurrentProcess();
500  if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
501    return;
502
503  gpu::GPUInfo gpu_info;
504  if (command_line->GetSwitchValueASCII(
505          switches::kUseGL) == gfx::kGLImplementationOSMesaName) {
506    // If using the OSMesa GL implementation, use fake vendor and device ids to
507    // make sure it never gets blacklisted. This is better than simply
508    // cancelling GPUInfo gathering as it allows us to proceed with loading the
509    // blacklist below which may have non-device specific entries we want to
510    // apply anyways (e.g., OS version blacklisting).
511    gpu_info.gpu.vendor_id = 0xffff;
512    gpu_info.gpu.device_id = 0xffff;
513
514    // Also declare the driver_vendor to be osmesa to be able to specify
515    // exceptions based on driver_vendor==osmesa for some blacklist rules.
516    gpu_info.driver_vendor = gfx::kGLImplementationOSMesaName;
517  } else {
518    TRACE_EVENT0("startup",
519      "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
520    gpu::CollectBasicGraphicsInfo(&gpu_info);
521  }
522#if defined(ARCH_CPU_X86_FAMILY)
523  if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id) {
524    gpu_info.context_info_state = gpu::kCollectInfoNonFatalFailure;
525#if defined(OS_WIN)
526    gpu_info.dx_diagnostics_info_state = gpu::kCollectInfoNonFatalFailure;
527#endif  // OS_WIN
528  }
529#endif  // ARCH_CPU_X86_FAMILY
530
531  std::string gpu_blacklist_string;
532  std::string gpu_driver_bug_list_string;
533  if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist) &&
534      !command_line->HasSwitch(switches::kUseGpuInTests)) {
535    gpu_blacklist_string = gpu::kSoftwareRenderingListJson;
536  }
537  if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
538    gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
539  }
540  InitializeImpl(gpu_blacklist_string,
541                 gpu_driver_bug_list_string,
542                 gpu_info);
543}
544
545void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
546  GetContentClient()->SetGpuInfo(gpu_info_);
547
548  if (gpu_blacklist_) {
549    std::set<int> features = gpu_blacklist_->MakeDecision(
550        gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
551    if (update_histograms_)
552      UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
553
554    UpdateBlacklistedFeatures(features);
555  }
556  if (gpu_driver_bug_list_) {
557    gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
558        gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
559  }
560  gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(
561      &gpu_driver_bugs_, *base::CommandLine::ForCurrentProcess());
562
563  // We have to update GpuFeatureType before notify all the observers.
564  NotifyGpuInfoUpdate();
565}
566
567void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
568  // No further update of gpu_info if falling back to SwiftShader.
569  if (use_swiftshader_ || ShouldUseWarp())
570    return;
571
572  gpu::MergeGPUInfo(&gpu_info_, gpu_info);
573  if (IsCompleteGpuInfoAvailable())
574    complete_gpu_info_already_requested_ = true;
575
576  UpdateGpuInfoHelper();
577}
578
579void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
580    const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
581  GpuDataManagerImpl::UnlockedSession session(owner_);
582  observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
583                         video_memory_usage_stats);
584}
585
586void GpuDataManagerImplPrivate::AppendRendererCommandLine(
587    base::CommandLine* command_line) const {
588  DCHECK(command_line);
589
590  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
591      !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
592    command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
593#if defined(ENABLE_WEBRTC)
594  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
595      !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding))
596    command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
597#endif
598
599#if defined(USE_AURA)
600  if (!CanUseGpuBrowserCompositor())
601    command_line->AppendSwitch(switches::kDisableGpuCompositing);
602#endif
603}
604
605void GpuDataManagerImplPrivate::AppendGpuCommandLine(
606    base::CommandLine* command_line) const {
607  DCHECK(command_line);
608
609  std::string use_gl =
610      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
611          switches::kUseGL);
612  base::FilePath swiftshader_path =
613      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
614          switches::kSwiftShaderPath);
615  if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
616    command_line->AppendSwitch(switches::kDisableD3D11);
617  if (use_swiftshader_) {
618    command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
619    if (swiftshader_path.empty())
620      swiftshader_path = swiftshader_path_;
621  } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
622              IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING) ||
623              IsFeatureBlacklisted(
624                  gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
625             (use_gl == "any")) {
626    command_line->AppendSwitchASCII(
627        switches::kUseGL, gfx::kGLImplementationOSMesaName);
628  } else if (!use_gl.empty()) {
629    command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
630  }
631  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
632    command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
633  else
634    command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
635
636  if (!swiftshader_path.empty()) {
637    command_line->AppendSwitchPath(switches::kSwiftShaderPath,
638                                   swiftshader_path);
639  }
640
641  if (!gpu_driver_bugs_.empty()) {
642    command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
643                                    IntSetToString(gpu_driver_bugs_));
644  }
645
646  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
647      !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
648    command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
649  }
650#if defined(ENABLE_WEBRTC)
651  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
652      !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
653    command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
654  }
655#endif
656
657  // Pass GPU and driver information to GPU process. We try to avoid full GPU
658  // info collection at GPU process startup, but we need gpu vendor_id,
659  // device_id, driver_vendor, driver_version for deciding whether we need to
660  // collect full info (on Linux) and for crash reporting purpose.
661  command_line->AppendSwitchASCII(switches::kGpuVendorID,
662      base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
663  command_line->AppendSwitchASCII(switches::kGpuDeviceID,
664      base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
665  command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
666      gpu_info_.driver_vendor);
667  command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
668      gpu_info_.driver_version);
669
670  if (ShouldUseWarp())
671    command_line->AppendSwitch(switches::kUseWarp);
672}
673
674void GpuDataManagerImplPrivate::AppendPluginCommandLine(
675    base::CommandLine* command_line) const {
676  DCHECK(command_line);
677
678#if defined(OS_MACOSX)
679  // TODO(jbauman): Add proper blacklist support for core animation plugins so
680  // special-casing this video card won't be necessary. See
681  // http://crbug.com/134015
682  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING)) {
683    if (!command_line->HasSwitch(
684           switches::kDisableCoreAnimationPlugins))
685      command_line->AppendSwitch(
686          switches::kDisableCoreAnimationPlugins);
687  }
688#endif
689}
690
691void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
692    WebPreferences* prefs) const {
693  DCHECK(prefs);
694
695  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) {
696    prefs->experimental_webgl_enabled = false;
697    prefs->pepper_3d_enabled = false;
698  }
699  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D))
700    prefs->flash_3d_enabled = false;
701  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
702    prefs->flash_stage3d_enabled = false;
703    prefs->flash_stage3d_baseline_enabled = false;
704  }
705  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
706    prefs->flash_stage3d_baseline_enabled = false;
707  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
708    prefs->accelerated_2d_canvas_enabled = false;
709  if (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTISAMPLING) ||
710      (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTIMONITOR_MULTISAMPLING) &&
711          display_count_ > 1))
712    prefs->gl_multisampling_enabled = false;
713
714#if defined(USE_AURA)
715  if (!CanUseGpuBrowserCompositor()) {
716    prefs->accelerated_2d_canvas_enabled = false;
717    prefs->pepper_3d_enabled = false;
718  }
719#endif
720
721  if (!IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
722      !base::CommandLine::ForCurrentProcess()->HasSwitch(
723          switches::kDisableAcceleratedVideoDecode)) {
724    prefs->pepper_accelerated_video_decode_enabled = true;
725  }
726}
727
728void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
729  card_blacklisted_ = true;
730
731  for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
732    blacklisted_features_.insert(i);
733
734  EnableWarpIfNecessary();
735  EnableSwiftShaderIfNecessary();
736  NotifyGpuInfoUpdate();
737}
738
739std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
740  if (gpu_blacklist_)
741    return gpu_blacklist_->version();
742  return "0";
743}
744
745std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
746  if (gpu_driver_bug_list_)
747    return gpu_driver_bug_list_->version();
748  return "0";
749}
750
751void GpuDataManagerImplPrivate::GetBlacklistReasons(
752    base::ListValue* reasons) const {
753  if (gpu_blacklist_)
754    gpu_blacklist_->GetReasons(reasons, "disabledFeatures");
755  if (gpu_driver_bug_list_)
756    gpu_driver_bug_list_->GetReasons(reasons, "workarounds");
757}
758
759void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
760    base::ListValue* workarounds) const {
761  for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
762       it != gpu_driver_bugs_.end(); ++it) {
763    workarounds->AppendString(
764        gpu::GpuDriverBugWorkaroundTypeToString(
765            static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
766  }
767}
768
769void GpuDataManagerImplPrivate::AddLogMessage(
770    int level, const std::string& header, const std::string& message) {
771  log_messages_.push_back(LogMessage(level, header, message));
772}
773
774void GpuDataManagerImplPrivate::ProcessCrashed(
775    base::TerminationStatus exit_code) {
776  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
777    // Unretained is ok, because it's posted to UI thread, the thread
778    // where the singleton GpuDataManagerImpl lives until the end.
779    BrowserThread::PostTask(
780        BrowserThread::UI,
781        FROM_HERE,
782        base::Bind(&GpuDataManagerImpl::ProcessCrashed,
783                   base::Unretained(owner_),
784                   exit_code));
785    return;
786  }
787  {
788    gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
789    GpuDataManagerImpl::UnlockedSession session(owner_);
790    observer_list_->Notify(
791        &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
792  }
793}
794
795base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
796  base::ListValue* value = new base::ListValue;
797  for (size_t ii = 0; ii < log_messages_.size(); ++ii) {
798    base::DictionaryValue* dict = new base::DictionaryValue();
799    dict->SetInteger("level", log_messages_[ii].level);
800    dict->SetString("header", log_messages_[ii].header);
801    dict->SetString("message", log_messages_[ii].message);
802    value->Append(dict);
803  }
804  return value;
805}
806
807void GpuDataManagerImplPrivate::HandleGpuSwitch() {
808  GpuDataManagerImpl::UnlockedSession session(owner_);
809  observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
810}
811
812bool GpuDataManagerImplPrivate::UpdateActiveGpu(
813    uint32 vendor_id, uint32 device_id) {
814  if (gpu_info_.gpu.vendor_id == vendor_id &&
815      gpu_info_.gpu.device_id == device_id) {
816    // The primary GPU is active.
817    if (gpu_info_.gpu.active)
818      return false;
819    gpu_info_.gpu.active = true;
820    for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii)
821      gpu_info_.secondary_gpus[ii].active = false;
822  } else {
823    // A secondary GPU is active.
824    for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) {
825      if (gpu_info_.secondary_gpus[ii].vendor_id == vendor_id &&
826          gpu_info_.secondary_gpus[ii].device_id == device_id) {
827        if (gpu_info_.secondary_gpus[ii].active)
828          return false;
829        gpu_info_.secondary_gpus[ii].active = true;
830      } else {
831        gpu_info_.secondary_gpus[ii].active = false;
832      }
833    }
834    gpu_info_.gpu.active = false;
835  }
836  UpdateGpuInfoHelper();
837  return true;
838}
839
840bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
841  if (CommandLine::ForCurrentProcess()->HasSwitch(
842          switches::kDisableGpuCompositing))
843    return false;
844  if (ShouldUseWarp())
845    return true;
846  if (ShouldUseSwiftShader())
847    return false;
848  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
849    return false;
850  return true;
851}
852
853void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
854    const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
855  BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
856}
857
858bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
859                                                 int render_process_id,
860                                                 int render_view_id,
861                                                 ThreeDAPIType requester) {
862  bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
863      GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
864  if (blocked) {
865    // Unretained is ok, because it's posted to UI thread, the thread
866    // where the singleton GpuDataManagerImpl lives until the end.
867    BrowserThread::PostTask(
868        BrowserThread::UI, FROM_HERE,
869        base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
870                   base::Unretained(owner_), url, render_process_id,
871                   render_view_id, requester));
872  }
873
874  return blocked;
875}
876
877void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
878  domain_blocking_enabled_ = false;
879}
880
881// static
882GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
883    GpuDataManagerImpl* owner) {
884  return new GpuDataManagerImplPrivate(owner);
885}
886
887GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
888    GpuDataManagerImpl* owner)
889    : complete_gpu_info_already_requested_(false),
890      observer_list_(new GpuDataManagerObserverList),
891      use_swiftshader_(false),
892      use_warp_(false),
893      card_blacklisted_(false),
894      update_histograms_(true),
895      window_count_(0),
896      domain_blocking_enabled_(true),
897      owner_(owner),
898      display_count_(0),
899      gpu_process_accessible_(true),
900      finalized_(false) {
901  DCHECK(owner_);
902  const base::CommandLine* command_line =
903      base::CommandLine::ForCurrentProcess();
904  if (command_line->HasSwitch(switches::kDisableGpu))
905    DisableHardwareAcceleration();
906
907#if defined(OS_MACOSX)
908  CGGetActiveDisplayList (0, NULL, &display_count_);
909  CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
910#endif  // OS_MACOSX
911
912  // For testing only.
913  if (command_line->HasSwitch(switches::kDisableDomainBlockingFor3DAPIs)) {
914    domain_blocking_enabled_ = false;
915  }
916}
917
918GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
919#if defined(OS_MACOSX)
920  CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
921#endif
922}
923
924void GpuDataManagerImplPrivate::InitializeImpl(
925    const std::string& gpu_blacklist_json,
926    const std::string& gpu_driver_bug_list_json,
927    const gpu::GPUInfo& gpu_info) {
928  const bool log_gpu_control_list_decisions =
929      base::CommandLine::ForCurrentProcess()->HasSwitch(
930          switches::kLogGpuControlListDecisions);
931
932  if (!gpu_blacklist_json.empty()) {
933    gpu_blacklist_.reset(gpu::GpuBlacklist::Create());
934    if (log_gpu_control_list_decisions)
935      gpu_blacklist_->enable_control_list_logging("gpu_blacklist");
936    bool success = gpu_blacklist_->LoadList(
937        gpu_blacklist_json, gpu::GpuControlList::kCurrentOsOnly);
938    DCHECK(success);
939  }
940  if (!gpu_driver_bug_list_json.empty()) {
941    gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create());
942    if (log_gpu_control_list_decisions)
943      gpu_driver_bug_list_->enable_control_list_logging("gpu_driver_bug_list");
944    bool success = gpu_driver_bug_list_->LoadList(
945        gpu_driver_bug_list_json, gpu::GpuControlList::kCurrentOsOnly);
946    DCHECK(success);
947  }
948
949  gpu_info_ = gpu_info;
950  UpdateGpuInfo(gpu_info);
951  UpdateGpuSwitchingManager(gpu_info);
952  UpdatePreliminaryBlacklistedFeatures();
953}
954
955void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
956    const std::set<int>& features) {
957  blacklisted_features_ = features;
958
959  // Force disable using the GPU for these features, even if they would
960  // otherwise be allowed.
961  if (card_blacklisted_) {
962    blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING);
963    blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
964  }
965
966  EnableWarpIfNecessary();
967  EnableSwiftShaderIfNecessary();
968}
969
970void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
971  preliminary_blacklisted_features_ = blacklisted_features_;
972}
973
974void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
975    const gpu::GPUInfo& gpu_info) {
976  ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
977      gpu_info.secondary_gpus.size() + 1);
978
979  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
980    if (gpu_driver_bugs_.count(gpu::FORCE_DISCRETE_GPU) == 1)
981      ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
982    else if (gpu_driver_bugs_.count(gpu::FORCE_INTEGRATED_GPU) == 1)
983      ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
984  }
985}
986
987void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
988  observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
989}
990
991void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
992  if (ShouldUseWarp())
993    return;
994
995  if (!GpuAccessAllowed(NULL) ||
996      blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
997    if (!swiftshader_path_.empty() &&
998        !base::CommandLine::ForCurrentProcess()->HasSwitch(
999             switches::kDisableSoftwareRasterizer))
1000      use_swiftshader_ = true;
1001  }
1002}
1003
1004void GpuDataManagerImplPrivate::EnableWarpIfNecessary() {
1005#if defined(OS_WIN)
1006  if (use_warp_)
1007    return;
1008  // We should only use WARP if we are unable to use the regular GPU for
1009  // compositing, and if we in Metro mode.
1010  use_warp_ =
1011      CommandLine::ForCurrentProcess()->HasSwitch(switches::kViewerConnect) &&
1012      !CanUseGpuBrowserCompositor();
1013#endif
1014}
1015
1016void GpuDataManagerImplPrivate::ForceWarpModeForTesting() {
1017  use_warp_ = true;
1018}
1019
1020std::string GpuDataManagerImplPrivate::GetDomainFromURL(
1021    const GURL& url) const {
1022  // For the moment, we just use the host, or its IP address, as the
1023  // entry in the set, rather than trying to figure out the top-level
1024  // domain. This does mean that a.foo.com and b.foo.com will be
1025  // treated independently in the blocking of a given domain, but it
1026  // would require a third-party library to reliably figure out the
1027  // top-level domain from a URL.
1028  if (!url.has_host()) {
1029    return std::string();
1030  }
1031
1032  return url.host();
1033}
1034
1035void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
1036    const GURL& url,
1037    GpuDataManagerImpl::DomainGuilt guilt,
1038    base::Time at_time) {
1039  if (!domain_blocking_enabled_)
1040    return;
1041
1042  std::string domain = GetDomainFromURL(url);
1043
1044  DomainBlockEntry& entry = blocked_domains_[domain];
1045  entry.last_guilt = guilt;
1046  timestamps_of_gpu_resets_.push_back(at_time);
1047}
1048
1049GpuDataManagerImpl::DomainBlockStatus
1050GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
1051    const GURL& url, base::Time at_time) const {
1052  if (!domain_blocking_enabled_)
1053    return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
1054
1055  // Note: adjusting the policies in this code will almost certainly
1056  // require adjusting the associated unit tests.
1057  std::string domain = GetDomainFromURL(url);
1058
1059  DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
1060  if (iter != blocked_domains_.end()) {
1061    // Err on the side of caution, and assume that if a particular
1062    // domain shows up in the block map, it's there for a good
1063    // reason and don't let its presence there automatically expire.
1064
1065    UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1066                              BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
1067                              BLOCK_STATUS_MAX);
1068
1069    return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
1070  }
1071
1072  // Look at the timestamps of the recent GPU resets to see if there are
1073  // enough within the threshold which would cause us to blacklist all
1074  // domains. This doesn't need to be overly precise -- if time goes
1075  // backward due to a system clock adjustment, that's fine.
1076  //
1077  // TODO(kbr): make this pay attention to the TDR thresholds in the
1078  // Windows registry, but make sure it continues to be testable.
1079  {
1080    std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
1081    int num_resets_within_timeframe = 0;
1082    while (iter != timestamps_of_gpu_resets_.end()) {
1083      base::Time time = *iter;
1084      base::TimeDelta delta_t = at_time - time;
1085
1086      // If this entry has "expired", just remove it.
1087      if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
1088        iter = timestamps_of_gpu_resets_.erase(iter);
1089        continue;
1090      }
1091
1092      ++num_resets_within_timeframe;
1093      ++iter;
1094    }
1095
1096    if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
1097      UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1098                                BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
1099                                BLOCK_STATUS_MAX);
1100
1101      return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
1102    }
1103  }
1104
1105  UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1106                            BLOCK_STATUS_NOT_BLOCKED,
1107                            BLOCK_STATUS_MAX);
1108
1109  return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
1110}
1111
1112int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
1113  return kBlockAllDomainsMs;
1114}
1115
1116void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
1117                                                   int render_process_id,
1118                                                   int render_view_id,
1119                                                   ThreeDAPIType requester) {
1120  GpuDataManagerImpl::UnlockedSession session(owner_);
1121  observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
1122                         url, render_process_id, render_view_id, requester);
1123}
1124
1125void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
1126  gpu_process_accessible_ = false;
1127  gpu_info_.context_info_state = gpu::kCollectInfoFatalFailure;
1128#if defined(OS_WIN)
1129  gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoFatalFailure;
1130#endif
1131  complete_gpu_info_already_requested_ = true;
1132  // Some observers might be waiting.
1133  NotifyGpuInfoUpdate();
1134}
1135
1136}  // namespace content
1137