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/compositor_util.h"
6
7#include "base/command_line.h"
8#include "base/logging.h"
9#include "base/metrics/field_trial.h"
10#include "base/strings/string_number_conversions.h"
11#include "build/build_config.h"
12#include "cc/base/switches.h"
13#include "content/browser/gpu/gpu_data_manager_impl.h"
14#include "content/public/common/content_switches.h"
15#include "gpu/config/gpu_feature_type.h"
16
17namespace content {
18
19namespace {
20
21static bool IsGpuRasterizationBlacklisted() {
22  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
23  return manager->IsFeatureBlacklisted(
24        gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION);
25}
26
27const char* kGpuCompositingFeatureName = "gpu_compositing";
28const char* kWebGLFeatureName = "webgl";
29const char* kRasterizationFeatureName = "rasterization";
30const char* kThreadedRasterizationFeatureName = "threaded_rasterization";
31const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";
32
33const int kMinRasterThreads = 1;
34const int kMaxRasterThreads = 64;
35
36struct GpuFeatureInfo {
37  std::string name;
38  bool blocked;
39  bool disabled;
40  std::string disabled_description;
41  bool fallback_to_software;
42};
43
44const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
45  const base::CommandLine& command_line =
46      *base::CommandLine::ForCurrentProcess();
47  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
48
49  const GpuFeatureInfo kGpuFeatureInfo[] = {
50      {
51          "2d_canvas",
52          manager->IsFeatureBlacklisted(
53              gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
54          command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) ||
55          !GpuDataManagerImpl::GetInstance()->
56              GetGPUInfo().SupportsAccelerated2dCanvas(),
57          "Accelerated 2D canvas is unavailable: either disabled at the command"
58          " line or not supported by the current system.",
59          true
60      },
61      {
62          kGpuCompositingFeatureName,
63          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING),
64          command_line.HasSwitch(switches::kDisableGpuCompositing),
65          "Gpu compositing has been disabled, either via about:flags or"
66          " command line. The browser will fall back to software compositing"
67          " and hardware acceleration will be unavailable.",
68          true
69      },
70      {
71          kWebGLFeatureName,
72          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL),
73          command_line.HasSwitch(switches::kDisableExperimentalWebGL),
74          "WebGL has been disabled, either via about:flags or command line.",
75          false
76      },
77      {
78          "flash_3d",
79          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D),
80          command_line.HasSwitch(switches::kDisableFlash3d),
81          "Using 3d in flash has been disabled, either via about:flags or"
82          " command line.",
83          true
84      },
85      {
86          "flash_stage3d",
87          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
88          command_line.HasSwitch(switches::kDisableFlashStage3d),
89          "Using Stage3d in Flash has been disabled, either via about:flags or"
90          " command line.",
91          true
92      },
93      {
94          "flash_stage3d_baseline",
95          manager->IsFeatureBlacklisted(
96              gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE) ||
97          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
98          command_line.HasSwitch(switches::kDisableFlashStage3d),
99          "Using Stage3d Baseline profile in Flash has been disabled, either"
100          " via about:flags or command line.",
101          true
102      },
103      {
104          "video_decode",
105          manager->IsFeatureBlacklisted(
106              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
107          command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
108          "Accelerated video decode has been disabled, either via about:flags"
109          " or command line.",
110          true
111      },
112#if defined(ENABLE_WEBRTC)
113      {
114          "video_encode",
115          manager->IsFeatureBlacklisted(
116              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE),
117          command_line.HasSwitch(switches::kDisableWebRtcHWEncoding),
118          "Accelerated video encode has been disabled, either via about:flags"
119          " or command line.",
120          true
121      },
122#endif
123#if defined(OS_CHROMEOS)
124      {
125          "panel_fitting",
126          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_PANEL_FITTING),
127          command_line.HasSwitch(switches::kDisablePanelFitting),
128          "Panel fitting has been disabled, either via about:flags or command"
129          " line.",
130          false
131      },
132#endif
133      {
134          kRasterizationFeatureName,
135          IsGpuRasterizationBlacklisted() &&
136          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled(),
137          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled() &&
138          !IsGpuRasterizationBlacklisted(),
139          "Accelerated rasterization has been disabled, either via about:flags"
140          " or command line.",
141          true
142      },
143      {
144          kThreadedRasterizationFeatureName,
145          false,
146          !IsImplSidePaintingEnabled(),
147          "Threaded rasterization has not been enabled or"
148          " is not supported by the current system.",
149          false
150      },
151      {
152          kMultipleRasterThreadsFeatureName,
153          false,
154          NumberOfRendererRasterThreads() == 1,
155          "Raster is using a single thread.",
156          false
157      },
158  };
159  DCHECK(index < arraysize(kGpuFeatureInfo));
160  *eof = (index == arraysize(kGpuFeatureInfo) - 1);
161  return kGpuFeatureInfo[index];
162}
163
164}  // namespace
165
166bool IsPinchVirtualViewportEnabled() {
167  const base::CommandLine& command_line =
168      *base::CommandLine::ForCurrentProcess();
169
170  // Command line switches take precedence over platform default.
171  if (command_line.HasSwitch(cc::switches::kDisablePinchVirtualViewport))
172    return false;
173  if (command_line.HasSwitch(cc::switches::kEnablePinchVirtualViewport))
174    return true;
175
176#if defined(OS_CHROMEOS)
177  return true;
178#else
179  return false;
180#endif
181}
182
183bool IsDelegatedRendererEnabled() {
184  const base::CommandLine& command_line =
185      *base::CommandLine::ForCurrentProcess();
186  bool enabled = false;
187
188#if defined(USE_AURA) || defined(OS_MACOSX)
189  // Enable on Aura and Mac.
190  enabled = true;
191#endif
192
193  // Flags override.
194  enabled |= command_line.HasSwitch(switches::kEnableDelegatedRenderer);
195  enabled &= !command_line.HasSwitch(switches::kDisableDelegatedRenderer);
196  return enabled;
197}
198
199bool IsImplSidePaintingEnabled() {
200  const base::CommandLine& command_line =
201      *base::CommandLine::ForCurrentProcess();
202
203  if (command_line.HasSwitch(switches::kDisableImplSidePainting))
204    return false;
205  else if (command_line.HasSwitch(switches::kEnableImplSidePainting))
206    return true;
207  else if (command_line.HasSwitch(
208      switches::kEnableBleedingEdgeRenderingFastPaths))
209    return true;
210
211  return true;
212}
213
214int NumberOfRendererRasterThreads() {
215  int num_raster_threads = 1;
216
217  int force_num_raster_threads = ForceNumberOfRendererRasterThreads();
218  if (force_num_raster_threads)
219    num_raster_threads = force_num_raster_threads;
220
221  return num_raster_threads;
222}
223
224int ForceNumberOfRendererRasterThreads() {
225  const base::CommandLine& command_line =
226      *base::CommandLine::ForCurrentProcess();
227
228  if (!command_line.HasSwitch(switches::kNumRasterThreads))
229    return 0;
230  std::string string_value =
231      command_line.GetSwitchValueASCII(switches::kNumRasterThreads);
232  int force_num_raster_threads = 0;
233  if (base::StringToInt(string_value, &force_num_raster_threads) &&
234      force_num_raster_threads >= kMinRasterThreads &&
235      force_num_raster_threads <= kMaxRasterThreads) {
236    return force_num_raster_threads;
237  } else {
238    LOG(WARNING) << "Failed to parse switch " <<
239        switches::kNumRasterThreads  << ": " << string_value;
240    return 0;
241  }
242}
243
244bool IsGpuRasterizationEnabled() {
245  const base::CommandLine& command_line =
246      *base::CommandLine::ForCurrentProcess();
247
248  if (!IsImplSidePaintingEnabled())
249    return false;
250
251  if (command_line.HasSwitch(switches::kDisableGpuRasterization))
252    return false;
253  else if (command_line.HasSwitch(switches::kEnableGpuRasterization))
254    return true;
255
256  if (IsGpuRasterizationBlacklisted()) {
257    return false;
258  }
259
260  return true;
261}
262
263bool IsForceGpuRasterizationEnabled() {
264  const base::CommandLine& command_line =
265      *base::CommandLine::ForCurrentProcess();
266
267  if (!IsImplSidePaintingEnabled())
268    return false;
269
270  return command_line.HasSwitch(switches::kForceGpuRasterization);
271}
272
273bool UseSurfacesEnabled() {
274  const base::CommandLine& command_line =
275      *base::CommandLine::ForCurrentProcess();
276
277  return command_line.HasSwitch(switches::kUseSurfaces);
278}
279
280base::Value* GetFeatureStatus() {
281  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
282  std::string gpu_access_blocked_reason;
283  bool gpu_access_blocked =
284      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
285
286  base::DictionaryValue* feature_status_dict = new base::DictionaryValue();
287
288  bool eof = false;
289  for (size_t i = 0; !eof; ++i) {
290    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
291    std::string status;
292    if (gpu_feature_info.disabled) {
293      status = "disabled";
294      if (gpu_feature_info.fallback_to_software)
295        status += "_software";
296      else
297        status += "_off";
298      if (gpu_feature_info.name == kThreadedRasterizationFeatureName)
299        status += "_ok";
300    } else if (gpu_feature_info.blocked ||
301               gpu_access_blocked) {
302      status = "unavailable";
303      if (gpu_feature_info.fallback_to_software)
304        status += "_software";
305      else
306        status += "_off";
307    } else {
308      status = "enabled";
309      if (gpu_feature_info.name == kWebGLFeatureName &&
310          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
311        status += "_readback";
312      if (gpu_feature_info.name == kRasterizationFeatureName) {
313        if (IsForceGpuRasterizationEnabled())
314          status += "_force";
315      }
316      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName) {
317        if (ForceNumberOfRendererRasterThreads() > 0)
318          status += "_force";
319      }
320      if (gpu_feature_info.name == kThreadedRasterizationFeatureName ||
321          gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
322        status += "_on";
323    }
324    if (gpu_feature_info.name == kWebGLFeatureName &&
325        (gpu_feature_info.blocked || gpu_access_blocked) &&
326        manager->ShouldUseSwiftShader()) {
327      status = "unavailable_software";
328    }
329
330    feature_status_dict->SetString(
331        gpu_feature_info.name.c_str(), status.c_str());
332  }
333  return feature_status_dict;
334}
335
336base::Value* GetProblems() {
337  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
338  std::string gpu_access_blocked_reason;
339  bool gpu_access_blocked =
340      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
341
342  base::ListValue* problem_list = new base::ListValue();
343  manager->GetBlacklistReasons(problem_list);
344
345  if (gpu_access_blocked) {
346    base::DictionaryValue* problem = new base::DictionaryValue();
347    problem->SetString("description",
348        "GPU process was unable to boot: " + gpu_access_blocked_reason);
349    problem->Set("crBugs", new base::ListValue());
350    problem->Set("webkitBugs", new base::ListValue());
351    base::ListValue* disabled_features = new base::ListValue();
352    disabled_features->AppendString("all");
353    problem->Set("affectedGpuSettings", disabled_features);
354    problem->SetString("tag", "disabledFeatures");
355    problem_list->Insert(0, problem);
356  }
357
358  bool eof = false;
359  for (size_t i = 0; !eof; ++i) {
360    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
361    if (gpu_feature_info.disabled) {
362      base::DictionaryValue* problem = new base::DictionaryValue();
363      problem->SetString(
364          "description", gpu_feature_info.disabled_description);
365      problem->Set("crBugs", new base::ListValue());
366      problem->Set("webkitBugs", new base::ListValue());
367      base::ListValue* disabled_features = new base::ListValue();
368      disabled_features->AppendString(gpu_feature_info.name);
369      problem->Set("affectedGpuSettings", disabled_features);
370      problem->SetString("tag", "disabledFeatures");
371      problem_list->Append(problem);
372    }
373  }
374  return problem_list;
375}
376
377base::Value* GetDriverBugWorkarounds() {
378  base::ListValue* workaround_list = new base::ListValue();
379  GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds(workaround_list);
380  return workaround_list;
381}
382
383}  // namespace content
384