// 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" #include "ui/gl/gl_utils.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 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 // Used to limit GL version to 2.0 for skia raster and compositing. const base::Feature kUseGles2ForOopR { "UseGles2ForOopR", #if BUILDFLAG(IS_ANDROID) base::FEATURE_DISABLED_BY_DEFAULT #else base::FEATURE_ENABLED_BY_DEFAULT #endif }; #if BUILDFLAG(IS_ANDROID) // 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 kAndroidSurfaceControlDeviceBlocklist{ &kAndroidSurfaceControl, "AndroidSurfaceControlDeviceBlocklist", "capri|caprip"}; // List of models on which SurfaceControl should be disabled. const base::FeatureParam 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 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 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 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", #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || \ (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) || BUILDFLAG(IS_FUCHSIA) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT #endif }; // Enables the use of MSAA in skia on Ice Lake and later intel architectures. const base::Feature kEnableMSAAOnNewIntelGPUs{ "EnableMSAAOnNewIntelGPUs", 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}; // Disable overlay promotion for clear video quads when their MPO quad would // move. const base::Feature kDisableVideoOverlayIfMoving{ "DisableVideoOverlayIfMoving", 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}; #if defined(ARCH_CPU_ARM64) const base::Feature kDisableFlushWorkaroundForMacCrash{ "DisableFlushWorkaroundForMacCrash", base::FEATURE_DISABLED_BY_DEFAULT}; #endif #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", #if BUILDFLAG(IS_ANDROID) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT #endif }; const base::Feature kForceGpuMainThreadToNormalPriorityDrDc{ "ForceGpuMainThreadToNormalPriorityDrDc", base::FEATURE_DISABLED_BY_DEFAULT}; #if BUILDFLAG(IS_ANDROID) const base::Feature kEnableDrDcVulkan{"EnableDrDcVulkan", base::FEATURE_DISABLED_BY_DEFAULT}; #endif // BUILDFLAG(IS_ANDROID) // Enable WebGPU on gpu service side only. This is used with origin trial and // enabled by default on supported platforms. const base::Feature kWebGPUService { "WebGPUService", #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT #endif }; #if BUILDFLAG(IS_ANDROID) const base::FeatureParam kVulkanBlockListByHardware{ &kVulkan, "BlockListByHardware", "mt*"}; const base::FeatureParam kVulkanBlockListByBrand{ &kVulkan, "BlockListByBrand", "HONOR"}; const base::FeatureParam kVulkanBlockListByDevice{ &kVulkan, "BlockListByDevice", "OP4863|OP4883"}; const base::FeatureParam kVulkanBlockListByAndroidBuildId{ &kVulkan, "BlockListByAndroidBuildId", ""}; const base::FeatureParam kVulkanBlockListByManufacturer{ &kVulkan, "BlockListByManufacturer", ""}; const base::FeatureParam kVulkanBlockListByModel{ &kVulkan, "BlockListByModel", ""}; const base::FeatureParam kVulkanBlockListByBoard{ &kVulkan, "BlockListByBoard", "RM67*|RM68*|k68*|mt6*|oppo67*|oppo68*|QM215|rk30sdk"}; const base::FeatureParam kVulkanBlockListByAndroidBuildFP{ &kVulkan, "BlockListByAndroidBuildFP", ""}; // Blocklists meant for DrDc. // crbug.com/1294648 const base::FeatureParam kDrDcBlockListByDevice{ &kEnableDrDc, "BlockListByDevice", "LF9810_2GB"}; // crbug.com/1340059, crbug.com/1340064 const base::FeatureParam kDrDcBlockListByModel{ &kEnableDrDc, "BlockListByModel", "SM-J400M|SM-J415F|ONEPLUS A3003|OCTAStream*"}; const base::FeatureParam kDrDcBlockListByHardware{ &kEnableDrDc, "BlockListByHardware", ""}; const base::FeatureParam kDrDcBlockListByBrand{ &kEnableDrDc, "BlockListByBrand", "HONOR"}; const base::FeatureParam kDrDcBlockListByAndroidBuildId{ &kEnableDrDc, "BlockListByAndroidBuildId", ""}; const base::FeatureParam kDrDcBlockListByManufacturer{ &kEnableDrDc, "BlockListByManufacturer", ""}; const base::FeatureParam kDrDcBlockListByBoard{ &kEnableDrDc, "BlockListByBoard", ""}; const base::FeatureParam kDrDcBlockListByAndroidBuildFP{ &kEnableDrDc, "BlockListByAndroidBuildFP", ""}; #endif // BUILDFLAG(IS_ANDROID) // 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}; // Enabling this will make the GPU decode path use a mock implementation of // discardable memory. const base::Feature kNoDiscardableMemoryForGpuDecodePath{ "NoDiscardableMemoryForGpuDecodePath", base::FEATURE_DISABLED_BY_DEFAULT}; // Use a 100-command limit before forcing context switch per command buffer // instead of 20. const base::Feature kIncreasedCmdBufferParseSlice{ "IncreasedCmdBufferParseSlice", base::FEATURE_DISABLED_BY_DEFAULT}; bool UseGles2ForOopR() { #if BUILDFLAG(IS_ANDROID) // GLS3 + passthrough decoder break many tests on Android. // TODO(crbug.com/1044287): use GLES3 with passthrough decoder. if (gl::UsePassthroughCommandDecoder(base::CommandLine::ForCurrentProcess())) return true; #endif return base::FeatureList::IsEnabled(features::kUseGles2ForOopR); } 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; if (IsDeviceBlocked(build_info->model(), kDrDcBlockListByModel.Get())) return false; if (IsDeviceBlocked(build_info->hardware(), kDrDcBlockListByHardware.Get())) return false; if (IsDeviceBlocked(build_info->brand(), kDrDcBlockListByBrand.Get())) return false; if (IsDeviceBlocked(build_info->android_build_id(), kDrDcBlockListByAndroidBuildId.Get())) return false; if (IsDeviceBlocked(build_info->manufacturer(), kDrDcBlockListByManufacturer.Get())) return false; if (IsDeviceBlocked(build_info->board(), kDrDcBlockListByBoard.Get())) return false; if (IsDeviceBlocked(build_info->android_build_fp(), kDrDcBlockListByAndroidBuildFP.Get())) return false; if (!base::FeatureList::IsEnabled(kEnableDrDc)) return false; return IsUsingVulkan() ? base::FeatureList::IsEnabled(kEnableDrDcVulkan) : true; #else return false; #endif } bool IsGpuMainThreadForcedToNormalPriorityDrDc() { // GPU main thread priority is forced to NORMAL only when DrDc is enabled. In // that case DrDc thread continues to use DISPLAY thread priority and hence // have higher thread priority than GPU main. return IsDrDcEnabled() && base::FeatureList::IsEnabled(kForceGpuMainThreadToNormalPriorityDrDc); } 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() { return base::FeatureList::IsEnabled(kDefaultEnableANGLEValidation) && UsePassthroughCommandDecoder(); } #if BUILDFLAG(IS_ANDROID) bool IsAImageReaderEnabled() { // Device Hammer_Energy_2 seems to be very crash with image reader during // gl::GLImageEGL::BindTexImage(). Disable image reader on that device for // now. crbug.com/1323921 if (IsDeviceBlocked(base::android::BuildInfo::GetInstance()->device(), "Hammer_Energy_2")) { return false; } 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 require thread-safe media to use SurfaceControl if (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())); } 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; } #endif } // namespace features