summaryrefslogtreecommitdiffstats
path: root/gfx/config
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/config')
-rw-r--r--gfx/config/gfxConfig.cpp289
-rw-r--r--gfx/config/gfxConfig.h226
-rw-r--r--gfx/config/gfxFallback.h30
-rw-r--r--gfx/config/gfxFeature.cpp313
-rw-r--r--gfx/config/gfxFeature.h136
-rw-r--r--gfx/config/gfxVarReceiver.h25
-rw-r--r--gfx/config/gfxVars.cpp125
-rw-r--r--gfx/config/gfxVars.h149
-rw-r--r--gfx/config/moz.build26
9 files changed, 1319 insertions, 0 deletions
diff --git a/gfx/config/gfxConfig.cpp b/gfx/config/gfxConfig.cpp
new file mode 100644
index 000000000..56a96d2b2
--- /dev/null
+++ b/gfx/config/gfxConfig.cpp
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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 "gfxConfig.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/gfx/GraphicsMessages.h"
+#include "plstr.h"
+
+namespace mozilla {
+namespace gfx {
+
+static UniquePtr<gfxConfig> sConfig;
+
+/* static */ FeatureState&
+gfxConfig::GetFeature(Feature aFeature)
+{
+ return sConfig->GetState(aFeature);
+}
+
+/* static */ bool
+gfxConfig::IsEnabled(Feature aFeature)
+{
+ const FeatureState& state = sConfig->GetState(aFeature);
+ return state.IsEnabled();
+}
+
+/* static */ bool
+gfxConfig::IsDisabledByDefault(Feature aFeature)
+{
+ const FeatureState& state = sConfig->GetState(aFeature);
+ return state.DisabledByDefault();
+}
+
+/* static */ bool
+gfxConfig::IsForcedOnByUser(Feature aFeature)
+{
+ const FeatureState& state = sConfig->GetState(aFeature);
+ return state.IsForcedOnByUser();
+}
+
+/* static */ FeatureStatus
+gfxConfig::GetValue(Feature aFeature)
+{
+ const FeatureState& state = sConfig->GetState(aFeature);
+ return state.GetValue();
+}
+
+/* static */ bool
+gfxConfig::SetDefault(Feature aFeature,
+ bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ return state.SetDefault(aEnable, aDisableStatus, aDisableMessage);
+}
+
+/* static */ void
+gfxConfig::DisableByDefault(Feature aFeature,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage,
+ const nsACString& aFailureId)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.DisableByDefault(aDisableStatus, aDisableMessage, aFailureId);
+}
+
+/* static */ void
+gfxConfig::EnableByDefault(Feature aFeature)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.EnableByDefault();
+}
+
+/* static */ void
+gfxConfig::SetDefaultFromPref(Feature aFeature,
+ const char* aPrefName,
+ bool aIsEnablePref,
+ bool aDefaultValue)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ return state.SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue);
+}
+
+/* static */ bool
+gfxConfig::InitOrUpdate(Feature aFeature,
+ bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ return state.InitOrUpdate(aEnable, aDisableStatus, aDisableMessage);
+}
+
+/* static */ void
+gfxConfig::SetFailed(Feature aFeature, FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.SetFailed(aStatus, aMessage, aFailureId);
+}
+
+/* static */ void
+gfxConfig::Disable(Feature aFeature, FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.Disable(aStatus, aMessage, aFailureId);
+}
+
+/* static */ void
+gfxConfig::UserEnable(Feature aFeature, const char* aMessage)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.UserEnable(aMessage);
+}
+
+/* static */ void
+gfxConfig::UserForceEnable(Feature aFeature, const char* aMessage)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.UserForceEnable(aMessage);
+}
+
+/* static */ void
+gfxConfig::UserDisable(Feature aFeature, const char* aMessage, const nsACString& aFailureId)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ state.UserDisable(aMessage, aFailureId);
+}
+
+/* static */ void
+gfxConfig::Reenable(Feature aFeature, Fallback aFallback)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+ MOZ_ASSERT(IsFeatureStatusFailure(state.GetValue()));
+
+ const char* message = state.GetRuntimeMessage();
+ EnableFallback(aFallback, message);
+ state.SetRuntime(FeatureStatus::Available, nullptr);
+}
+
+/* static */ void
+gfxConfig::Inherit(Feature aFeature, FeatureStatus aStatus)
+{
+ FeatureState& state = sConfig->GetState(aFeature);
+
+ state.Reset();
+
+ switch (aStatus) {
+ case FeatureStatus::Unused:
+ break;
+ case FeatureStatus::Available:
+ gfxConfig::EnableByDefault(aFeature);
+ break;
+ case FeatureStatus::ForceEnabled:
+ gfxConfig::EnableByDefault(aFeature);
+ gfxConfig::UserForceEnable(aFeature, "Inherited from parent process");
+ break;
+ default:
+ gfxConfig::SetDefault(
+ aFeature,
+ false,
+ aStatus,
+ "Disabled in parent process");
+ break;
+ }
+}
+
+/* static */ bool
+gfxConfig::UseFallback(Fallback aFallback)
+{
+ return sConfig->UseFallbackImpl(aFallback);
+}
+
+/* static */ void
+gfxConfig::EnableFallback(Fallback aFallback, const char* aMessage)
+{
+ // Ignore aMessage for now.
+ sConfig->EnableFallbackImpl(aFallback, aMessage);
+}
+
+bool
+gfxConfig::UseFallbackImpl(Fallback aFallback) const
+{
+ return !!(mFallbackBits & (uint64_t(1) << uint64_t(aFallback)));
+}
+
+void
+gfxConfig::EnableFallbackImpl(Fallback aFallback, const char* aMessage)
+{
+ if (!UseFallbackImpl(aFallback)) {
+ MOZ_ASSERT(mNumFallbackLogEntries < kNumFallbacks);
+
+ FallbackLogEntry& entry = mFallbackLog[mNumFallbackLogEntries];
+ mNumFallbackLogEntries++;
+
+ entry.mFallback = aFallback;
+ PL_strncpyz(entry.mMessage, aMessage, sizeof(entry.mMessage));
+ }
+ mFallbackBits |= (uint64_t(1) << uint64_t(aFallback));
+}
+
+struct FeatureInfo {
+ const char* name;
+ const char* description;
+};
+static const FeatureInfo sFeatureInfo[] = {
+#define FOR_EACH_FEATURE(name, type, desc) {#name, desc},
+ GFX_FEATURE_MAP(FOR_EACH_FEATURE)
+#undef FOR_EACH_FEATURE
+ {nullptr, nullptr}
+};
+
+/* static */ void
+gfxConfig::ForEachFeature(const FeatureIterCallback& aCallback)
+{
+ for (size_t i = 0; i < kNumFeatures; i++) {
+ FeatureState& state = GetFeature(static_cast<Feature>(i));
+ if (!state.IsInitialized()) {
+ continue;
+ }
+
+ aCallback(sFeatureInfo[i].name,
+ sFeatureInfo[i].description,
+ state);
+ }
+}
+
+static const char* sFallbackNames[] = {
+#define FOR_EACH_FALLBACK(name) #name,
+ GFX_FALLBACK_MAP(FOR_EACH_FALLBACK)
+#undef FOR_EACH_FALLBACK
+ nullptr
+};
+
+/* static */ void
+gfxConfig::ForEachFallback(const FallbackIterCallback& aCallback)
+{
+ sConfig->ForEachFallbackImpl(aCallback);
+}
+
+void
+gfxConfig::ForEachFallbackImpl(const FallbackIterCallback& aCallback)
+{
+ for (size_t i = 0; i < mNumFallbackLogEntries; i++) {
+ const FallbackLogEntry& entry = mFallbackLog[i];
+ aCallback(sFallbackNames[size_t(entry.mFallback)], entry.mMessage);
+ }
+}
+
+/* static */ const nsCString&
+gfxConfig::GetFailureId(Feature aFeature)
+{
+ const FeatureState& state = sConfig->GetState(aFeature);
+ return state.GetFailureId();
+}
+
+/* static */ void
+gfxConfig::ImportChange(Feature aFeature, const FeatureChange& aChange)
+{
+ if (aChange.type() == FeatureChange::Tnull_t) {
+ return;
+ }
+
+ const FeatureFailure& failure = aChange.get_FeatureFailure();
+ gfxConfig::SetFailed(
+ aFeature,
+ failure.status(),
+ failure.message().get(),
+ failure.failureId());
+}
+
+/* static */ void
+gfxConfig::Init()
+{
+ sConfig = mozilla::MakeUnique<gfxConfig>();
+}
+
+/* static */ void
+gfxConfig::Shutdown()
+{
+ sConfig = nullptr;
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/config/gfxConfig.h b/gfx/config/gfxConfig.h
new file mode 100644
index 000000000..5bff35e22
--- /dev/null
+++ b/gfx/config/gfxConfig.h
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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_gfxConfig_h
+#define mozilla_gfx_config_gfxConfig_h
+
+#include "gfxFeature.h"
+#include "gfxFallback.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Function.h"
+
+namespace mozilla {
+namespace gfx {
+
+// Defined in GraphicsMessages.ipdlh.
+class FeatureChange;
+
+// Manages the history and state of a graphics feature. The flow of a feature
+// is:
+// - A default value, set by all.js, gfxPrefs, or gfxPlatform.
+// - A user value, set by an external value or user pref.
+// - An environment value, determined by system/hardware factors or nsIGfxInfo.
+// - A runtime value, determined by any failures encountered after enabling
+// the feature.
+//
+// Each state change for a feature is recorded in this class.
+class gfxConfig
+{
+public:
+ // Return the full state history of a feature.
+ static FeatureState& GetFeature(Feature aFeature);
+
+ // Query whether a parameter is enabled, taking into account any user or
+ // runtime overrides. The algorithm works as follow:
+ //
+ // 1. If a runtime decision disabled the feature, return false.
+ // 2. If the user force-enabled the feature, return true.
+ // 3. If the environment disabled the feature, return false.
+ // 4. If the user specified a decision, return it.
+ // 5. Return the base setting for the feature.
+ static bool IsEnabled(Feature aFeature);
+
+ // Query the history of a parameter. ForcedOnByUser returns whether or not
+ // the user specifically used a "force" preference to enable the parameter.
+ // IsDisabledByDefault returns whether or not the initial status of the
+ // feature, before adding user prefs and runtime decisions, was disabled.
+ static bool IsForcedOnByUser(Feature aFeature);
+
+ // This returns true if the feature was disabled by default, or was never
+ // initialized to begin with.
+ static bool IsDisabledByDefault(Feature aFeature);
+
+ // Query the status value of a parameter. This is computed similar to
+ // IsEnabled:
+ //
+ // 1. If a runtime failure was set, return it.
+ // 2. If the user force-enabled the feature, return ForceEnabled.
+ // 3. If an environment status was set, return it.
+ // 4. If a user status was set, return it.
+ // 5. Return the default status.
+ static FeatureStatus GetValue(Feature aFeature);
+
+ // Initialize the base value of a parameter. The return value is aEnable.
+ static bool SetDefault(Feature aFeature,
+ bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage);
+ static void DisableByDefault(Feature aFeature,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage,
+ const nsACString& aFailureId = EmptyCString());
+ static void EnableByDefault(Feature aFeature);
+
+ // Inherit a computed value from another process.
+ static void Inherit(Feature aFeature, FeatureStatus aStatus);
+
+ // Set a environment status that overrides both the default and user
+ // statuses; this should be used to disable features based on system
+ // or hardware problems that can be determined up-front. The only
+ // status that can override this decision is the user force-enabling
+ // the feature.
+ static void Disable(Feature aFeature,
+ FeatureStatus aStatus,
+ const char* aMessage,
+ const nsACString& aFailureId = EmptyCString());
+
+ // Given a preference name, infer the default value and whether or not the
+ // user has changed it. |aIsEnablePref| specifies whether or not the pref
+ // is intended to enable a feature (true), or disable it (false).
+ static void SetDefaultFromPref(Feature aFeature,
+ const char* aPrefName,
+ bool aIsEnablePref,
+ bool aDefaultValue);
+
+ // Disable a parameter based on a runtime decision. This permanently
+ // disables the feature, since runtime decisions override all other
+ // decisions.
+ static void SetFailed(Feature aFeature,
+ FeatureStatus aStatus,
+ const char* aMessage,
+ const nsACString& aFailureId = EmptyCString());
+
+ // Force a feature to be disabled permanently. This is the same as
+ // SetFailed(), but the name may be clearer depending on the context.
+ static void ForceDisable(Feature aFeature,
+ FeatureStatus aStatus,
+ const char* aMessage,
+ const nsACString& aFailureId = EmptyCString())
+ {
+ SetFailed(aFeature, aStatus, aMessage, aFailureId);
+ }
+
+ // Convenience helpers for SetFailed().
+ static bool MaybeSetFailed(Feature aFeature,
+ bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage,
+ const nsACString& aFailureId = EmptyCString())
+ {
+ if (!aEnable) {
+ SetFailed(aFeature, aDisableStatus, aDisableMessage, aFailureId);
+ return false;
+ }
+ return true;
+ }
+
+ // Convenience helper for SetFailed().
+ static bool MaybeSetFailed(Feature aFeature,
+ FeatureStatus aStatus,
+ const char* aDisableMessage,
+ const nsACString& aFailureId = EmptyCString())
+ {
+ return MaybeSetFailed(
+ aFeature,
+ (aStatus != FeatureStatus::Available &&
+ aStatus != FeatureStatus::ForceEnabled),
+ aStatus,
+ aDisableMessage, aFailureId);
+ }
+
+ // Re-enables a feature that was previously disabled, by attaching it to a
+ // fallback. The fallback inherits the message that was used for disabling
+ // the feature. This can be used, for example, when D3D11 fails at runtime
+ // but we acquire a second, successful device with WARP.
+ static void Reenable(Feature aFeature, Fallback aFallback);
+
+ // Same as SetDefault, except if the feature already has a default value
+ // set, the new value will be set as a runtime value. This is useful for
+ // when the base value can change (for example, via an update from the
+ // parent process).
+ static bool InitOrUpdate(Feature aFeature,
+ bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage);
+
+ // Set a user status that overrides the base value (but not runtime value)
+ // of a parameter.
+ static void UserEnable(Feature aFeature, const char* aMessage);
+ static void UserForceEnable(Feature aFeature, const char* aMessage);
+ static void UserDisable(Feature aFeature, const char* aMessage, const nsACString& aFailureId = EmptyCString());
+
+ // Query whether a fallback has been toggled.
+ static bool UseFallback(Fallback aFallback);
+
+ // Enable a fallback.
+ static void EnableFallback(Fallback aFallback, const char* aMessage);
+
+ // Run a callback for each initialized FeatureState.
+ typedef mozilla::function<void(const char* aName,
+ const char* aDescription,
+ FeatureState& aFeature)> FeatureIterCallback;
+ static void ForEachFeature(const FeatureIterCallback& aCallback);
+
+ // Run a callback for each enabled fallback.
+ typedef mozilla::function<void(const char* aName, const char* aMsg)>
+ FallbackIterCallback;
+ static void ForEachFallback(const FallbackIterCallback& aCallback);
+
+ // Get the most descriptive failure id message for this feature.
+ static const nsCString& GetFailureId(Feature aFeature);
+
+ static void ImportChange(Feature aFeature, const FeatureChange& aChange);
+
+ static void Init();
+ static void Shutdown();
+
+private:
+ void ForEachFallbackImpl(const FallbackIterCallback& aCallback);
+
+private:
+ FeatureState& GetState(Feature aFeature) {
+ MOZ_ASSERT(size_t(aFeature) < kNumFeatures);
+ return mFeatures[size_t(aFeature)];
+ }
+ const FeatureState& GetState(Feature aFeature) const {
+ MOZ_ASSERT(size_t(aFeature) < kNumFeatures);
+ return mFeatures[size_t(aFeature)];
+ }
+
+ bool UseFallbackImpl(Fallback aFallback) const;
+ void EnableFallbackImpl(Fallback aFallback, const char* aMessage);
+
+private:
+ static const size_t kNumFeatures = size_t(Feature::NumValues);
+ static const size_t kNumFallbacks = size_t(Fallback::NumValues);
+
+private:
+ FeatureState mFeatures[kNumFeatures];
+ uint64_t mFallbackBits;
+
+private:
+ struct FallbackLogEntry {
+ Fallback mFallback;
+ char mMessage[80];
+ };
+
+ FallbackLogEntry mFallbackLog[kNumFallbacks];
+ size_t mNumFallbackLogEntries;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_config_gfxConfig_h
diff --git a/gfx/config/gfxFallback.h b/gfx/config/gfxFallback.h
new file mode 100644
index 000000000..bd7e7ff87
--- /dev/null
+++ b/gfx/config/gfxFallback.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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_gfxFallback_h
+#define mozilla_gfx_config_gfxFallback_h
+
+#include <stdint.h>
+#include "gfxTelemetry.h"
+
+namespace mozilla {
+namespace gfx {
+
+#define GFX_FALLBACK_MAP(_) \
+ /* Name */ \
+ _(PLACEHOLDER_DO_NOT_USE) \
+ /* Add new entries above this comment */
+
+enum class Fallback : uint32_t {
+#define MAKE_ENUM(name) name,
+ GFX_FALLBACK_MAP(MAKE_ENUM)
+#undef MAKE_ENUM
+ NumValues
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_config_gfxFallback_h
diff --git a/gfx/config/gfxFeature.cpp b/gfx/config/gfxFeature.cpp
new file mode 100644
index 000000000..53e291ffe
--- /dev/null
+++ b/gfx/config/gfxFeature.cpp
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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 "gfxFeature.h"
+
+#include "mozilla/Preferences.h"
+#include "mozilla/Sprintf.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace gfx {
+
+bool
+FeatureState::IsEnabled() const
+{
+ return IsInitialized() && IsFeatureStatusSuccess(GetValue());
+}
+
+FeatureStatus
+FeatureState::GetValue() const
+{
+ if (!IsInitialized()) {
+ return FeatureStatus::Unused;
+ }
+
+ if (mRuntime.mStatus != FeatureStatus::Unused) {
+ return mRuntime.mStatus;
+ }
+ if (mUser.mStatus == FeatureStatus::ForceEnabled) {
+ return FeatureStatus::ForceEnabled;
+ }
+ if (mEnvironment.mStatus != FeatureStatus::Unused) {
+ return mEnvironment.mStatus;
+ }
+ if (mUser.mStatus != FeatureStatus::Unused) {
+ return mUser.mStatus;
+ }
+ return mDefault.mStatus;
+}
+
+bool
+FeatureState::SetDefault(bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage)
+{
+ if (!aEnable) {
+ DisableByDefault(aDisableStatus, aDisableMessage,
+ NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED"));
+ return false;
+ }
+ EnableByDefault();
+ return true;
+}
+
+void
+FeatureState::SetDefaultFromPref(const char* aPrefName,
+ bool aIsEnablePref,
+ bool aDefaultValue)
+{
+ bool baseValue = Preferences::GetDefaultBool(aPrefName, aDefaultValue);
+ SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled, "Disabled by default");
+
+ if (Preferences::HasUserValue(aPrefName)) {
+ bool userValue = Preferences::GetBool(aPrefName, aDefaultValue);
+ if (userValue == aIsEnablePref) {
+ nsCString message("Enabled via ");
+ message.AppendASCII(aPrefName);
+ UserEnable(message.get());
+ } else {
+ nsCString message("Disabled via ");
+ message.AppendASCII(aPrefName);
+ UserDisable(message.get(), NS_LITERAL_CSTRING("FEATURE_FAILURE_PREF_OFF"));
+ }
+ }
+}
+
+bool
+FeatureState::InitOrUpdate(bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aDisableMessage)
+{
+ if (!IsInitialized()) {
+ return SetDefault(aEnable, aDisableStatus, aDisableMessage);
+ }
+ return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString());
+}
+
+void
+FeatureState::UserEnable(const char* aMessage)
+{
+ AssertInitialized();
+ SetUser(FeatureStatus::Available, aMessage);
+}
+
+void
+FeatureState::UserForceEnable(const char* aMessage)
+{
+ AssertInitialized();
+ SetUser(FeatureStatus::ForceEnabled, aMessage);
+}
+
+void
+FeatureState::UserDisable(const char* aMessage, const nsACString& aFailureId)
+{
+ AssertInitialized();
+ SetUser(FeatureStatus::Disabled, aMessage);
+ SetFailureId(aFailureId);
+}
+
+void
+FeatureState::Disable(FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ AssertInitialized();
+
+ // We should never bother setting an environment status to "enabled," since
+ // it could override an explicit user decision to disable it.
+ MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
+
+ SetEnvironment(aStatus, aMessage);
+ SetFailureId(aFailureId);
+}
+
+void
+FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ AssertInitialized();
+
+ // We should never bother setting a runtime status to "enabled," since it could
+ // override an explicit user decision to disable it.
+ MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
+
+ SetRuntime(aStatus, aMessage);
+ SetFailureId(aFailureId);
+}
+
+bool
+FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ if (!aEnable) {
+ SetFailed(aStatus, aMessage, aFailureId);
+ return false;
+ }
+ return true;
+}
+
+bool
+FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
+ aFailureId);
+}
+
+bool
+FeatureState::DisabledByDefault() const
+{
+ return mDefault.mStatus != FeatureStatus::Available;
+}
+
+bool
+FeatureState::IsForcedOnByUser() const
+{
+ AssertInitialized();
+ return mUser.mStatus == FeatureStatus::ForceEnabled;
+}
+
+void
+FeatureState::EnableByDefault()
+{
+ // User/runtime decisions should not have been made yet.
+ MOZ_ASSERT(!mUser.IsInitialized());
+ MOZ_ASSERT(!mEnvironment.IsInitialized());
+ MOZ_ASSERT(!mRuntime.IsInitialized());
+
+ mDefault.Set(FeatureStatus::Available);
+}
+
+void
+FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage,
+ const nsACString& aFailureId)
+{
+ // User/runtime decisions should not have been made yet.
+ MOZ_ASSERT(!mUser.IsInitialized());
+ MOZ_ASSERT(!mEnvironment.IsInitialized());
+ MOZ_ASSERT(!mRuntime.IsInitialized());
+
+ mDefault.Set(aStatus, aMessage);
+ SetFailureId(aFailureId);
+}
+
+void
+FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage)
+{
+ // Default decision must have been made, but not runtime or environment.
+ MOZ_ASSERT(mDefault.IsInitialized());
+ MOZ_ASSERT(!mEnvironment.IsInitialized());
+ MOZ_ASSERT(!mRuntime.IsInitialized());
+
+ mUser.Set(aStatus, aMessage);
+}
+
+void
+FeatureState::SetEnvironment(FeatureStatus aStatus, const char* aMessage)
+{
+ // Default decision must have been made, but not runtime.
+ MOZ_ASSERT(mDefault.IsInitialized());
+ MOZ_ASSERT(!mRuntime.IsInitialized());
+
+ mEnvironment.Set(aStatus, aMessage);
+}
+
+void
+FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage)
+{
+ AssertInitialized();
+
+ mRuntime.Set(aStatus, aMessage);
+}
+
+const char*
+FeatureState::GetRuntimeMessage() const
+{
+ MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus));
+ return mRuntime.mMessage;
+}
+
+void
+FeatureState::ForEachStatusChange(const StatusIterCallback& aCallback) const
+{
+ AssertInitialized();
+
+ aCallback("default", mDefault.mStatus, mDefault.MessageOrNull());
+ if (mUser.IsInitialized()) {
+ aCallback("user", mUser.mStatus, mUser.Message());
+ }
+ if (mEnvironment.IsInitialized()) {
+ aCallback("env", mEnvironment.mStatus, mEnvironment.Message());
+ }
+ if (mRuntime.IsInitialized()) {
+ aCallback("runtime", mRuntime.mStatus, mRuntime.Message());
+ }
+}
+
+void
+FeatureState::SetFailureId(const nsACString& aFailureId)
+{
+ if (mFailureId.IsEmpty()) {
+ mFailureId = aFailureId;
+ }
+}
+
+const char*
+FeatureState::GetFailureMessage() const
+{
+ AssertInitialized();
+ MOZ_ASSERT(!IsEnabled());
+
+ if (mRuntime.mStatus != FeatureStatus::Unused &&
+ IsFeatureStatusFailure(mRuntime.mStatus))
+ {
+ return mRuntime.mMessage;
+ }
+ if (mEnvironment.mStatus != FeatureStatus::Unused &&
+ IsFeatureStatusFailure(mEnvironment.mStatus))
+ {
+ return mEnvironment.mMessage;
+ }
+ if (mUser.mStatus != FeatureStatus::Unused &&
+ IsFeatureStatusFailure(mUser.mStatus))
+ {
+ return mUser.mMessage;
+ }
+
+ MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
+ return mDefault.mMessage;
+}
+
+const nsCString&
+FeatureState::GetFailureId() const
+{
+ MOZ_ASSERT(!IsEnabled());
+ return mFailureId;
+}
+
+void
+FeatureState::Reset()
+{
+ mDefault.Set(FeatureStatus::Unused);
+ mUser.Set(FeatureStatus::Unused);
+ mEnvironment.Set(FeatureStatus::Unused);
+ mRuntime.Set(FeatureStatus::Unused);
+ mFailureId = nsCString();
+}
+
+void
+FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */)
+{
+ mStatus = aStatus;
+ if (aMessage) {
+ SprintfLiteral(mMessage, "%s", aMessage);
+ } else {
+ mMessage[0] = '\0';
+ }
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/config/gfxFeature.h b/gfx/config/gfxFeature.h
new file mode 100644
index 000000000..7e7734f6e
--- /dev/null
+++ b/gfx/config/gfxFeature.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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_gfxFeature_h
+#define mozilla_gfx_config_gfxFeature_h
+
+#include <stdint.h>
+#include "gfxTelemetry.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Function.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace gfx {
+
+#define GFX_FEATURE_MAP(_) \
+ /* Name, Type, Description */ \
+ _(HW_COMPOSITING, Feature, "Compositing") \
+ _(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \
+ _(D3D9_COMPOSITING, Feature, "Direct3D9 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") \
+ /* Add new entries above this comment */
+
+enum class Feature : uint32_t {
+#define MAKE_ENUM(name, type, desc) name,
+ GFX_FEATURE_MAP(MAKE_ENUM)
+#undef MAKE_ENUM
+ NumValues
+};
+
+class FeatureState
+{
+ friend class gfxConfig;
+
+ public:
+ bool IsEnabled() const;
+ FeatureStatus GetValue() const;
+
+ void EnableByDefault();
+ void DisableByDefault(FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId);
+ bool SetDefault(bool aEnable, FeatureStatus aDisableStatus, const char* aDisableMessage);
+ bool InitOrUpdate(bool aEnable,
+ FeatureStatus aDisableStatus,
+ const char* aMessage);
+ void SetDefaultFromPref(const char* aPrefName,
+ bool aIsEnablePref,
+ bool aDefaultValue);
+ void UserEnable(const char* aMessage);
+ void UserForceEnable(const char* aMessage);
+ void UserDisable(const char* aMessage, const nsACString& aFailureId);
+ void Disable(FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId);
+ void ForceDisable(FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId) {
+ SetFailed(aStatus, aMessage, aFailureId);
+ }
+ void SetFailed(FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId);
+ bool MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId);
+ bool MaybeSetFailed(FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId);
+
+ // aType is "base", "user", "env", or "runtime".
+ // aMessage may be null.
+ typedef mozilla::function<void(const char* aType,
+ FeatureStatus aStatus,
+ const char* aMessage)> StatusIterCallback;
+ void ForEachStatusChange(const StatusIterCallback& aCallback) const;
+
+ const char* GetFailureMessage() const;
+ const nsCString& GetFailureId() const;
+
+ bool DisabledByDefault() const;
+
+ private:
+ void SetUser(FeatureStatus aStatus, const char* aMessage);
+ void SetEnvironment(FeatureStatus aStatus, const char* aMessage);
+ void SetRuntime(FeatureStatus aStatus, const char* aMessage);
+ bool IsForcedOnByUser() const;
+ const char* GetRuntimeMessage() const;
+ bool IsInitialized() const {
+ return mDefault.IsInitialized();
+ }
+
+ void AssertInitialized() const {
+ MOZ_ASSERT(IsInitialized());
+ }
+
+ // Clear all state.
+ void Reset();
+
+ private:
+ void SetFailureId(const nsACString& aFailureId);
+
+ struct Instance {
+ char mMessage[64];
+ FeatureStatus mStatus;
+
+ void Set(FeatureStatus aStatus, const char* aMessage = nullptr);
+ bool IsInitialized() const {
+ return mStatus != FeatureStatus::Unused;
+ }
+ const char* MessageOrNull() const {
+ return mMessage[0] != '\0' ? mMessage : nullptr;
+ }
+ const char* Message() const {
+ MOZ_ASSERT(MessageOrNull());
+ return mMessage;
+ }
+ };
+
+ // The default state is the state we decide on startup, based on the operating
+ // system or a base preference.
+ //
+ // The user state factors in any changes to preferences that the user made.
+ //
+ // The environment state factors in any additional decisions made, such as
+ // availability or blacklisting.
+ //
+ // The runtime state factors in any problems discovered at runtime.
+ Instance mDefault;
+ Instance mUser;
+ Instance mEnvironment;
+ Instance mRuntime;
+
+ // Store the first reported failureId for now but we might want to track this
+ // by instance later if we need a specific breakdown.
+ nsCString mFailureId;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_config_gfxFeature_h
diff --git a/gfx/config/gfxVarReceiver.h b/gfx/config/gfxVarReceiver.h
new file mode 100644
index 000000000..a3127e0aa
--- /dev/null
+++ b/gfx/config/gfxVarReceiver.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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_gfxVarReceiver_h
+#define mozilla_gfx_config_gfxVarReceiver_h
+
+namespace mozilla {
+namespace gfx {
+
+class GfxVarUpdate;
+
+// This allows downstream processes (such as PContent, PGPU) to listen for
+// updates on gfxVarReceiver.
+class gfxVarReceiver
+{
+public:
+ virtual void OnVarChanged(const GfxVarUpdate& aVar) = 0;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_config_gfxVarReceiver_h
diff --git a/gfx/config/gfxVars.cpp b/gfx/config/gfxVars.cpp
new file mode 100644
index 000000000..6b41d29c9
--- /dev/null
+++ b/gfx/config/gfxVars.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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 "gfxVars.h"
+#include "gfxVarReceiver.h"
+#include "mozilla/dom/ContentChild.h"
+
+namespace mozilla {
+namespace gfx {
+
+StaticAutoPtr<gfxVars> gfxVars::sInstance;
+StaticAutoPtr<nsTArray<gfxVars::VarBase*>> gfxVars::sVarList;
+
+void
+gfxVars::Initialize()
+{
+ if (sInstance) {
+ return;
+ }
+
+ // sVarList must be initialized first since it's used in the constructor for
+ // sInstance.
+ sVarList = new nsTArray<gfxVars::VarBase*>();
+ sInstance = new gfxVars;
+
+ // Like Preferences, we want content to synchronously get initial data on
+ // init. Note the GPU process is not handled here - it cannot send sync
+ // messages, so instead the initial data is pushed down.
+ if (XRE_IsContentProcess()) {
+ InfallibleTArray<GfxVarUpdate> vars;
+ dom::ContentChild::GetSingleton()->SendGetGfxVars(&vars);
+ for (const auto& var : vars) {
+ ApplyUpdate(var);
+ }
+ }
+}
+
+gfxVars::gfxVars()
+{
+}
+
+void
+gfxVars::Shutdown()
+{
+ sInstance = nullptr;
+ sVarList = nullptr;
+}
+
+/* static */ void
+gfxVars::ApplyUpdate(const GfxVarUpdate& aUpdate)
+{
+ // Only subprocesses receive updates and apply them locally.
+ MOZ_ASSERT(!XRE_IsParentProcess());
+ sVarList->ElementAt(aUpdate.index())->SetValue(aUpdate.value());
+}
+
+/* static */ void
+gfxVars::AddReceiver(gfxVarReceiver* aReceiver)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Don't double-add receivers, in case a broken content process sends two
+ // init messages.
+ if (!sInstance->mReceivers.Contains(aReceiver)) {
+ sInstance->mReceivers.AppendElement(aReceiver);
+ }
+}
+
+/* static */ void
+gfxVars::RemoveReceiver(gfxVarReceiver* aReceiver)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (sInstance) {
+ sInstance->mReceivers.RemoveElement(aReceiver);
+ }
+}
+
+/* static */ nsTArray<GfxVarUpdate>
+gfxVars::FetchNonDefaultVars()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(sVarList);
+
+ nsTArray<GfxVarUpdate> updates;
+ for (size_t i = 0; i < sVarList->Length(); i++) {
+ VarBase* var = sVarList->ElementAt(i);
+ if (var->HasDefaultValue()) {
+ continue;
+ }
+
+ GfxVarValue value;
+ var->GetValue(&value);
+
+ updates.AppendElement(GfxVarUpdate(i, value));
+ }
+
+ return updates;
+}
+
+gfxVars::VarBase::VarBase()
+{
+ mIndex = gfxVars::sVarList->Length();
+ gfxVars::sVarList->AppendElement(this);
+}
+
+void
+gfxVars::NotifyReceivers(VarBase* aVar)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ GfxVarValue value;
+ aVar->GetValue(&value);
+
+ GfxVarUpdate update(aVar->Index(), value);
+ for (auto& receiver : mReceivers) {
+ receiver->OnVarChanged(update);
+ }
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/config/gfxVars.h b/gfx/config/gfxVars.h
new file mode 100644
index 000000000..2fd2689ed
--- /dev/null
+++ b/gfx/config/gfxVars.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
+/* 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_gfxVars_h
+#define mozilla_gfx_config_gfxVars_h
+
+#include <stdint.h>
+#include "mozilla/Assertions.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/gfx/GraphicsMessages.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/gfx/Types.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+namespace gfx {
+
+class gfxVarReceiver;
+
+// Generator for graphics vars.
+#define GFX_VARS_LIST(_) \
+ /* C++ Name, Data Type, Default Value */ \
+ _(BrowserTabsRemoteAutostart, bool, false) \
+ _(ContentBackend, BackendType, BackendType::NONE) \
+ _(TileSize, IntSize, IntSize(-1, -1)) \
+ _(UseXRender, bool, false) \
+ _(OffscreenFormat, gfxImageFormat, mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
+ _(RequiresAcceleratedGLContextForCompositorOGL, bool, false) \
+ _(CanUseHardwareVideoDecoding, bool, false) \
+ _(PDMWMFDisableD3D11Dlls, nsCString, nsCString()) \
+ _(PDMWMFDisableD3D9Dlls, nsCString, nsCString()) \
+
+ /* Add new entries above this line. */
+
+// Some graphics settings are computed on the UI process and must be
+// communicated to content and GPU processes. gfxVars helps facilitate
+// this. Its function is similar to gfxPrefs, except rather than hold
+// user preferences, it holds dynamically computed values.
+//
+// Each variable in GFX_VARS_LIST exposes the following static methods:
+//
+// const DataType& CxxName();
+// void SetCxxName(const DataType& aValue);
+//
+// Note that the setter may only be called in the UI process; a gfxVar must be
+// a variable that is determined in the UI process and pushed to child
+// processes.
+class gfxVars final
+{
+public:
+ static void Initialize();
+ static void Shutdown();
+
+ static void ApplyUpdate(const GfxVarUpdate& aUpdate);
+ static void AddReceiver(gfxVarReceiver* aReceiver);
+ static void RemoveReceiver(gfxVarReceiver* aReceiver);
+
+ // Return a list of updates for all variables with non-default values.
+ static nsTArray<GfxVarUpdate> FetchNonDefaultVars();
+
+public:
+ // Each variable must expose Set and Get methods for IPDL.
+ class VarBase
+ {
+ public:
+ VarBase();
+ virtual void SetValue(const GfxVarValue& aValue) = 0;
+ virtual void GetValue(GfxVarValue* aOutValue) = 0;
+ virtual bool HasDefaultValue() const = 0;
+ size_t Index() const {
+ return mIndex;
+ }
+ private:
+ size_t mIndex;
+ };
+
+private:
+ static StaticAutoPtr<gfxVars> sInstance;
+ static StaticAutoPtr<nsTArray<VarBase*>> sVarList;
+
+ template <typename T, T Default()>
+ class VarImpl final : public VarBase
+ {
+ public:
+ VarImpl()
+ : mValue(Default())
+ {}
+ void SetValue(const GfxVarValue& aValue) override {
+ aValue.get(&mValue);
+ }
+ void GetValue(GfxVarValue* aOutValue) override {
+ *aOutValue = GfxVarValue(mValue);
+ }
+ bool HasDefaultValue() const override {
+ return mValue == Default();
+ }
+ const T& Get() const {
+ return mValue;
+ }
+ // Return true if the value changed, false otherwise.
+ bool Set(const T& aValue) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ if (mValue == aValue) {
+ return false;
+ }
+ mValue = aValue;
+ return true;
+ }
+ private:
+ T mValue;
+ };
+
+#define GFX_VAR_DECL(CxxName, DataType, DefaultValue) \
+private: \
+ static DataType Get##CxxName##Default() { \
+ return DefaultValue; \
+ } \
+ VarImpl<DataType, Get##CxxName##Default> mVar##CxxName; \
+public: \
+ static const DataType& CxxName() { \
+ return sInstance->mVar##CxxName.Get(); \
+ } \
+ static void Set##CxxName(const DataType& aValue) { \
+ if (sInstance->mVar##CxxName.Set(aValue)) { \
+ sInstance->NotifyReceivers(&sInstance->mVar##CxxName); \
+ } \
+ }
+
+ GFX_VARS_LIST(GFX_VAR_DECL)
+#undef GFX_VAR_DECL
+
+private:
+ gfxVars();
+
+ void NotifyReceivers(VarBase* aVar);
+
+private:
+ nsTArray<gfxVarReceiver*> mReceivers;
+};
+
+#undef GFX_VARS_LIST
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_config_gfxVars_h
diff --git a/gfx/config/moz.build b/gfx/config/moz.build
new file mode 100644
index 000000000..2b8f9e7fc
--- /dev/null
+++ b/gfx/config/moz.build
@@ -0,0 +1,26 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS += [
+ 'gfxConfig.h',
+ 'gfxFallback.h',
+ 'gfxFeature.h',
+]
+
+EXPORTS.mozilla.gfx += [
+ 'gfxVarReceiver.h',
+ 'gfxVars.h',
+]
+
+UNIFIED_SOURCES += [
+ 'gfxConfig.cpp',
+ 'gfxFeature.cpp',
+ 'gfxVars.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'