// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/gpu/compositor_util.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/public/common/content_switches.h"
#include "gpu/config/gpu_feature_type.h"
namespace content {
namespace {
struct GpuFeatureInfo {
std::string name;
uint32 blocked;
bool disabled;
std::string disabled_description;
bool fallback_to_software;
};
#if defined(OS_CHROMEOS)
const size_t kNumFeatures = 14;
#else
const size_t kNumFeatures = 13;
#endif
const GpuFeatureInfo GetGpuFeatureInfo(size_t index) {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
const GpuFeatureInfo kGpuFeatureInfo[] = {
{
"2d_canvas",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) ||
!GpuDataManagerImpl::GetInstance()->
GetGPUInfo().SupportsAccelerated2dCanvas(),
"Accelerated 2D canvas is unavailable: either disabled at the command"
" line or not supported by the current system.",
true
},
{
"compositing",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING),
command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
"Accelerated compositing has been disabled, either via about:flags or"
" command line. This adversely affects performance of all hardware"
" accelerated features.",
true
},
{
"3d_css",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS),
command_line.HasSwitch(switches::kDisableAcceleratedLayers),
"Accelerated layers have been disabled at the command line.",
false
},
{
"css_animation",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS),
command_line.HasSwitch(cc::switches::kDisableThreadedAnimation) ||
command_line.HasSwitch(switches::kDisableAcceleratedCompositing) ||
command_line.HasSwitch(switches::kDisableAcceleratedLayers),
"Accelerated CSS animation has been disabled at the command line.",
true
},
{
"webgl",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL),
command_line.HasSwitch(switches::kDisableExperimentalWebGL),
"WebGL has been disabled, either via about:flags or command line.",
false
},
{
"multisampling",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING),
command_line.HasSwitch(switches::kDisableGLMultisampling),
"Multisampling has been disabled, either via about:flags or command"
" line.",
false
},
{
"flash_3d",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D),
command_line.HasSwitch(switches::kDisableFlash3d),
"Using 3d in flash has been disabled, either via about:flags or"
" command line.",
false
},
{
"flash_stage3d",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
command_line.HasSwitch(switches::kDisableFlashStage3d),
"Using Stage3d in Flash has been disabled, either via about:flags or"
" command line.",
false
},
{
"flash_stage3d_baseline",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE) ||
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
command_line.HasSwitch(switches::kDisableFlashStage3d),
"Using Stage3d Baseline profile in Flash has been disabled, either"
" via about:flags or command line.",
false
},
{
"texture_sharing",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING),
command_line.HasSwitch(switches::kDisableImageTransportSurface),
"Sharing textures between processes has been disabled, either via"
" about:flags or command line.",
false
},
{
"video_decode",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
"Accelerated video decode has been disabled, either via about:flags"
" or command line.",
true
},
#if defined(ENABLE_WEBRTC)
{
"video_encode",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE),
command_line.HasSwitch(switches::kDisableWebRtcHWEncoding),
"Accelerated video encode has been disabled, either via about:flags"
" or command line.",
true
},
#endif
{
"video",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO),
command_line.HasSwitch(switches::kDisableAcceleratedVideo) ||
command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
"Accelerated video presentation has been disabled, either via"
" about:flags or command line.",
true
},
#if defined(OS_CHROMEOS)
{
"panel_fitting",
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_PANEL_FITTING),
command_line.HasSwitch(switches::kDisablePanelFitting),
"Panel fitting has been disabled, either via about:flags or command"
" line.",
false
},
#endif
{
"force_compositing_mode",
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE) &&
!IsForceCompositingModeEnabled(),
!IsForceCompositingModeEnabled() &&
!manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE),
"Force compositing mode is off, either disabled at the command"
" line or not supported by the current system.",
false
},
};
return kGpuFeatureInfo[index];
}
bool CanDoAcceleratedCompositing() {
const GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
// Don't use force compositing mode if gpu access has been blocked or
// accelerated compositing is blacklisted.
if (!manager->GpuAccessAllowed(NULL) ||
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
return false;
// Check for SwiftShader.
if (manager->ShouldUseSwiftShader())
return false;
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kDisableAcceleratedCompositing))
return false;
return true;
}
bool IsForceCompositingModeBlacklisted() {
return GpuDataManagerImpl::GetInstance()->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE);
}
} // namespace
bool IsThreadedCompositingEnabled() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
// Command line switches take precedence over blacklist.
if (command_line.HasSwitch(switches::kDisableForceCompositingMode) ||
command_line.HasSwitch(switches::kDisableThreadedCompositing)) {
return false;
} else if (command_line.HasSwitch(switches::kEnableThreadedCompositing)) {
return true;
}
#if defined(USE_AURA)
// We always want threaded compositing on Aura.
return true;
#endif
if (!CanDoAcceleratedCompositing() || IsForceCompositingModeBlacklisted())
return false;
#if defined(OS_MACOSX) || defined(OS_WIN)
// Windows Vista+ has been shipping with TCM enabled at 100% since M24 and
// Mac OSX 10.8+ since M28. The blacklist check above takes care of returning
// false before this hits on unsupported Win/Mac versions.
return true;
#endif
return false;
}
bool IsForceCompositingModeEnabled() {
// Force compositing mode is a subset of threaded compositing mode.
if (IsThreadedCompositingEnabled())
return true;
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
// Command line switches take precedence over blacklisting.
if (command_line.HasSwitch(switches::kDisableForceCompositingMode))
return false;
else if (command_line.HasSwitch(switches::kForceCompositingMode))
return true;
if (!CanDoAcceleratedCompositing() || IsForceCompositingModeBlacklisted())
return false;
#if defined(OS_MACOSX) || defined(OS_WIN)
// Windows Vista+ has been shipping with TCM enabled at 100% since M24 and
// Mac OSX 10.8+ since M28. The blacklist check above takes care of returning
// false before this hits on unsupported Win/Mac versions.
return true;
#endif
return false;
}
bool IsDelegatedRendererEnabled() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
bool enabled = false;
#if defined(USE_AURA)
// Enable on Aura.
enabled = true;
#endif
// Flags override.
enabled |= command_line.HasSwitch(switches::kEnableDelegatedRenderer);
enabled &= !command_line.HasSwitch(switches::kDisableDelegatedRenderer);
// Needs compositing, and thread.
if (enabled &&
(!IsForceCompositingModeEnabled() || !IsThreadedCompositingEnabled())) {
enabled = false;
LOG(ERROR) << "Disabling delegated-rendering because it needs "
<< "force-compositing-mode and threaded-compositing.";
}
return enabled;
}
bool IsDeadlineSchedulingEnabled() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
// Default to enabled.
bool enabled = true;
// Flags override.
enabled |= command_line.HasSwitch(switches::kEnableDeadlineScheduling);
enabled &= !command_line.HasSwitch(switches::kDisableDeadlineScheduling);
return enabled;
}
base::Value* GetFeatureStatus() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
std::string gpu_access_blocked_reason;
bool gpu_access_blocked =
!manager->GpuAccessAllowed(&gpu_access_blocked_reason);
base::DictionaryValue* feature_status_dict = new base::DictionaryValue();
for (size_t i = 0; i < kNumFeatures; ++i) {
const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i);
// force_compositing_mode status is part of the compositing status.
if (gpu_feature_info.name == "force_compositing_mode")
continue;
std::string status;
if (gpu_feature_info.disabled) {
status = "disabled";
if (gpu_feature_info.name == "css_animation") {
status += "_software_animated";
} else if (gpu_feature_info.name == "raster") {
if (cc::switches::IsImplSidePaintingEnabled())
status += "_software_multithreaded";
else
status += "_software";
} else {
if (gpu_feature_info.fallback_to_software)
status += "_software";
else
status += "_off";
}
} else if (manager->ShouldUseSwiftShader()) {
status = "unavailable_software";
} else if (gpu_feature_info.blocked ||
gpu_access_blocked) {
status = "unavailable";
if (gpu_feature_info.fallback_to_software)
status += "_software";
else
status += "_off";
} else {
status = "enabled";
if (gpu_feature_info.name == "webgl" &&
(command_line.HasSwitch(switches::kDisableAcceleratedCompositing) ||
manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING)))
status += "_readback";
bool has_thread = IsThreadedCompositingEnabled();
if (gpu_feature_info.name == "compositing") {
bool force_compositing = IsForceCompositingModeEnabled();
if (force_compositing)
status += "_force";
if (has_thread)
status += "_threaded";
}
if (gpu_feature_info.name == "css_animation") {
if (has_thread)
status = "accelerated_threaded";
else
status = "accelerated";
}
}
// TODO(reveman): Remove this when crbug.com/223286 has been fixed.
if (gpu_feature_info.name == "raster" &&
cc::switches::IsImplSidePaintingEnabled()) {
status = "disabled_software_multithreaded";
}
feature_status_dict->SetString(
gpu_feature_info.name.c_str(), status.c_str());
}
return feature_status_dict;
}
base::Value* GetProblems() {
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
std::string gpu_access_blocked_reason;
bool gpu_access_blocked =
!manager->GpuAccessAllowed(&gpu_access_blocked_reason);
base::ListValue* problem_list = new base::ListValue();
manager->GetBlacklistReasons(problem_list);
if (gpu_access_blocked) {
base::DictionaryValue* problem = new base::DictionaryValue();
problem->SetString("description",
"GPU process was unable to boot: " + gpu_access_blocked_reason);
problem->Set("crBugs", new base::ListValue());
problem->Set("webkitBugs", new base::ListValue());
problem_list->Insert(0, problem);
}
for (size_t i = 0; i < kNumFeatures; ++i) {
const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i);
if (gpu_feature_info.disabled) {
base::DictionaryValue* problem = new base::DictionaryValue();
problem->SetString(
"description", gpu_feature_info.disabled_description);
problem->Set("crBugs", new base::ListValue());
problem->Set("webkitBugs", new base::ListValue());
problem_list->Append(problem);
}
}
return problem_list;
}
base::Value* GetDriverBugWorkarounds() {
base::ListValue* workaround_list = new base::ListValue();
GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds(workaround_list);
return workaround_list;
}
} // namespace content