diff options
Diffstat (limited to 'gfx/config')
-rw-r--r-- | gfx/config/gfxConfig.cpp | 289 | ||||
-rw-r--r-- | gfx/config/gfxConfig.h | 226 | ||||
-rw-r--r-- | gfx/config/gfxFallback.h | 30 | ||||
-rw-r--r-- | gfx/config/gfxFeature.cpp | 313 | ||||
-rw-r--r-- | gfx/config/gfxFeature.h | 136 | ||||
-rw-r--r-- | gfx/config/gfxVarReceiver.h | 25 | ||||
-rw-r--r-- | gfx/config/gfxVars.cpp | 125 | ||||
-rw-r--r-- | gfx/config/gfxVars.h | 149 | ||||
-rw-r--r-- | gfx/config/moz.build | 26 |
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' |