Bug 1632259 - Refactor WebRender configuration logic in gfxPlatform to be testable. r=jrmuizel

We have encountered issues when rolling out WebRender because the
configuration logic is quite complicated. It would serve us well to have
it in a form that we can easily test. This patch does said refactor, as
well as adds an initial set of tests.

Differential Revision: https://phabricator.services.mozilla.com/D72027
This commit is contained in:
Andrew Osmond 2020-05-04 01:01:53 +00:00
parent d0679695d6
commit f5baf0eea6
12 changed files with 1325 additions and 405 deletions

View File

@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebRenderRollout.h"
#include "mozilla/Preferences.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Services.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsISupportsImpl.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace gfx {
static const char* const WR_ROLLOUT_PREF = "gfx.webrender.all.qualified";
static const bool WR_ROLLOUT_PREF_DEFAULTVALUE = true;
static const char* const WR_ROLLOUT_DEFAULT_PREF =
"gfx.webrender.all.qualified.default";
static const bool WR_ROLLOUT_DEFAULT_PREF_DEFAULTVALUE = false;
static const char* const WR_ROLLOUT_PREF_OVERRIDE =
"gfx.webrender.all.qualified.gfxPref-default-override";
static const char* const WR_ROLLOUT_HW_QUALIFIED_OVERRIDE =
"gfx.webrender.all.qualified.hardware-override";
static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
// If the "gfx.webrender.all.qualified" pref is true we want to enable
// WebRender for qualified hardware. This pref may be set by the Normandy
// Preference Rollout feature. The Normandy pref rollout code sets default
// values on rolled out prefs on every startup. Default pref values are not
// persisted; they only exist in memory for that session. Gfx starts up
// before Normandy does. So it's too early to observe the WR qualified pref
// changed by Normandy rollout on gfx startup. So we add a shutdown observer to
// save the default value on shutdown, and read the saved value on startup
// instead.
class WrRolloutPrefShutdownSaver final : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports*, const char* aTopic,
const char16_t*) override {
if (strcmp(PROFILE_BEFORE_CHANGE_TOPIC, aTopic) != 0) {
// Not the observer we're looking for, move along.
return NS_OK;
}
SaveRolloutPref();
// Shouldn't receive another notification, remove the observer.
RefPtr<WrRolloutPrefShutdownSaver> kungFuDeathGrip(this);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return NS_ERROR_FAILURE;
}
observerService->RemoveObserver(this, PROFILE_BEFORE_CHANGE_TOPIC);
return NS_OK;
}
static void AddShutdownObserver() {
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return;
}
RefPtr<WrRolloutPrefShutdownSaver> wrRolloutSaver =
new WrRolloutPrefShutdownSaver();
observerService->AddObserver(wrRolloutSaver, PROFILE_BEFORE_CHANGE_TOPIC,
false);
}
private:
virtual ~WrRolloutPrefShutdownSaver() = default;
void SaveRolloutPref() {
if (Preferences::HasUserValue(WR_ROLLOUT_PREF) ||
Preferences::GetType(WR_ROLLOUT_PREF) == nsIPrefBranch::PREF_INVALID) {
// Don't need to create a backup of default value, because either:
// 1. the user or the WR SHIELD study has set a user pref value, or
// 2. we've not had a default pref set by Normandy that needs to be saved
// for reading before Normandy has started up.
return;
}
bool defaultValue =
Preferences::GetBool(WR_ROLLOUT_PREF, false, PrefValueKind::Default);
Preferences::SetBool(WR_ROLLOUT_DEFAULT_PREF, defaultValue);
}
};
NS_IMPL_ISUPPORTS(WrRolloutPrefShutdownSaver, nsIObserver)
/* static */ void WebRenderRollout::Init() {
WrRolloutPrefShutdownSaver::AddShutdownObserver();
}
/* static */ Maybe<bool> WebRenderRollout::CalculateQualifiedOverride() {
// This pref only ever gets set in test_pref_rollout_workaround, and in
// that case we want to ignore the MOZ_WEBRENDER=0 that will be set by
// the test harness so as to actually make the test work.
if (!Preferences::HasUserValue(WR_ROLLOUT_HW_QUALIFIED_OVERRIDE)) {
return Nothing();
}
return Some(Preferences::GetBool(WR_ROLLOUT_HW_QUALIFIED_OVERRIDE, false));
}
// If the "gfx.webrender.all.qualified" pref is true we want to enable
// WebRender for qualifying hardware. The Normandy pref rollout code sets
// default values on rolled out prefs on every startup, but Gfx starts up
// before Normandy does. So it's too early to observe the WR qualified pref
// default value changed by Normandy rollout here yet. So we have a shutdown
// observer to save the default value on shutdown, and read the saved default
// value here instead, and emulate the behavior of the pref system, with
// respect to default/user values of the rollout pref.
/* static */ bool WebRenderRollout::CalculateQualified() {
auto clearPrefOnExit = MakeScopeExit([]() {
// Clear the mirror of the default value of the rollout pref on scope exit,
// if we have one. This ensures the user doesn't mess with the pref.
// If we need it again, we'll re-create it on shutdown.
Preferences::ClearUser(WR_ROLLOUT_DEFAULT_PREF);
});
if (!Preferences::HasUserValue(WR_ROLLOUT_PREF) &&
Preferences::HasUserValue(WR_ROLLOUT_DEFAULT_PREF)) {
// The user has not set a user pref, and we have a default value set by the
// shutdown observer. Let's use this as it should be the value Normandy set
// before startup. WR_ROLLOUT_DEFAULT_PREF should only be set on shutdown by
// the shutdown observer.
// Normandy runs *during* startup, but *after* this code here runs (hence
// the need for the workaround).
// To have a value stored in the WR_ROLLOUT_DEFAULT_PREF pref here, during
// the previous run Normandy must have set a default value on the in-memory
// pref, and on shutdown we stored the default value in this
// WR_ROLLOUT_DEFAULT_PREF user pref. Then once the user restarts, we
// observe this pref. Normandy is the only way a default (not user) value
// can be set for this pref.
return Preferences::GetBool(WR_ROLLOUT_DEFAULT_PREF,
WR_ROLLOUT_DEFAULT_PREF_DEFAULTVALUE);
}
// We don't have a user value for the rollout pref, and we don't have the
// value of the rollout pref at last shutdown stored. So we should fallback
// to using the default. *But* if we're running
// under the Marionette pref rollout work-around test, we may want to override
// the default value expressed here, so we can test the "default disabled;
// rollout pref enabled" case.
// Note that those preferences can't be defined in all.js nor
// StaticPrefsList.h as they would create the pref, leading SaveRolloutPref()
// above to abort early as the pref would have a valid type.
// We also don't want those prefs to appear in about:config.
if (Preferences::HasUserValue(WR_ROLLOUT_PREF_OVERRIDE)) {
return Preferences::GetBool(WR_ROLLOUT_PREF_OVERRIDE);
}
return Preferences::GetBool(WR_ROLLOUT_PREF, WR_ROLLOUT_PREF_DEFAULTVALUE);
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_gfx_config_WebRenderRollout_h
#define mozilla_gfx_config_WebRenderRollout_h
#include "mozilla/Maybe.h"
namespace mozilla {
namespace gfx {
class WebRenderRollout final {
public:
static void Init();
static Maybe<bool> CalculateQualifiedOverride();
static bool CalculateQualified();
WebRenderRollout() = delete;
~WebRenderRollout() = delete;
};
} // namespace gfx
} // namespace mozilla
#endif // mozilla_gfx_config_WebRenderRollout_h

View File

@ -0,0 +1,346 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/gfx/gfxConfigManager.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layers.h"
#include "gfxConfig.h"
#include "gfxPlatform.h"
#include "nsIGfxInfo.h"
#include "nsXULAppAPI.h"
#include "WebRenderRollout.h"
#ifdef XP_WIN
# include "mozilla/WindowsVersion.h"
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/gfx/DisplayConfigWindows.h"
#endif
namespace mozilla {
namespace gfx {
void gfxConfigManager::Init() {
MOZ_ASSERT(XRE_IsParentProcess());
WebRenderRollout::Init();
mWrQualifiedOverride = WebRenderRollout::CalculateQualifiedOverride();
mWrQualified = WebRenderRollout::CalculateQualified();
EmplaceUserPref("gfx.webrender.compositor", mWrCompositorEnabled);
mWrForceEnabled = gfxPlatform::WebRenderPrefEnabled();
mWrForceDisabled = StaticPrefs::gfx_webrender_force_disabled_AtStartup();
mWrCompositorForceEnabled =
StaticPrefs::gfx_webrender_compositor_force_enabled_AtStartup();
mGPUProcessAllowSoftware =
StaticPrefs::layers_gpu_process_allow_software_AtStartup();
mWrPictureCaching = StaticPrefs::gfx_webrender_picture_caching();
mWrPartialPresent =
StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup() > 0;
#ifdef XP_WIN
mWrForceAngle = StaticPrefs::gfx_webrender_force_angle_AtStartup();
mWrForceAngleNoGPUProcess = StaticPrefs::
gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup();
mWrDCompWinEnabled =
Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false);
#endif
mWrEnvForceEnabled = gfxPlatform::WebRenderEnvvarEnabled();
mWrEnvForceDisabled = gfxPlatform::WebRenderEnvvarDisabled();
#ifdef XP_WIN
mHwStretchingSupport =
DeviceManagerDx::Get()->CheckHardwareStretchingSupport();
mScaledResolution = HasScaledResolution();
mIsWin10OrLater = IsWin10OrLater();
#else
mHwStretchingSupport = true;
#endif
#ifdef MOZ_WIDGET_GTK
mDisableHwCompositingNoWr = true;
#endif
#ifdef NIGHTLY_BUILD
mIsNightly = true;
#endif
mSafeMode = gfxPlatform::InSafeMode();
mGfxInfo = services::GetGfxInfo();
mFeatureWr = &gfxConfig::GetFeature(Feature::WEBRENDER);
mFeatureWrQualified = &gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
mFeatureWrCompositor = &gfxConfig::GetFeature(Feature::WEBRENDER_COMPOSITOR);
mFeatureWrAngle = &gfxConfig::GetFeature(Feature::WEBRENDER_ANGLE);
mFeatureWrDComp = &gfxConfig::GetFeature(Feature::WEBRENDER_DCOMP_PRESENT);
mFeatureWrPartial = &gfxConfig::GetFeature(Feature::WEBRENDER_PARTIAL);
mFeatureHwCompositing = &gfxConfig::GetFeature(Feature::HW_COMPOSITING);
#ifdef XP_WIN
mFeatureD3D11HwAngle = &gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
#endif
mFeatureGPUProcess = &gfxConfig::GetFeature(Feature::GPU_PROCESS);
}
void gfxConfigManager::EmplaceUserPref(const char* aPrefName,
Maybe<bool>& aValue) {
if (Preferences::HasUserValue(aPrefName)) {
aValue.emplace(Preferences::GetBool(aPrefName, false));
}
}
void gfxConfigManager::ConfigureFromBlocklist(long aFeature,
FeatureState* aFeatureState) {
MOZ_ASSERT(aFeatureState);
nsCString blockId;
int32_t status;
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
aFeatureState->Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_GFX_INFO"));
} else {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
aFeatureState->Disable(FeatureStatus::Blacklisted,
"Blacklisted by gfxInfo", blockId);
}
}
}
bool gfxConfigManager::ConfigureWebRenderQualified() {
MOZ_ASSERT(mFeatureWrQualified);
MOZ_ASSERT(mFeatureWrCompositor);
bool guarded = true;
mFeatureWrQualified->EnableByDefault();
if (mWrQualifiedOverride) {
if (!*mWrQualifiedOverride) {
mFeatureWrQualified->Disable(
FeatureStatus::BlockedOverride, "HW qualification pref override",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_QUALIFICATION_OVERRIDE"));
}
return guarded;
}
nsCString failureId;
int32_t status;
if (NS_FAILED(mGfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER,
failureId, &status))) {
mFeatureWrQualified->Disable(
FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_NO_GFX_INFO"));
return guarded;
}
switch (status) {
case nsIGfxInfo::FEATURE_ALLOW_ALWAYS:
// We want to honour ALLOW_ALWAYS on beta and release, but on nightly,
// we still want to perform experiments. A larger population is the most
// useful, demote nightly to merely qualified.
guarded = mIsNightly;
break;
case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED:
break;
case nsIGfxInfo::FEATURE_DENIED:
mFeatureWrQualified->Disable(FeatureStatus::Denied, "Not on allowlist",
failureId);
break;
default:
mFeatureWrQualified->Disable(FeatureStatus::Blacklisted,
"No qualified hardware", failureId);
break;
case nsIGfxInfo::FEATURE_STATUS_OK:
MOZ_ASSERT_UNREACHABLE("We should still be rolling out WebRender!");
mFeatureWrQualified->Disable(FeatureStatus::Blocked,
"Not controlled by rollout", failureId);
break;
}
if (!mIsNightly) {
// Disable WebRender if we don't have DirectComposition
nsAutoString adapterVendorID;
mGfxInfo->GetAdapterVendorID(adapterVendorID);
if (adapterVendorID == u"0x8086") {
bool hasBattery = false;
mGfxInfo->GetHasBattery(&hasBattery);
if (hasBattery && !mFeatureWrCompositor->IsEnabled()) {
mFeatureWrQualified->Disable(
FeatureStatus::Blocked, "Battery Intel requires os compositor",
NS_LITERAL_CSTRING("INTEL_BATTERY_REQUIRES_DCOMP"));
}
}
}
return guarded;
}
void gfxConfigManager::ConfigureWebRender() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mFeatureWr);
MOZ_ASSERT(mFeatureWrQualified);
MOZ_ASSERT(mFeatureWrCompositor);
MOZ_ASSERT(mFeatureWrAngle);
MOZ_ASSERT(mFeatureWrDComp);
MOZ_ASSERT(mFeatureWrPartial);
MOZ_ASSERT(mFeatureHwCompositing);
MOZ_ASSERT(mFeatureGPUProcess);
// Initialize WebRender native compositor usage
mFeatureWrCompositor->SetDefaultFromPref("gfx.webrender.compositor", true,
false, mWrCompositorEnabled);
if (mWrCompositorForceEnabled) {
mFeatureWrCompositor->UserForceEnable("Force enabled by pref");
}
ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
mFeatureWrCompositor);
// Disable native compositor when hardware stretching is not supported. It is
// for avoiding a problem like Bug 1618370.
// XXX Is there a better check for Bug 1618370?
if (!mHwStretchingSupport && mScaledResolution) {
mFeatureWrCompositor->Disable(
FeatureStatus::Unavailable, "No hardware stretching support",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_HARDWARE_STRETCHING"));
}
bool guardedByQualifiedPref = ConfigureWebRenderQualified();
mFeatureWr->DisableByDefault(
FeatureStatus::OptIn, "WebRender is an opt-in feature",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
// envvar works everywhere; note that we need this for testing in CI.
// Prior to bug 1523788, the `prefEnabled` check was only done on Nightly,
// so as to prevent random users from easily enabling WebRender on
// unqualified hardware in beta/release.
if (mWrEnvForceEnabled) {
mFeatureWr->UserEnable("Force enabled by envvar");
} else if (mWrForceEnabled) {
mFeatureWr->UserEnable("Force enabled by pref");
} else if (mFeatureWrQualified->IsEnabled()) {
// If the HW is qualified, we enable if either the HW has been qualified
// on the release channel (i.e. it's no longer guarded by the qualified
// pref), or if the qualified pref is enabled.
if (!guardedByQualifiedPref) {
mFeatureWr->UserEnable("Qualified in release");
} else if (mWrQualified) {
mFeatureWr->UserEnable("Qualified enabled by pref");
}
}
// If the user set the pref to force-disable, let's do that. This will
// override all the other enabling prefs (gfx.webrender.enabled,
// gfx.webrender.all, and gfx.webrender.all.qualified).
if (mWrForceDisabled ||
(mWrEnvForceDisabled && mWrQualifiedOverride.isNothing())) {
mFeatureWr->UserDisable(
"User force-disabled WR",
NS_LITERAL_CSTRING("FEATURE_FAILURE_USER_FORCE_DISABLED"));
}
// HW_COMPOSITING being disabled implies interfacing with the GPU might break
if (!mFeatureHwCompositing->IsEnabled()) {
mFeatureWr->ForceDisable(
FeatureStatus::UnavailableNoHwCompositing,
"Hardware compositing is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"));
}
if (mSafeMode) {
mFeatureWr->ForceDisable(FeatureStatus::UnavailableInSafeMode,
"Safe-mode is enabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
}
mFeatureWrAngle->DisableByDefault(
FeatureStatus::OptIn, "WebRender ANGLE is an opt-in feature",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
if (mFeatureD3D11HwAngle && mWrForceAngle) {
if (!mFeatureD3D11HwAngle->IsEnabled()) {
mFeatureWr->ForceDisable(
FeatureStatus::UnavailableNoAngle, "ANGLE is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED"));
} else if (!mFeatureGPUProcess->IsEnabled() &&
(!mIsNightly || !mWrForceAngleNoGPUProcess)) {
// WebRender with ANGLE relies on the GPU process when on Windows
mFeatureWr->ForceDisable(
FeatureStatus::UnavailableNoGpuProcess, "GPU Process is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
} else if (mFeatureWr->IsEnabled()) {
mFeatureWrAngle->UserEnable("Enabled");
}
}
if (!mFeatureWr->IsEnabled() && mDisableHwCompositingNoWr) {
if (mFeatureHwCompositing->IsEnabled()) {
// Hardware compositing should be disabled by default if we aren't using
// WebRender. We had to check if it is enabled at all, because it may
// already have been forced disabled (e.g. safe mode, headless). It may
// still be forced on by the user, and if so, this should have no effect.
mFeatureHwCompositing->Disable(FeatureStatus::Blocked,
"Acceleration blocked by platform",
EmptyCString());
}
if (!mFeatureHwCompositing->IsEnabled() &&
mFeatureGPUProcess->IsEnabled() && !mGPUProcessAllowSoftware) {
// We have neither WebRender nor OpenGL, we don't allow the GPU process
// for basic compositor, and it wasn't disabled already.
mFeatureGPUProcess->Disable(FeatureStatus::Unavailable,
"Hardware compositing is unavailable.",
EmptyCString());
}
}
mFeatureWrDComp->DisableByDefault(
FeatureStatus::OptIn, "WebRender DirectComposition is an opt-in feature",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
if (mWrDCompWinEnabled) {
// XXX relax win version to windows 8.
if (mIsWin10OrLater && mFeatureWr->IsEnabled() &&
mFeatureWrAngle->IsEnabled()) {
mFeatureWrDComp->UserEnable("Enabled");
}
}
if (!mWrPictureCaching) {
mFeatureWrCompositor->ForceDisable(
FeatureStatus::Unavailable, "Picture caching is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_PICTURE_CACHING_DISABLED"));
}
if (!mFeatureWrDComp->IsEnabled()) {
mFeatureWrCompositor->ForceDisable(
FeatureStatus::Unavailable, "No DirectComposition usage",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_DIRECTCOMPOSITION"));
}
// Initialize WebRender partial present config.
// Partial present is used only when WebRender compositor is not used.
if (mWrPartialPresent) {
if (mFeatureWr->IsEnabled()) {
mFeatureWrPartial->EnableByDefault();
if (mWrPictureCaching) {
// Call UserEnable() only for reporting to Decision Log.
// If feature is enabled by default. It is not reported to Decision Log.
mFeatureWrPartial->UserEnable("Enabled");
} else {
mFeatureWrPartial->ForceDisable(
FeatureStatus::Unavailable, "Picture caching is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_PICTURE_CACHING_DISABLED"));
}
}
}
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_gfx_config_gfxConfigManager_h
#define mozilla_gfx_config_gfxConfigManager_h
#include "gfxFeature.h"
namespace mozilla {
namespace gfx {
class gfxConfigManager {
public:
gfxConfigManager()
: mFeatureWr(nullptr),
mFeatureWrQualified(nullptr),
mFeatureWrCompositor(nullptr),
mFeatureWrAngle(nullptr),
mFeatureWrDComp(nullptr),
mFeatureWrPartial(nullptr),
mFeatureHwCompositing(nullptr),
mFeatureD3D11HwAngle(nullptr),
mFeatureGPUProcess(nullptr),
mWrForceEnabled(false),
mWrForceDisabled(false),
mWrCompositorForceEnabled(false),
mWrQualified(false),
mWrForceAngle(false),
mWrForceAngleNoGPUProcess(false),
mWrDCompWinEnabled(false),
mWrPictureCaching(false),
mWrPartialPresent(false),
mGPUProcessAllowSoftware(false),
mWrEnvForceEnabled(false),
mWrEnvForceDisabled(false),
mHwStretchingSupport(false),
mScaledResolution(false),
mDisableHwCompositingNoWr(false),
mIsNightly(false),
mSafeMode(false),
mIsWin10OrLater(false) {}
void Init();
void ConfigureWebRender();
void ConfigureFromBlocklist(long aFeature, FeatureState* aFeatureState);
protected:
void EmplaceUserPref(const char* aPrefName, Maybe<bool>& aValue);
bool ConfigureWebRenderQualified();
nsCOMPtr<nsIGfxInfo> mGfxInfo;
FeatureState* mFeatureWr;
FeatureState* mFeatureWrQualified;
FeatureState* mFeatureWrCompositor;
FeatureState* mFeatureWrAngle;
FeatureState* mFeatureWrDComp;
FeatureState* mFeatureWrPartial;
FeatureState* mFeatureHwCompositing;
FeatureState* mFeatureD3D11HwAngle;
FeatureState* mFeatureGPUProcess;
/**
* Prefs
*/
Maybe<bool> mWrCompositorEnabled;
bool mWrForceEnabled;
bool mWrForceDisabled;
bool mWrCompositorForceEnabled;
bool mWrQualified;
Maybe<bool> mWrQualifiedOverride;
bool mWrForceAngle;
bool mWrForceAngleNoGPUProcess;
bool mWrDCompWinEnabled;
bool mWrPictureCaching;
bool mWrPartialPresent;
bool mGPUProcessAllowSoftware;
/**
* Environment variables
*/
bool mWrEnvForceEnabled;
bool mWrEnvForceDisabled;
/**
* System support
*/
bool mHwStretchingSupport;
bool mScaledResolution;
bool mDisableHwCompositingNoWr;
bool mIsNightly;
bool mSafeMode;
bool mIsWin10OrLater;
};
} // namespace gfx
} // namespace mozilla
#endif // mozilla_gfx_config_gfxConfigParams_h

View File

@ -49,15 +49,15 @@ bool FeatureState::SetDefault(bool aEnable, FeatureStatus aDisableStatus,
}
void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
bool aDefaultValue) {
bool aDefaultValue,
Maybe<bool> aUserValue) {
bool baseValue =
Preferences::GetBool(aPrefName, aDefaultValue, PrefValueKind::Default);
SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled,
"Disabled by default");
if (Preferences::HasUserValue(aPrefName)) {
bool userValue = Preferences::GetBool(aPrefName, aDefaultValue);
if (userValue == aIsEnablePref) {
if (aUserValue) {
if (*aUserValue == aIsEnablePref) {
nsCString message("Enabled via ");
message.AppendASCII(aPrefName);
UserEnable(message.get());
@ -70,6 +70,16 @@ void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
}
}
void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
bool aDefaultValue) {
Maybe<bool> userValue;
if (Preferences::HasUserValue(aPrefName)) {
userValue.emplace(Preferences::GetBool(aPrefName, aDefaultValue));
}
SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue, userValue);
}
bool FeatureState::InitOrUpdate(bool aEnable, FeatureStatus aDisableStatus,
const char* aDisableMessage) {
if (!IsInitialized()) {

View File

@ -10,27 +10,30 @@
#include <stdint.h>
#include "gfxTelemetry.h"
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include "nsString.h"
namespace mozilla {
namespace gfx {
#define GFX_FEATURE_MAP(_) \
/* Name, Type, Description */ \
_(HW_COMPOSITING, Feature, "Compositing") \
_(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \
_(OPENGL_COMPOSITING, Feature, "OpenGL Compositing") \
_(DIRECT2D, Feature, "Direct2D") \
_(D3D11_HW_ANGLE, Feature, "Direct3D11 hardware ANGLE") \
_(DIRECT_DRAW, Feature, "DirectDraw") \
_(GPU_PROCESS, Feature, "GPU Process") \
_(WEBRENDER, Feature, "WebRender") \
_(WEBRENDER_QUALIFIED, Feature, "WebRender qualified") \
_(WEBRENDER_COMPOSITOR, Feature, "WebRender native compositor") \
_(WEBRENDER_PARTIAL, Feature, "WebRender partial present") \
_(OMTP, Feature, "Off Main Thread Painting") \
_(ADVANCED_LAYERS, Feature, "Advanced Layers") \
_(WEBGPU, Feature, "WebGPU") \
#define GFX_FEATURE_MAP(_) \
/* Name, Type, Description */ \
_(HW_COMPOSITING, Feature, "Compositing") \
_(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \
_(OPENGL_COMPOSITING, Feature, "OpenGL Compositing") \
_(DIRECT2D, Feature, "Direct2D") \
_(D3D11_HW_ANGLE, Feature, "Direct3D11 hardware ANGLE") \
_(DIRECT_DRAW, Feature, "DirectDraw") \
_(GPU_PROCESS, Feature, "GPU Process") \
_(WEBRENDER, Feature, "WebRender") \
_(WEBRENDER_QUALIFIED, Feature, "WebRender qualified") \
_(WEBRENDER_COMPOSITOR, Feature, "WebRender native compositor") \
_(WEBRENDER_PARTIAL, Feature, "WebRender partial present") \
_(WEBRENDER_ANGLE, Feature, "WebRender ANGLE") \
_(WEBRENDER_DCOMP_PRESENT, Feature, "WebRender DirectComposition") \
_(OMTP, Feature, "Off Main Thread Painting") \
_(ADVANCED_LAYERS, Feature, "Advanced Layers") \
_(WEBGPU, Feature, "WebGPU") \
/* Add new entries above this comment */
enum class Feature : uint32_t {
@ -42,8 +45,11 @@ enum class Feature : uint32_t {
class FeatureState {
friend class gfxConfig;
friend class GfxConfigManager; // for testing
public:
FeatureState() { Reset(); }
bool IsEnabled() const;
FeatureStatus GetValue() const;
@ -54,6 +60,8 @@ class FeatureState {
const char* aDisableMessage);
bool InitOrUpdate(bool aEnable, FeatureStatus aDisableStatus,
const char* aMessage);
void SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
bool aDefaultValue, Maybe<bool> aUserValue);
void SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
bool aDefaultValue);
void UserEnable(const char* aMessage);

View File

@ -11,14 +11,17 @@ EXPORTS += [
]
EXPORTS.mozilla.gfx += [
'gfxConfigManager.h',
'gfxVarReceiver.h',
'gfxVars.h',
]
UNIFIED_SOURCES += [
'gfxConfig.cpp',
'gfxConfigManager.cpp',
'gfxFeature.cpp',
'gfxVars.cpp',
'WebRenderRollout.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -0,0 +1,624 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "gfxFeature.h"
#include "mozilla/gfx/gfxConfigManager.h"
#include "nsIGfxInfo.h"
using namespace mozilla;
using namespace mozilla::gfx;
namespace mozilla {
namespace gfx {
class MockGfxInfo final : public nsIGfxInfo {
public:
NS_DECL_THREADSAFE_ISUPPORTS
int32_t mStatusWr;
int32_t mStatusWrCompositor;
Maybe<bool> mHasBattery;
const char* mVendorId;
// Default allows WebRender + compositor, and is desktop NVIDIA.
MockGfxInfo()
: mStatusWr(nsIGfxInfo::FEATURE_ALLOW_ALWAYS),
mStatusWrCompositor(nsIGfxInfo::FEATURE_STATUS_OK),
mHasBattery(Some(false)),
mVendorId("0x10de") {}
NS_IMETHOD GetFeatureStatus(int32_t aFeature, nsACString& aFailureId,
int32_t* _retval) override {
switch (aFeature) {
case nsIGfxInfo::FEATURE_WEBRENDER:
*_retval = mStatusWr;
break;
case nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR:
*_retval = mStatusWrCompositor;
break;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
return NS_OK;
}
NS_IMETHOD GetHasBattery(bool* aHasBattery) override {
if (mHasBattery.isNothing()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
*aHasBattery = *mHasBattery;
return NS_OK;
}
NS_IMETHOD GetAdapterVendorID(nsAString& aAdapterVendorID) override {
if (!mVendorId) {
return NS_ERROR_NOT_IMPLEMENTED;
}
aAdapterVendorID.AssignASCII(mVendorId);
return NS_OK;
}
// The following methods we don't need for testing gfxConfigManager.
NS_IMETHOD GetFeatureSuggestedDriverVersion(int32_t aFeature,
nsAString& _retval) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetMonitors(JSContext* cx,
JS::MutableHandleValue _retval) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetFailures(nsTArray<int32_t>& indices,
nsTArray<nsCString>& failures) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD_(void) LogFailure(const nsACString& failure) override {}
NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetFeatureLog(JSContext*, JS::MutableHandle<JS::Value>) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetActiveCrashGuards(JSContext*,
JS::MutableHandle<JS::Value>) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetContentBackend(nsAString& aContentBackend) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetUsingGPUProcess(bool* aOutValue) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetWebRenderEnabled(bool* aWebRenderEnabled) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetUsesTiling(bool* aUsesTiling) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetContentUsesTiling(bool* aUsesTiling) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetOffMainThreadPaintEnabled(
bool* aOffMainThreadPaintEnabled) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetOffMainThreadPaintWorkerCount(
int32_t* aOffMainThreadPaintWorkerCount) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetTargetFrameRate(uint32_t* aTargetFrameRate) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetD2DEnabled(bool* aD2DEnabled) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDWriteEnabled(bool* aDWriteEnabled) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDWriteVersion(nsAString& aDwriteVersion) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDeviceID(nsAString& aAdapterDeviceID) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterSubsysID(nsAString& aAdapterSubsysID) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterRAM(uint32_t* aAdapterRAM) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverVersion(
nsAString& aAdapterDriverVersion) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverDate(nsAString& aAdapterDriverDate) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDescription2(nsAString& aAdapterDescription) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriver2(nsAString& aAdapterDriver) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterVendorID2(nsAString& aAdapterVendorID) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDeviceID2(nsAString& aAdapterDeviceID) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterSubsysID2(nsAString& aAdapterSubsysID) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterRAM2(uint32_t* aAdapterRAM) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverVersion2(
nsAString& aAdapterDriverVersion) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetAdapterDriverDate2(nsAString& aAdapterDriverDate) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetIsGPU2Active(bool* aIsGPU2Active) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD ControlGPUProcessForXPCShell(bool aEnable,
bool* _retval) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD_(void) GetData() override {}
private:
virtual ~MockGfxInfo() = default;
};
NS_IMPL_ISUPPORTS(MockGfxInfo, nsIGfxInfo)
class GfxConfigManager : public ::testing::Test, public gfxConfigManager {
public:
GfxConfigManager() {
mFeatureWr = &mFeatures.mWr;
mFeatureWrQualified = &mFeatures.mWrQualified;
mFeatureWrCompositor = &mFeatures.mWrCompositor;
mFeatureWrAngle = &mFeatures.mWrAngle;
mFeatureWrDComp = &mFeatures.mWrDComp;
mFeatureWrPartial = &mFeatures.mWrPartial;
mFeatureHwCompositing = &mFeatures.mHwCompositing;
mFeatureD3D11HwAngle = &mFeatures.mD3D11HwAngle;
mFeatureGPUProcess = &mFeatures.mGPUProcess;
}
void SetUp() override {
mMockGfxInfo = new MockGfxInfo();
mGfxInfo = mMockGfxInfo;
// By default, turn everything on. This effectively assumes we are on
// qualified nightly Windows 10 with DirectComposition support.
mFeatureHwCompositing->EnableByDefault();
mFeatureD3D11HwAngle->EnableByDefault();
mFeatureGPUProcess->EnableByDefault();
mWrCompositorEnabled.emplace(true);
mWrQualified = true;
mWrPictureCaching = true;
mWrPartialPresent = true;
mWrForceAngle = true;
mWrDCompWinEnabled = true;
mHwStretchingSupport = true;
mIsWin10OrLater = true;
mIsNightly = true;
}
void TearDown() override {
mFeatures.mWr.Reset();
mFeatures.mWrQualified.Reset();
mFeatures.mWrCompositor.Reset();
mFeatures.mWrAngle.Reset();
mFeatures.mWrDComp.Reset();
mFeatures.mWrPartial.Reset();
mFeatures.mHwCompositing.Reset();
mFeatures.mD3D11HwAngle.Reset();
mFeatures.mGPUProcess.Reset();
}
struct {
FeatureState mWr;
FeatureState mWrQualified;
FeatureState mWrCompositor;
FeatureState mWrAngle;
FeatureState mWrDComp;
FeatureState mWrPartial;
FeatureState mHwCompositing;
FeatureState mD3D11HwAngle;
FeatureState mGPUProcess;
} mFeatures;
RefPtr<MockGfxInfo> mMockGfxInfo;
};
} // namespace gfx
} // namespace mozilla
TEST_F(GfxConfigManager, WebRenderDefault) {
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderNoPartialPresent) {
mWrPartialPresent = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderNoPictureCaching) {
mWrPictureCaching = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderScaledResolutionWithHwStretching) {
mScaledResolution = true;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderScaledResolutionNoHwStretching) {
mHwStretchingSupport = false;
mScaledResolution = true;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderEnabledWithDisableHwCompositingNoWr) {
mDisableHwCompositingNoWr = true;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderDisabledWithDisableHwCompositingNoWr) {
mDisableHwCompositingNoWr = true;
mWrQualified = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_FALSE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_FALSE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderDisabledWithAllowSoftwareGPUProcess) {
mDisableHwCompositingNoWr = true;
mWrQualified = false;
mGPUProcessAllowSoftware = true;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_FALSE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderQualifiedOverrideDisabled) {
mWrQualifiedOverride.emplace(false);
ConfigureWebRender();
EXPECT_FALSE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderSafeMode) {
mSafeMode = true;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderEarlierThanWindows10) {
mIsWin10OrLater = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderDCompDisabled) {
mWrDCompWinEnabled = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderForceAngleDisabled) {
mWrForceAngle = false;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderD3D11HwAngleDisabled) {
mFeatures.mD3D11HwAngle.UserDisable("", EmptyCString());
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_FALSE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderD3D11HwAngleAndForceAngleDisabled) {
mWrForceAngle = false;
mFeatures.mD3D11HwAngle.UserDisable("", EmptyCString());
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_FALSE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderGPUProcessDisabled) {
mFeatures.mGPUProcess.UserDisable("", EmptyCString());
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_FALSE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderQualifiedAndBlocklistAllowQualified) {
mMockGfxInfo->mStatusWr = nsIGfxInfo::FEATURE_ALLOW_QUALIFIED;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderQualifiedAndBlocklistAllowAlways) {
mIsNightly = false;
mMockGfxInfo->mStatusWr = nsIGfxInfo::FEATURE_ALLOW_ALWAYS;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderNotQualifiedAndBlocklistAllowQualified) {
mWrQualified = false;
mMockGfxInfo->mStatusWr = nsIGfxInfo::FEATURE_ALLOW_QUALIFIED;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderNotQualifiedAndBlocklistAllowAlways) {
mWrQualified = false;
mIsNightly = false;
mMockGfxInfo->mStatusWr = nsIGfxInfo::FEATURE_ALLOW_ALWAYS;
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_TRUE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_TRUE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderIntelBatteryNoPictureCaching) {
mWrPictureCaching = false;
mMockGfxInfo->mHasBattery.ref() = true;
mMockGfxInfo->mVendorId = "0x8086";
ConfigureWebRender();
EXPECT_TRUE(mFeatures.mWrQualified.IsEnabled());
EXPECT_TRUE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_TRUE(mFeatures.mWrAngle.IsEnabled());
EXPECT_TRUE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}
TEST_F(GfxConfigManager, WebRenderIntelBatteryNoHwStretchingNotNightly) {
mIsNightly = false;
mHwStretchingSupport = false;
mScaledResolution = true;
mMockGfxInfo->mHasBattery.ref() = true;
mMockGfxInfo->mVendorId = "0x8086";
ConfigureWebRender();
EXPECT_FALSE(mFeatures.mWrQualified.IsEnabled());
EXPECT_FALSE(mFeatures.mWr.IsEnabled());
EXPECT_FALSE(mFeatures.mWrCompositor.IsEnabled());
EXPECT_FALSE(mFeatures.mWrAngle.IsEnabled());
EXPECT_FALSE(mFeatures.mWrDComp.IsEnabled());
EXPECT_FALSE(mFeatures.mWrPartial.IsEnabled());
EXPECT_TRUE(mFeatures.mHwCompositing.IsEnabled());
EXPECT_TRUE(mFeatures.mGPUProcess.IsEnabled());
EXPECT_TRUE(mFeatures.mD3D11HwAngle.IsEnabled());
}

View File

@ -13,6 +13,7 @@ UNIFIED_SOURCES += [
'TestBSPTree.cpp',
'TestBufferRotation.cpp',
'TestColorNames.cpp',
'TestConfigManager.cpp',
'TestGfxWidgets.cpp',
'TestJobScheduler.cpp',
'TestLayers.cpp',

View File

@ -16,6 +16,7 @@
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/gfx/gfxConfigManager.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/GraphicsMessages.h"
@ -64,7 +65,6 @@
#if defined(XP_WIN)
# include "gfxWindowsPlatform.h"
# include "DisplayConfigWindows.h"
#elif defined(XP_MACOSX)
# include "gfxPlatformMac.h"
# include "gfxQuartzSurface.h"
@ -80,7 +80,6 @@
#ifdef XP_WIN
# include "mozilla/WindowsVersion.h"
# include "mozilla/gfx/DeviceManagerDx.h"
#endif
#ifdef MOZ_WAYLAND
@ -798,82 +797,6 @@ WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
#undef REPORT_INTERNER
#undef REPORT_DATA_STORE
static const char* const WR_ROLLOUT_PREF = "gfx.webrender.all.qualified";
static const bool WR_ROLLOUT_PREF_DEFAULTVALUE = true;
static const char* const WR_ROLLOUT_DEFAULT_PREF =
"gfx.webrender.all.qualified.default";
static const bool WR_ROLLOUT_DEFAULT_PREF_DEFAULTVALUE = false;
static const char* const WR_ROLLOUT_PREF_OVERRIDE =
"gfx.webrender.all.qualified.gfxPref-default-override";
static const char* const WR_ROLLOUT_HW_QUALIFIED_OVERRIDE =
"gfx.webrender.all.qualified.hardware-override";
static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
// If the "gfx.webrender.all.qualified" pref is true we want to enable
// WebRender for qualified hardware. This pref may be set by the Normandy
// Preference Rollout feature. The Normandy pref rollout code sets default
// values on rolled out prefs on every startup. Default pref values are not
// persisted; they only exist in memory for that session. Gfx starts up
// before Normandy does. So it's too early to observe the WR qualified pref
// changed by Normandy rollout on gfx startup. So we add a shutdown observer to
// save the default value on shutdown, and read the saved value on startup
// instead.
class WrRolloutPrefShutdownSaver : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports*, const char* aTopic,
const char16_t*) override {
if (strcmp(PROFILE_BEFORE_CHANGE_TOPIC, aTopic) != 0) {
// Not the observer we're looking for, move along.
return NS_OK;
}
SaveRolloutPref();
// Shouldn't receive another notification, remove the observer.
RefPtr<WrRolloutPrefShutdownSaver> kungFuDeathGrip(this);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return NS_ERROR_FAILURE;
}
observerService->RemoveObserver(this, PROFILE_BEFORE_CHANGE_TOPIC);
return NS_OK;
}
static void AddShutdownObserver() {
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return;
}
RefPtr<WrRolloutPrefShutdownSaver> wrRolloutSaver =
new WrRolloutPrefShutdownSaver();
observerService->AddObserver(wrRolloutSaver, PROFILE_BEFORE_CHANGE_TOPIC,
false);
}
private:
virtual ~WrRolloutPrefShutdownSaver() = default;
void SaveRolloutPref() {
if (Preferences::HasUserValue(WR_ROLLOUT_PREF) ||
Preferences::GetType(WR_ROLLOUT_PREF) == nsIPrefBranch::PREF_INVALID) {
// Don't need to create a backup of default value, because either:
// 1. the user or the WR SHIELD study has set a user pref value, or
// 2. we've not had a default pref set by Normandy that needs to be saved
// for reading before Normandy has started up.
return;
}
bool defaultValue =
Preferences::GetBool(WR_ROLLOUT_PREF, false, PrefValueKind::Default);
Preferences::SetBool(WR_ROLLOUT_DEFAULT_PREF, defaultValue);
}
};
static void FrameRatePrefChanged(const char* aPref, void*) {
int32_t newRate = gfxPlatform::ForceSoftwareVsync()
? gfxPlatform::GetSoftwareVsyncRate()
@ -884,8 +807,6 @@ static void FrameRatePrefChanged(const char* aPref, void*) {
}
}
NS_IMPL_ISUPPORTS(WrRolloutPrefShutdownSaver, nsIObserver)
void gfxPlatform::Init() {
MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
MOZ_RELEASE_ASSERT(!XRE_IsRDDProcess(), "GFX: Not allowed in RDD process.");
@ -928,8 +849,6 @@ void gfxPlatform::Init() {
}
if (XRE_IsParentProcess()) {
WrRolloutPrefShutdownSaver::AddShutdownObserver();
nsCOMPtr<nsIFile> profDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
getter_AddRefs(profDir));
@ -1237,22 +1156,6 @@ static bool IsFeatureSupported(long aFeature, bool aDefault) {
return status == nsIGfxInfo::FEATURE_STATUS_OK;
}
static void ApplyGfxInfoFeature(long aFeature, FeatureState& aFeatureState) {
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString blockId;
int32_t status;
if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
aFeatureState.Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_GFX_INFO"));
} else {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
aFeatureState.Disable(FeatureStatus::Blacklisted,
"Blacklisted by gfxInfo", blockId);
}
}
}
/* static*/
bool gfxPlatform::IsDXInterop2Blocked() {
return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_INTEROP2, false);
@ -2770,140 +2673,12 @@ bool gfxPlatform::WebRenderEnvvarEnabled() {
return (env && *env == '1');
}
static bool WebRenderEnvvarDisabled() {
/*static*/
bool gfxPlatform::WebRenderEnvvarDisabled() {
const char* env = PR_GetEnv("MOZ_WEBRENDER");
return (env && *env == '0');
}
static bool InMarionetteRolloutTest() {
// This pref only ever gets set in test_pref_rollout_workaround, and in
// that case we want to ignore the MOZ_WEBRENDER=0 that will be set by
// the test harness so as to actually make the test work.
return Preferences::HasUserValue(WR_ROLLOUT_HW_QUALIFIED_OVERRIDE);
}
// If the "gfx.webrender.all.qualified" pref is true we want to enable
// WebRender for qualifying hardware. The Normandy pref rollout code sets
// default values on rolled out prefs on every startup, but Gfx starts up
// before Normandy does. So it's too early to observe the WR qualified pref
// default value changed by Normandy rollout here yet. So we have a shutdown
// observer to save the default value on shutdown, and read the saved default
// value here instead, and emulate the behavior of the pref system, with
// respect to default/user values of the rollout pref.
static bool CalculateWrQualifiedPrefValue() {
auto clearPrefOnExit = MakeScopeExit([]() {
// Clear the mirror of the default value of the rollout pref on scope exit,
// if we have one. This ensures the user doesn't mess with the pref.
// If we need it again, we'll re-create it on shutdown.
Preferences::ClearUser(WR_ROLLOUT_DEFAULT_PREF);
});
if (!Preferences::HasUserValue(WR_ROLLOUT_PREF) &&
Preferences::HasUserValue(WR_ROLLOUT_DEFAULT_PREF)) {
// The user has not set a user pref, and we have a default value set by the
// shutdown observer. Let's use this as it should be the value Normandy set
// before startup. WR_ROLLOUT_DEFAULT_PREF should only be set on shutdown by
// the shutdown observer.
// Normandy runs *during* startup, but *after* this code here runs (hence
// the need for the workaround).
// To have a value stored in the WR_ROLLOUT_DEFAULT_PREF pref here, during
// the previous run Normandy must have set a default value on the in-memory
// pref, and on shutdown we stored the default value in this
// WR_ROLLOUT_DEFAULT_PREF user pref. Then once the user restarts, we
// observe this pref. Normandy is the only way a default (not user) value
// can be set for this pref.
return Preferences::GetBool(WR_ROLLOUT_DEFAULT_PREF,
WR_ROLLOUT_DEFAULT_PREF_DEFAULTVALUE);
}
// We don't have a user value for the rollout pref, and we don't have the
// value of the rollout pref at last shutdown stored. So we should fallback
// to using the default. *But* if we're running
// under the Marionette pref rollout work-around test, we may want to override
// the default value expressed here, so we can test the "default disabled;
// rollout pref enabled" case.
// Note that those preferences can't be defined in all.js nor
// StaticPrefsList.h as they would create the pref, leading SaveRolloutPref()
// above to abort early as the pref would have a valid type.
// We also don't want those prefs to appear in about:config.
if (Preferences::HasUserValue(WR_ROLLOUT_PREF_OVERRIDE)) {
return Preferences::GetBool(WR_ROLLOUT_PREF_OVERRIDE);
}
return Preferences::GetBool(WR_ROLLOUT_PREF, WR_ROLLOUT_PREF_DEFAULTVALUE);
}
static FeatureState& WebRenderHardwareQualificationStatus(
bool* aOutGuardedByQualifiedPref) {
FeatureState& featureWebRenderQualified =
gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
featureWebRenderQualified.EnableByDefault();
MOZ_ASSERT(aOutGuardedByQualifiedPref && *aOutGuardedByQualifiedPref);
if (Preferences::HasUserValue(WR_ROLLOUT_HW_QUALIFIED_OVERRIDE)) {
if (!Preferences::GetBool(WR_ROLLOUT_HW_QUALIFIED_OVERRIDE)) {
featureWebRenderQualified.Disable(
FeatureStatus::BlockedOverride, "HW qualification pref override",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_QUALIFICATION_OVERRIDE"));
}
return featureWebRenderQualified;
}
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString failureId;
int32_t status;
if (NS_FAILED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER,
failureId, &status))) {
featureWebRenderQualified.Disable(
FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_NO_GFX_INFO"));
return featureWebRenderQualified;
}
switch (status) {
case nsIGfxInfo::FEATURE_ALLOW_ALWAYS:
#ifndef NIGHTLY_BUILD
// We want to honour ALLOW_ALWAYS on beta and release, but on nightly,
// we still want to perform experiments. A larger population is the most
// useful, demote nightly to merely qualified.
*aOutGuardedByQualifiedPref = false;
break;
#endif
case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED:
*aOutGuardedByQualifiedPref = true;
break;
case nsIGfxInfo::FEATURE_DENIED:
featureWebRenderQualified.Disable(FeatureStatus::Denied,
"Not on allowlist", failureId);
break;
default:
featureWebRenderQualified.Disable(FeatureStatus::Blacklisted,
"No qualified hardware", failureId);
break;
case nsIGfxInfo::FEATURE_STATUS_OK:
MOZ_ASSERT_UNREACHABLE("We should still be rolling out WebRender!");
featureWebRenderQualified.Disable(FeatureStatus::Blocked,
"Not controlled by rollout", failureId);
break;
}
#if !defined(NIGHTLY_BUILD) && defined(XP_WIN)
// Disable WebRender if we don't have DirectComposition
nsAutoString adapterVendorID;
gfxInfo->GetAdapterVendorID(adapterVendorID);
if (adapterVendorID == u"0x8086") {
bool hasBattery = false;
gfxInfo->GetHasBattery(&hasBattery);
if (hasBattery && !gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
featureWebRenderQualified.Disable(
FeatureStatus::Blocked, "Battery Intel requires os compositor",
NS_LITERAL_CSTRING("INTEL_BATTERY_REQUIRES_DCOMP"));
}
}
#endif
return featureWebRenderQualified;
}
void gfxPlatform::InitWebRenderConfig() {
bool prefEnabled = WebRenderPrefEnabled();
bool envvarEnabled = WebRenderEnvvarEnabled();
@ -2921,109 +2696,20 @@ void gfxPlatform::InitWebRenderConfig() {
// The parent process runs through all the real decision-making code
// later in this function. For other processes we still want to report
// the state of the feature for crash reports.
if (UseWebRender()) {
if (gfxVars::UseWebRender()) {
reporter.SetSuccessful();
}
return;
}
// Initialize WebRender native compositor usage
FeatureState& featureComp =
gfxConfig::GetFeature(Feature::WEBRENDER_COMPOSITOR);
featureComp.SetDefaultFromPref("gfx.webrender.compositor", true, false);
if (StaticPrefs::gfx_webrender_compositor_force_enabled_AtStartup()) {
featureComp.UserForceEnable("Force enabled by pref");
}
ApplyGfxInfoFeature(nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR, featureComp);
// Update the gfxConfig feature states.
gfxConfigManager manager;
manager.Init();
manager.ConfigureWebRender();
#ifdef XP_WIN
// Disable native compositor when hardware stretching is not supported. It is
// for avoiding a problem like Bug 1618370.
// XXX Is there a better check for Bug 1618370?
if (!DeviceManagerDx::Get()->CheckHardwareStretchingSupport() &&
HasScaledResolution()) {
featureComp.Disable(
FeatureStatus::Unavailable, "No hardware stretching support",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_HARDWARE_STRETCHING"));
}
#endif
bool guardedByQualifiedPref = true;
FeatureState& featureWebRenderQualified =
WebRenderHardwareQualificationStatus(&guardedByQualifiedPref);
FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
featureWebRender.DisableByDefault(
FeatureStatus::OptIn, "WebRender is an opt-in feature",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
const bool wrQualifiedAll = CalculateWrQualifiedPrefValue();
// envvar works everywhere; note that we need this for testing in CI.
// Prior to bug 1523788, the `prefEnabled` check was only done on Nightly,
// so as to prevent random users from easily enabling WebRender on
// unqualified hardware in beta/release.
if (envvarEnabled) {
featureWebRender.UserEnable("Force enabled by envvar");
} else if (prefEnabled) {
featureWebRender.UserEnable("Force enabled by pref");
} else if (featureWebRenderQualified.IsEnabled()) {
// If the HW is qualified, we enable if either the HW has been qualified
// on the release channel (i.e. it's no longer guarded by the qualified
// pref), or if the qualified pref is enabled.
if (!guardedByQualifiedPref) {
featureWebRender.UserEnable("Qualified in release");
} else if (wrQualifiedAll) {
featureWebRender.UserEnable("Qualified enabled by pref");
}
}
// If the user set the pref to force-disable, let's do that. This will
// override all the other enabling prefs (gfx.webrender.enabled,
// gfx.webrender.all, and gfx.webrender.all.qualified).
if (StaticPrefs::gfx_webrender_force_disabled_AtStartup() ||
(WebRenderEnvvarDisabled() && !InMarionetteRolloutTest())) {
featureWebRender.UserDisable(
"User force-disabled WR",
NS_LITERAL_CSTRING("FEATURE_FAILURE_USER_FORCE_DISABLED"));
}
// HW_COMPOSITING being disabled implies interfacing with the GPU might break
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
featureWebRender.ForceDisable(
FeatureStatus::UnavailableNoHwCompositing,
"Hardware compositing is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"));
}
if (InSafeMode()) {
featureWebRender.ForceDisable(
FeatureStatus::UnavailableInSafeMode, "Safe-mode is enabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
}
#ifdef XP_WIN
if (StaticPrefs::gfx_webrender_force_angle_AtStartup()) {
if (!gfxConfig::IsEnabled(Feature::D3D11_HW_ANGLE)) {
featureWebRender.ForceDisable(
FeatureStatus::UnavailableNoAngle, "ANGLE is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED"));
} else if (
!gfxConfig::IsEnabled(Feature::GPU_PROCESS)
# ifdef NIGHTLY_BUILD
&& !StaticPrefs::
gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup()
# endif
) {
// WebRender with ANGLE relies on the GPU process when on Windows
featureWebRender.ForceDisable(
FeatureStatus::UnavailableNoGpuProcess, "GPU Process is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
} else {
gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER));
}
if (gfxConfig::IsEnabled(Feature::WEBRENDER_ANGLE)) {
gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER));
}
#endif
@ -3066,41 +2752,17 @@ void gfxPlatform::InitWebRenderConfig() {
UpdateAllowSacrificingSubpixelAA();
}
#if defined(MOZ_WIDGET_GTK)
else {
if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
// Hardware compositing should be disabled by default if we aren't using
// WebRender. We had to check if it is enabled at all, because it may
// already have been forced disabled (e.g. safe mode, headless). It may
// still be forced on by the user, and if so, this should have no effect.
gfxConfig::Disable(Feature::HW_COMPOSITING, FeatureStatus::Blocked,
"Acceleration blocked by platform");
}
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING) &&
gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
!StaticPrefs::layers_gpu_process_allow_software_AtStartup()) {
// We have neither WebRender nor OpenGL, we don't allow the GPU process
// for basic compositor, and it wasn't disabled already.
gfxConfig::Disable(Feature::GPU_PROCESS, FeatureStatus::Unavailable,
"Hardware compositing is unavailable.");
}
}
#endif
#ifdef XP_WIN
if (gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT)) {
gfxVars::SetUseWebRenderDCompWin(true);
}
if (Preferences::GetBool("gfx.webrender.flip-sequential", false)) {
// XXX relax win version to windows 8.
if (IsWin10OrLater() && UseWebRender() && gfxVars::UseWebRenderANGLE()) {
gfxVars::SetUseWebRenderFlipSequentialWin(true);
}
}
if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) {
// XXX relax win version to windows 8.
if (IsWin10OrLater() && UseWebRender() && gfxVars::UseWebRenderANGLE()) {
gfxVars::SetUseWebRenderDCompWin(true);
}
}
if (Preferences::GetBool("gfx.webrender.triple-buffering.enabled", false)) {
if (gfxVars::UseWebRenderDCompWin() ||
gfxVars::UseWebRenderFlipSequentialWin()) {
@ -3109,21 +2771,7 @@ void gfxPlatform::InitWebRenderConfig() {
}
#endif
if (!StaticPrefs::gfx_webrender_picture_caching()) {
featureComp.ForceDisable(
FeatureStatus::Unavailable, "Picture caching is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_PICTURE_CACHING_DISABLED"));
}
#ifdef XP_WIN
if (!gfxVars::UseWebRenderDCompWin()) {
featureComp.Disable(
FeatureStatus::Unavailable, "No DirectComposition usage",
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_DIRECTCOMPOSITION"));
}
#endif
if (gfx::gfxConfig::IsEnabled(gfx::Feature::WEBRENDER_COMPOSITOR)) {
if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
gfxVars::SetUseWebRenderCompositor(true);
}
@ -3131,25 +2779,9 @@ void gfxPlatform::InitWebRenderConfig() {
Telemetry::ScalarID::GFX_OS_COMPOSITOR,
gfx::gfxConfig::IsEnabled(gfx::Feature::WEBRENDER_COMPOSITOR));
// Initialize WebRender partial present config.
// Partial present is used only when WebRender compositor is not used.
if (StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup() > 0) {
if (UseWebRender()) {
FeatureState& featurePartial =
gfxConfig::GetFeature(Feature::WEBRENDER_PARTIAL);
featurePartial.EnableByDefault();
if (StaticPrefs::gfx_webrender_picture_caching()) {
gfxVars::SetWebRenderMaxPartialPresentRects(
StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup());
// Call UserEnable() only for reporting to Decision Log.
// If feature is enabled by default. It is not reported to Decision Log.
featurePartial.UserEnable("Enabled");
} else {
featurePartial.ForceDisable(
FeatureStatus::Unavailable, "Picture caching is disabled",
NS_LITERAL_CSTRING("FEATURE_FAILURE_PICTURE_CACHING_DISABLED"));
}
}
if (gfxConfig::IsEnabled(Feature::WEBRENDER_PARTIAL)) {
gfxVars::SetWebRenderMaxPartialPresentRects(
StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup());
}
// Set features that affect WR's RendererOptions

View File

@ -755,6 +755,8 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
static bool WebRenderPrefEnabled();
// you probably want to use gfxVars::UseWebRender() instead of this
static bool WebRenderEnvvarEnabled();
// you probably want to use gfxVars::UseWebRender() instead of this
static bool WebRenderEnvvarDisabled();
void NotifyFrameStats(nsTArray<mozilla::layers::FrameStats>&& aFrameStats);

View File

@ -67,6 +67,7 @@ EXPORTS += [
EXPORTS.mozilla.gfx += [
'D3D11Checks.h',
'DeviceManagerDx.h',
'DisplayConfigWindows.h',
'PrintTarget.h',
'PrintTargetThebes.h',
'ThebesRLBox.h',