Skip to content

Commit

Permalink
Bug 1632259 - Refactor WebRender configuration logic in gfxPlatform t…
Browse files Browse the repository at this point in the history
…o 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
  • Loading branch information
aosmond committed May 4, 2020
1 parent d067969 commit f5baf0e
Show file tree
Hide file tree
Showing 12 changed files with 1,325 additions and 405 deletions.
163 changes: 163 additions & 0 deletions gfx/config/WebRenderRollout.cpp
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions gfx/config/WebRenderRollout.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit f5baf0e

Please sign in to comment.