blob: ba60aef77fbe9b958a1302cc295daa1594856d77 [file] [log] [blame]
// Copyright 2017 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 "gpu/config/gpu_finch_features.h"
#include "base/command_line.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "gpu/config/gpu_switches.h"
#include "ui/gl/gl_features.h"
#include "ui/gl/gl_surface_egl.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/android_image_reader_compat.h"
#include "base/android/build_info.h"
#include "base/android/sys_utils.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/pattern.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "ui/gfx/android/android_surface_control_compat.h"
#endif
namespace features {
namespace {
#if BUILDFLAG(IS_ANDROID)
bool FieldIsInBlocklist(const char* current_value, std::string blocklist_str) {
std::vector<std::string> blocklist = base::SplitString(
blocklist_str, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (const std::string& blocklisted_value : blocklist) {
if (base::StartsWith(current_value, blocklisted_value,
base::CompareCase::INSENSITIVE_ASCII)) {
return true;
}
}
return false;
}
bool IsDeviceBlocked(const char* field, const std::string& block_list) {
auto disable_patterns = base::SplitString(
block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
for (const auto& disable_pattern : disable_patterns) {
if (base::MatchPattern(field, disable_pattern))
return true;
}
return false;
}
#endif
} // namespace
#if BUILDFLAG(IS_ANDROID)
// Used to limit GL version to 2.0 for skia raster on Android.
const base::Feature kUseGles2ForOopR{"UseGles2ForOopR",
base::FEATURE_DISABLED_BY_DEFAULT};
// Use android SurfaceControl API for managing display compositor's buffer queue
// and using overlays on Android. Also used by webview to disable surface
// SurfaceControl.
const base::Feature kAndroidSurfaceControl{"AndroidSurfaceControl",
base::FEATURE_ENABLED_BY_DEFAULT};
// https://crbug.com/1176185 List of devices on which SurfaceControl should be
// disabled.
const base::FeatureParam<std::string> kAndroidSurfaceControlDeviceBlocklist{
&kAndroidSurfaceControl, "AndroidSurfaceControlDeviceBlocklist",
"capri|caprip"};
// List of models on which SurfaceControl should be disabled.
const base::FeatureParam<std::string> kAndroidSurfaceControlModelBlocklist{
&kAndroidSurfaceControl, "AndroidSurfaceControlModelBlocklist",
"SM-F9*|SM-W202?|SCV44|SCG05|SCG11|SC-55B"};
// Hardware Overlays for WebView.
const base::Feature kWebViewSurfaceControl{"WebViewSurfaceControl",
base::FEATURE_DISABLED_BY_DEFAULT};
// Same as kWebViewSurfaceControl, but affects only Android T+, used for
// targeting pre-release version.
const base::Feature kWebViewSurfaceControlForT{
"WebViewSurfaceControlForT", base::FEATURE_DISABLED_BY_DEFAULT};
// Use thread-safe media path on WebView.
const base::Feature kWebViewThreadSafeMedia{"WebViewThreadSafeMedia",
base::FEATURE_DISABLED_BY_DEFAULT};
// This is used as default state because it's different for webview and chrome.
// WebView hardcodes this as enabled in AwMainDelegate.
const base::Feature kWebViewThreadSafeMediaDefault{
"WebViewThreadSafeMediaDefault", base::FEATURE_DISABLED_BY_DEFAULT};
// Use AImageReader for MediaCodec and MediaPlyer on android.
const base::Feature kAImageReader{"AImageReader",
base::FEATURE_ENABLED_BY_DEFAULT};
// If webview-draw-functor-uses-vulkan is set, use vulkan for composite and
// raster.
const base::Feature kWebViewVulkan{"WebViewVulkan",
base::FEATURE_ENABLED_BY_DEFAULT};
// Used to enable/disable zero copy video path on webview for MCVD.
const base::Feature kWebViewZeroCopyVideo{"WebViewZeroCopyVideo",
base::FEATURE_DISABLED_BY_DEFAULT};
// List of devices on which WebViewZeroCopyVideo should be disabled.
const base::FeatureParam<std::string> kWebViewZeroCopyVideoBlocklist{
&kWebViewZeroCopyVideo, "WebViewZeroCopyVideoBlocklist", ""};
// Used to limit AImageReader max queue size to 1 since many devices especially
// android Tv devices do not support more than 1 images.
const base::Feature kLimitAImageReaderMaxSizeToOne{
"LimitAImageReaderMaxSizeToOne", base::FEATURE_ENABLED_BY_DEFAULT};
// List of devices on which to limit AImageReader max queue size to 1.
const base::FeatureParam<std::string> kLimitAImageReaderMaxSizeToOneBlocklist{
&kLimitAImageReaderMaxSizeToOne, "LimitAImageReaderMaxSizeToOneBlocklist",
"MIBOX"};
// Increase number of buffers and pipeline depth for high frame rate devices.
const base::Feature kIncreaseBufferCountForHighFrameRate{
"IncreaseBufferCountForHighFrameRate", base::FEATURE_ENABLED_BY_DEFAULT};
const base::FeatureParam<std::string>
kDisableIncreaseBufferCountForHighFrameRate{
&kIncreaseBufferCountForHighFrameRate,
"DisableIncreaseBufferCountForHighFrameRate", ""};
#endif
// Enable GPU Rasterization by default. This can still be overridden by
// --enable-gpu-rasterization or --disable-gpu-rasterization.
// DefaultEnableGpuRasterization has launched on Mac, Windows, ChromeOS,
// Android and Linux.
const base::Feature kDefaultEnableGpuRasterization{
"DefaultEnableGpuRasterization",
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || \
BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_LINUX)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
};
// Enables the use of out of process rasterization for canvas.
const base::Feature kCanvasOopRasterization{"CanvasOopRasterization",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enables the use of ANGLE validation for non-WebGL contexts.
const base::Feature kDefaultEnableANGLEValidation{
"DefaultEnableANGLEValidation", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables canvas to free its resources by default when it's running in
// the background.
const base::Feature kCanvasContextLostInBackground{
"CanvasContextLostInBackground", base::FEATURE_DISABLED_BY_DEFAULT};
#if BUILDFLAG(IS_WIN)
// Use a high priority for GPU process on Windows.
const base::Feature kGpuProcessHighPriorityWin{
"GpuProcessHighPriorityWin", base::FEATURE_ENABLED_BY_DEFAULT};
#endif
// Use ThreadPriority::DISPLAY for GPU main, viz compositor and IO threads.
const base::Feature kGpuUseDisplayThreadPriority{
"GpuUseDisplayThreadPriority",
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
};
#if BUILDFLAG(IS_MAC)
// Enable use of Metal for OOP rasterization.
const base::Feature kMetal{"Metal", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
// Causes us to use the SharedImageManager, removing support for the old
// mailbox system. Any consumers of the GPU process using the old mailbox
// system will experience undefined results.
const base::Feature kSharedImageManager{"SharedImageManager",
base::FEATURE_DISABLED_BY_DEFAULT};
// Controls the decode acceleration of JPEG images (as opposed to camera
// captures) in Chrome OS using the VA-API.
// TODO(andrescj): remove or enable by default in Chrome OS once
// https://crbug.com/868400 is resolved.
const base::Feature kVaapiJpegImageDecodeAcceleration{
"VaapiJpegImageDecodeAcceleration", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls the decode acceleration of WebP images in Chrome OS using the
// VA-API.
// TODO(gildekel): remove or enable by default in Chrome OS once
// https://crbug.com/877694 is resolved.
const base::Feature kVaapiWebPImageDecodeAcceleration{
"VaapiWebPImageDecodeAcceleration", base::FEATURE_DISABLED_BY_DEFAULT};
// Enable Vulkan graphics backend for compositing and rasterization. Defaults to
// native implementation if --use-vulkan flag is not used. Otherwise
// --use-vulkan will be followed.
// Note Android WebView uses kWebViewVulkan instead of this.
const base::Feature kVulkan {
"Vulkan",
#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
};
const base::Feature kEnableDrDc{"EnableDrDc",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enable WebGPU on gpu service side only. This is used with origin trial
// before gpu service is enabled by default.
const base::Feature kWebGPUService{"WebGPUService",
base::FEATURE_DISABLED_BY_DEFAULT};
#if BUILDFLAG(IS_ANDROID)
const base::FeatureParam<std::string> kVulkanBlockListByHardware{
&kVulkan, "BlockListByHardware", "mt*"};
const base::FeatureParam<std::string> kVulkanBlockListByBrand{
&kVulkan, "BlockListByBrand", "HONOR"};
const base::FeatureParam<std::string> kVulkanBlockListByDevice{
&kVulkan, "BlockListByDevice", "OP4863|OP4883"};
const base::FeatureParam<std::string> kVulkanBlockListByAndroidBuildId{
&kVulkan, "BlockListByAndroidBuildId", ""};
const base::FeatureParam<std::string> kVulkanBlockListByManufacturer{
&kVulkan, "BlockListByManufacturer", ""};
const base::FeatureParam<std::string> kVulkanBlockListByModel{
&kVulkan, "BlockListByModel", ""};
const base::FeatureParam<std::string> kVulkanBlockListByBoard{
&kVulkan, "BlockListByBoard",
"RM67*|RM68*|k68*|mt67*|oppo67*|oppo68*|QM215|rk30sdk"};
const base::FeatureParam<std::string> kVulkanBlockListByAndroidBuildFP{
&kVulkan, "BlockListByAndroidBuildFP", ""};
// crbug.com/1294648
const base::FeatureParam<std::string> kDrDcBlockListByDevice{
&kEnableDrDc, "BlockListByDevice", "LF9810_2GB"};
#endif
// Enable SkiaRenderer Dawn graphics backend. On Windows this will use D3D12,
// and on Linux this will use Vulkan.
const base::Feature kSkiaDawn{"SkiaDawn", base::FEATURE_DISABLED_BY_DEFAULT};
// Enable GrShaderCache to use with Vulkan backend.
const base::Feature kEnableGrShaderCacheForVulkan{
"EnableGrShaderCacheForVulkan", base::FEATURE_ENABLED_BY_DEFAULT};
// Enable persistent storage of VkPipelineCache data.
const base::Feature kEnableVkPipelineCache{"EnableVkPipelineCache",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enable Skia reduceOpsTaskSplitting to reduce render passes.
const base::Feature kReduceOpsTaskSplitting{
"ReduceOpsTaskSplitting", base::FEATURE_DISABLED_BY_DEFAULT};
bool IsUsingVulkan() {
#if BUILDFLAG(IS_ANDROID)
// Force on if Vulkan feature is enabled from command line.
base::FeatureList* feature_list = base::FeatureList::GetInstance();
if (feature_list &&
feature_list->IsFeatureOverriddenFromCommandLine(
features::kVulkan.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE))
return true;
// WebView checks, which do not use (and disables) kVulkan.
// Do this above the Android version check because there are test devices
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWebViewDrawFunctorUsesVulkan) &&
base::FeatureList::IsEnabled(kWebViewVulkan)) {
return true;
}
// No support for devices before Q -- exit before checking feature flags
// so that devices are not counted in finch trials.
if (base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_Q)
return false;
if (!base::FeatureList::IsEnabled(kVulkan))
return false;
// Check block list against build info.
const auto* build_info = base::android::BuildInfo::GetInstance();
if (IsDeviceBlocked(build_info->hardware(), kVulkanBlockListByHardware.Get()))
return false;
if (IsDeviceBlocked(build_info->brand(), kVulkanBlockListByBrand.Get()))
return false;
if (IsDeviceBlocked(build_info->device(), kVulkanBlockListByDevice.Get()))
return false;
if (IsDeviceBlocked(build_info->android_build_id(),
kVulkanBlockListByAndroidBuildId.Get()))
return false;
if (IsDeviceBlocked(build_info->manufacturer(),
kVulkanBlockListByManufacturer.Get()))
return false;
if (IsDeviceBlocked(build_info->model(), kVulkanBlockListByModel.Get()))
return false;
if (IsDeviceBlocked(build_info->board(), kVulkanBlockListByBoard.Get()))
return false;
if (IsDeviceBlocked(build_info->android_build_fp(),
kVulkanBlockListByAndroidBuildFP.Get()))
return false;
return true;
#else
return base::FeatureList::IsEnabled(kVulkan);
#endif
}
bool IsDrDcEnabled() {
#if BUILDFLAG(IS_ANDROID)
// Enabled on android P+.
if (base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_P) {
return false;
}
// DrDc is supported on android MediaPlayer and MCVD path only when
// AImageReader is enabled. Also DrDc requires AImageReader max size to be
// at least 2 for each gpu thread. Hence DrDc is disabled on devices which has
// only 1 image.
if (!IsAImageReaderEnabled() || LimitAImageReaderMaxSizeToOne())
return false;
// Check block list against build info.
const auto* build_info = base::android::BuildInfo::GetInstance();
if (IsDeviceBlocked(build_info->device(), kDrDcBlockListByDevice.Get()))
return false;
return base::FeatureList::IsEnabled(kEnableDrDc);
#else
return false;
#endif
}
bool IsUsingThreadSafeMediaForWebView() {
#if BUILDFLAG(IS_ANDROID)
// SurfaceTexture can't be thread-safe. Also thread safe media code currently
// requires AImageReader max size to be at least 2 since one image could be
// accessed by each gpu thread in webview.
if (!IsAImageReaderEnabled() || LimitAImageReaderMaxSizeToOne())
return false;
// If the feature is overridden from command line or finch we will use its
// value. If not we use kWebViewThreadSafeMediaDefault which is set in
// AwMainDelegate for WebView.
base::FeatureList* feature_list = base::FeatureList::GetInstance();
if (feature_list &&
feature_list->IsFeatureOverridden(kWebViewThreadSafeMedia.name))
return base::FeatureList::IsEnabled(kWebViewThreadSafeMedia);
return base::FeatureList::IsEnabled(kWebViewThreadSafeMediaDefault);
#else
return false;
#endif
}
bool NeedThreadSafeAndroidMedia() {
return IsDrDcEnabled() || IsUsingThreadSafeMediaForWebView();
}
bool IsANGLEValidationEnabled() {
if (!UsePassthroughCommandDecoder()) {
return false;
}
return base::FeatureList::IsEnabled(kDefaultEnableANGLEValidation);
}
#if BUILDFLAG(IS_ANDROID)
bool IsAImageReaderEnabled() {
return base::FeatureList::IsEnabled(kAImageReader) &&
base::android::AndroidImageReader::GetInstance().IsSupported();
}
bool IsAndroidSurfaceControlEnabled() {
const auto* build_info = base::android::BuildInfo::GetInstance();
if (IsDeviceBlocked(build_info->device(),
kAndroidSurfaceControlDeviceBlocklist.Get()) ||
IsDeviceBlocked(build_info->model(),
kAndroidSurfaceControlModelBlocklist.Get())) {
return false;
}
if (!gfx::SurfaceControl::IsSupported())
return false;
// We can use surface control only with AImageReader.
if (!IsAImageReaderEnabled())
return false;
// SurfaceControl requires at least 3 frames in flight.
if (LimitAImageReaderMaxSizeToOne())
return false;
// On WebView we also require zero copy or thread-safe media to use
// SurfaceControl
if (IsWebViewZeroCopyVideoEnabled() || IsUsingThreadSafeMediaForWebView()) {
// If main feature is not overridden from command line and we're running T+
// use kWebViewSurfaceControlForT to decide feature status instead so we
// can target pre-release android to fish out platform side bugs.
base::FeatureList* feature_list = base::FeatureList::GetInstance();
if ((!feature_list || !feature_list->IsFeatureOverriddenFromCommandLine(
features::kWebViewSurfaceControl.name)) &&
build_info->is_at_least_t()) {
return base::FeatureList::IsEnabled(kWebViewSurfaceControlForT);
}
return base::FeatureList::IsEnabled(kWebViewSurfaceControl);
}
return base::FeatureList::IsEnabled(kAndroidSurfaceControl);
}
// Many devices do not support more than 1 image to be acquired from the
// AImageReader.(crbug.com/1051705). This method returns true for those
// devices. Currently the list of device model names are sent from server side
// via a finch config file. There is a known device MIBOX for which max size
// should be 1 irrespecticve of the feature LimitAImageReaderMaxSizeToOne
// enabled or not. Get() returns default value even if the feature is disabled.
bool LimitAImageReaderMaxSizeToOne() {
// Always limit image reader to 1 frame for Android TV. Many TVs doesn't work
// with more than 1 frame and it's very hard to localize which models do.
if (base::android::BuildInfo::GetInstance()->is_tv())
return true;
return (FieldIsInBlocklist(base::android::BuildInfo::GetInstance()->model(),
kLimitAImageReaderMaxSizeToOneBlocklist.Get()));
}
// Zero copy is disabled if device can not support 3 max images.
bool IsWebViewZeroCopyVideoEnabled() {
const bool limit_max_size_to_one = LimitAImageReaderMaxSizeToOne();
if (!IsAImageReaderEnabled() || limit_max_size_to_one)
return false;
if (!base::FeatureList::IsEnabled(kWebViewZeroCopyVideo))
return false;
return !(FieldIsInBlocklist(base::android::BuildInfo::GetInstance()->model(),
kWebViewZeroCopyVideoBlocklist.Get()));
}
bool IncreaseBufferCountForHighFrameRate() {
// TODO(crbug.com/1211332): We don't have a way to dynamically adjust number
// of buffers. So these checks, espeically the RAM one, is to limit the impact
// of more buffers to devices that can handle them.
// 8GB of ram with large margin for error.
constexpr int RAM_8GB_CUTOFF = 7200 * 1024;
static bool increase =
base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SdkVersion::SDK_VERSION_R &&
IsAndroidSurfaceControlEnabled() && IsAImageReaderEnabled() &&
base::android::SysUtils::AmountOfPhysicalMemoryKB() > RAM_8GB_CUTOFF &&
base::FeatureList::IsEnabled(kIncreaseBufferCountForHighFrameRate) &&
!IsDeviceBlocked(base::android::BuildInfo::GetInstance()->device(),
kDisableIncreaseBufferCountForHighFrameRate.Get());
return increase;
}
bool IncreaseBufferCountForWebViewOverlays() {
return IsAndroidSurfaceControlEnabled() &&
base::FeatureList::IsEnabled(kWebViewSurfaceControl);
}
#endif
} // namespace features