Bug 1274046 - Add FailureId to gfxConfig (FeatureState). WIP draft
authorBenoit Girard <b56girard@gmail.com>
Tue, 24 May 2016 15:48:20 -0400
changeset 370471 c7d9c4795b0b04d00830c802874a6806f3eac302
parent 370285 829d3be6ba648b838ee1953fdfa1a477dace752f
child 370477 acb65bc78b007670cb9cedbec07c866d3d3e8067
push id19066
push userb56girard@gmail.com
push dateTue, 24 May 2016 19:48:35 +0000
bugs1274046
milestone49.0a1
Bug 1274046 - Add FailureId to gfxConfig (FeatureState). WIP MozReview-Commit-ID: HZWbgs0l2mK
gfx/config/gfxConfig.cpp
gfx/config/gfxConfig.h
gfx/config/gfxFeature.cpp
gfx/config/gfxFeature.h
gfx/gl/GLLibraryEGL.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxWindowsPlatform.cpp
--- a/gfx/config/gfxConfig.cpp
+++ b/gfx/config/gfxConfig.cpp
@@ -53,20 +53,21 @@ gfxConfig::SetDefault(Feature aFeature,
 {
   FeatureState& state = sConfig.GetState(aFeature);
   return state.SetDefault(aEnable, aDisableStatus, aDisableMessage);
 }
 
 /* static */ void
 gfxConfig::DisableByDefault(Feature aFeature,
                             FeatureStatus aDisableStatus,
-                            const char* aDisableMessage)
+                            const char* aDisableMessage,
+                            const nsACString& aFailureId)
 {
   FeatureState& state = sConfig.GetState(aFeature);
-  state.DisableByDefault(aDisableStatus, aDisableMessage);
+  state.DisableByDefault(aDisableStatus, aDisableMessage, aFailureId);
 }
 
 /* static */ void
 gfxConfig::EnableByDefault(Feature aFeature)
 {
   FeatureState& state = sConfig.GetState(aFeature);
   state.EnableByDefault();
 }
@@ -87,27 +88,29 @@ gfxConfig::InitOrUpdate(Feature aFeature
                         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)
+gfxConfig::SetFailed(Feature aFeature, FeatureStatus aStatus, const char* aMessage,
+                     const nsACString& aFailureId)
 {
   FeatureState& state = sConfig.GetState(aFeature);
-  state.SetFailed(aStatus, aMessage);
+  state.SetFailed(aStatus, aMessage, aFailureId);
 }
 
 /* static */ void
-gfxConfig::Disable(Feature aFeature, FeatureStatus aStatus, const char* aMessage)
+gfxConfig::Disable(Feature aFeature, FeatureStatus aStatus, const char* aMessage,
+                   const nsACString& aFailureId)
 {
   FeatureState& state = sConfig.GetState(aFeature);
-  state.Disable(aStatus, aMessage);
+  state.Disable(aStatus, aMessage, aFailureId);
 }
 
 /* static */ void
 gfxConfig::UserEnable(Feature aFeature, const char* aMessage)
 {
   FeatureState& state = sConfig.GetState(aFeature);
   state.UserEnable(aMessage);
 }
@@ -115,20 +118,20 @@ gfxConfig::UserEnable(Feature aFeature, 
 /* 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)
+gfxConfig::UserDisable(Feature aFeature, const char* aMessage, const nsACString& aFailureId)
 {
   FeatureState& state = sConfig.GetState(aFeature);
-  state.UserDisable(aMessage);
+  state.UserDisable(aMessage, aFailureId);
 }
 
 /* static */ void
 gfxConfig::Reenable(Feature aFeature, Fallback aFallback)
 {
   FeatureState& state = sConfig.GetState(aFeature);
   MOZ_ASSERT(IsFeatureStatusFailure(state.GetValue()));
 
@@ -214,10 +217,17 @@ 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 nsACString&
+gfxConfig::GetFailureId(Feature aFeature)
+{
+  const FeatureState& state = sConfig.GetState(aFeature);
+  return state.GetFailureId();
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/config/gfxConfig.h
+++ b/gfx/config/gfxConfig.h
@@ -58,76 +58,82 @@ public:
 
   // 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 char* aDisableMessage,
+                               const nsACString& aFailureId = EmptyCString());
   static void EnableByDefault(Feature aFeature);
 
   // 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 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 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 char* aMessage,
+                           const nsACString& aFailureId = EmptyCString())
   {
-    SetFailed(aFeature, aStatus, aMessage);
+    SetFailed(aFeature, aStatus, aMessage, aFailureId);
   }
 
   // Convenience helpers for SetFailed().
   static bool MaybeSetFailed(Feature aFeature,
                              bool aEnable,
                              FeatureStatus aDisableStatus,
-                             const char* aDisableMessage)
+                             const char* aDisableMessage,
+                             const nsACString& aFailureId = EmptyCString())
   {
     if (!aEnable) {
-      SetFailed(aFeature, aDisableStatus, aDisableMessage);
+      SetFailed(aFeature, aDisableStatus, aDisableMessage, aFailureId);
       return false;
     }
     return true;
   }
 
   // Convenience helper for SetFailed().
   static bool MaybeSetFailed(Feature aFeature,
                              FeatureStatus aStatus,
-                             const char* aDisableMessage)
+                             const char* aDisableMessage,
+                             const nsACString& aFailureId = EmptyCString())
   {
     return MaybeSetFailed(
       aFeature,
       (aStatus != FeatureStatus::Available &&
        aStatus != FeatureStatus::ForceEnabled),
       aStatus,
-      aDisableMessage);
+      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);
 
@@ -139,17 +145,17 @@ public:
                            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);
+  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.
@@ -158,16 +164,19 @@ public:
                                  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 nsACString& GetFailureId(Feature aFeature);
+
 private:
   void ForEachFallbackImpl(const FallbackIterCallback& aCallback);
 
 private:
   FeatureState& GetState(Feature aFeature) {
     MOZ_ASSERT(size_t(aFeature) < kNumFeatures);
     return mFeatures[size_t(aFeature)];
   }
--- a/gfx/config/gfxFeature.cpp
+++ b/gfx/config/gfxFeature.cpp
@@ -38,17 +38,18 @@ FeatureState::GetValue() const
 }
 
 bool
 FeatureState::SetDefault(bool aEnable,
                          FeatureStatus aDisableStatus,
                          const char* aDisableMessage)
 {
   if (!aEnable) {
-    DisableByDefault(aDisableStatus, aDisableMessage);
+    DisableByDefault(aDisableStatus, aDisableMessage,
+                     NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED"));
     return false;
   }
   EnableByDefault();
   return true;
 }
 
 void
 FeatureState::SetDefaultFromPref(const char* aPrefName,
@@ -62,30 +63,30 @@ FeatureState::SetDefaultFromPref(const c
     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());
+      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);
+  return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString());
 }
 
 void
 FeatureState::UserEnable(const char* aMessage)
 {
   AssertInitialized();
   SetUser(FeatureStatus::Available, aMessage);
 }
@@ -93,60 +94,68 @@ FeatureState::UserEnable(const char* aMe
 void
 FeatureState::UserForceEnable(const char* aMessage)
 {
   AssertInitialized();
   SetUser(FeatureStatus::ForceEnabled, aMessage);
 }
 
 void
-FeatureState::UserDisable(const char* aMessage)
+FeatureState::UserDisable(const char* aMessage, const nsACString& aFailureId)
 {
   AssertInitialized();
   SetUser(FeatureStatus::Disabled, aMessage);
+  SetFailureId(aFailureId);
 }
 
 void
-FeatureState::Disable(FeatureStatus aStatus, const char* aMessage)
+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)
+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)
+FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage,
+                             const nsACString& aFailureId)
 {
   if (!aEnable) {
-    SetFailed(aStatus, aMessage);
+    SetFailed(aStatus, aMessage, aFailureId);
     return false;
   }
   return true;
 }
 
 bool
-FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage)
+FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
+                             const nsACString& aFailureId)
 {
-  return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage);
+  return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
+                        aFailureId);
 }
 
 bool
 FeatureState::DisabledByDefault() const
 {
   AssertInitialized();
   return mDefault.mStatus != FeatureStatus::Available;
 }
@@ -165,24 +174,26 @@ FeatureState::EnableByDefault()
   MOZ_ASSERT(!mUser.IsInitialized());
   MOZ_ASSERT(!mEnvironment.IsInitialized());
   MOZ_ASSERT(!mRuntime.IsInitialized());
 
   mDefault.Set(FeatureStatus::Available);
 }
 
 void
-FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage)
+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());
@@ -229,16 +240,31 @@ FeatureState::ForEachStatusChange(const 
     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 nsACString&
+FeatureState::GetFailureId() const
+{
+  MOZ_ASSERT(!IsEnabled());
+  return mFailureId;
+}
+
+void
 FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */)
 {
   mStatus = aStatus;
   if (aMessage) {
     PR_snprintf(mMessage, sizeof(mMessage), "%s", aMessage);
   }
 }
 
--- a/gfx/config/gfxFeature.h
+++ b/gfx/config/gfxFeature.h
@@ -5,16 +5,17 @@
  * 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")         \
@@ -34,58 +35,62 @@ class FeatureState
 {
   friend class gfxConfig;
 
  public:
   bool IsEnabled() const;
   FeatureStatus GetValue() const;
 
   void EnableByDefault();
-  void DisableByDefault(FeatureStatus aStatus, const char* aMessage);
+  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);
-  void Disable(FeatureStatus aStatus, const char* aMessage);
-  void ForceDisable(FeatureStatus aStatus, const char* aMessage) {
-    SetFailed(aStatus, 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);
-  bool MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage);
-  bool MaybeSetFailed(FeatureStatus aStatus, const char* aMessage);
+  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 nsACString& GetFailureId() 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;
   bool DisabledByDefault() const;
   const char* GetRuntimeMessage() const;
   bool IsInitialized() const {
     return mDefault.IsInitialized();
   }
 
   void AssertInitialized() const {
     MOZ_ASSERT(IsInitialized());
   }
 
  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;
     }
@@ -106,14 +111,18 @@ class FeatureState
   // 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
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -168,17 +168,18 @@ GetAndInitDisplay(GLLibraryEGL& egl, voi
 static EGLDisplay
 GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl)
 {
     EGLDisplay ret = 0;
 
     FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_ANGLE);
 
     if (!gfxPrefs::WebGLANGLETryD3D11())
-        d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref");
+        d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
+                               NS_LITERAL_CSTRING("FAILURE_ID_ANGLE_PREF"));
 
     if (gfxPrefs::WebGLANGLEForceD3D11())
         d3d11ANGLE.UserForceEnable("User force-enabled D3D11 ANGLE on disabled hardware");
 
     if (gfxConfig::IsForcedOnByUser(Feature::D3D11_ANGLE))
         return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
 
     if (d3d11ANGLE.IsEnabled()) {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2132,34 +2132,37 @@ gfxPlatform::InitCompositorAccelerationP
   FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
 
   // Base value - does the platform allow acceleration?
   if (feature.SetDefault(AccelerateLayersByDefault(),
                          FeatureStatus::Blocked,
                          "Acceleration blocked by platform"))
   {
     if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) {
-      feature.UserDisable("Disabled by pref");
+      feature.UserDisable("Disabled by pref",
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
     } else if (acceleratedEnv && *acceleratedEnv == '0') {
-      feature.UserDisable("Disabled by envvar");
+      feature.UserDisable("Disabled by envvar",
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_ENV"));
     }
   } else {
     if (acceleratedEnv && *acceleratedEnv == '1') {
       feature.UserEnable("Enabled by envvar");
     }
   }
 
   // This has specific meaning elsewhere, so we always record it.
   if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
     feature.UserForceEnable("Force-enabled by pref");
   }
 
   // Safe mode trumps everything.
   if (InSafeMode()) {
-    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode");
+    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
+                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
   }
 }
 
 bool
 gfxPlatform::CanUseHardwareVideoDecoding()
 {
   // this function is called from the compositor thread, so it is not
   // safe to init the prefs etc. from here.
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -563,19 +563,20 @@ gfxWindowsPlatform::CreatePlatformFontLi
 
 // This function will permanently disable D2D for the session. It's intended to
 // be used when, after initially chosing to use Direct2D, we encounter a
 // scenario we can't support.
 //
 // This is called during gfxPlatform::Init() so at this point there should be no
 // DrawTargetD2D/1 instances.
 void
-gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage)
+gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage
+                               const nsACString& aFailureId)
 {
-  gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage);
+  gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId);
   Factory::SetDirect3D11Device(nullptr);
   UpdateBackendPrefs();
 }
 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize,
                                            gfxImageFormat aFormat)
 {
@@ -1885,26 +1886,25 @@ bool DoesD3D11TextureSharingWork(ID3D11D
 }
 
 bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
 {
   return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
 }
 
 static inline bool
-IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage)
+IsGfxInfoStatusOkay(int32_t aFeatu, failureIdre, nsCString* aOutMessage, nsCString& aFailureId)
 {
   nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
   if (!gfxInfo) {
     return true;
   }
 
   int32_t status;
-  nsCString failureId;
-  if (SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, failureId, &status)) &&
+  if (SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
       status != nsIGfxInfo::FEATURE_STATUS_OK)
   {
     aOutMessage->AssignLiteral("#BLOCKLIST_");
     aOutMessage->AppendASCII(failureId.get());
     return false;
   }
 
   return true;
@@ -1936,17 +1936,18 @@ gfxWindowsPlatform::InitializeConfig()
 void
 gfxWindowsPlatform::InitializeD3D9Config()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   FeatureState& d3d9 = gfxConfig::GetFeature(Feature::D3D9_COMPOSITING);
 
   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
-    d3d9.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled");
+    d3d9.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D9_NEED_HWCOMP"));
     return;
   }
 
   if (!IsVistaOrLater()) {
     d3d9.EnableByDefault();
   } else {
     d3d9.SetDefaultFromPref(
       gfxPrefs::GetLayersAllowD3D9FallbackPrefName(),
@@ -1954,53 +1955,58 @@ gfxWindowsPlatform::InitializeD3D9Config
       gfxPrefs::GetLayersAllowD3D9FallbackPrefDefault());
 
     if (!d3d9.IsEnabled() && gfxPrefs::LayersPreferD3D9()) {
       d3d9.UserEnable("Direct3D9 enabled via layers.prefer-d3d9");
     }
   }
 
   nsCString message;
+  nsCString failureId;
   if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &message)) {
-    d3d9.Disable(FeatureStatus::Blacklisted, message.get());
+    d3d9.Disable(FeatureStatus::Blacklisted, message.get(), aFailureId);
   }
 
   if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
     d3d9.UserForceEnable("Hardware compositing is force-enabled");
   }
 }
 
 void
 gfxWindowsPlatform::InitializeD3D11Config()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
 
   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
-    d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled");
+    d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
+                           NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_NEED_HWCOMP"));
     return;
   }
 
   d3d11.EnableByDefault();
 
   // If the user prefers D3D9, act as though they disabled D3D11.
   if (gfxPrefs::LayersPreferD3D9()) {
-    d3d11.UserDisable("Disabled due to user preference for Direct3D 9");
+    d3d11.UserDisable("Disabled due to user preference for Direct3D 9",
+                      NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_PREF"));
     return;
   }
 
   nsCString message;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message)) {
+  nsCString failureId;
+  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) {
     if (IsWARPStable() && !gfxPrefs::LayersD3D11DisableWARP()) {
       // We do not expect hardware D3D11 to work, so we'll try WARP.
       gfxConfig::EnableFallback(Fallback::USE_D3D11_WARP_COMPOSITOR, message.get());
     } else {
       // There is little to no chance of D3D11 working, so just disable it.
-      d3d11.Disable(FeatureStatus::Blacklisted, message.get());
+      d3d11.Disable(FeatureStatus::Blacklisted, message.get(),
+                    failureId);
     }
   }
 
   // Check if the user really, really wants WARP.
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     // Force D3D11 on even if we disabled it.
     d3d11.UserForceEnable("User force-enabled WARP on disabled hardware");
 
@@ -2475,17 +2481,18 @@ gfxWindowsPlatform::InitializeD3D11()
   d3d11Module.disown();
 }
 
 void
 gfxWindowsPlatform::DisableD3D11AfterCrash()
 {
   gfxConfig::Disable(Feature::D3D11_COMPOSITING,
     FeatureStatus::CrashedInHandler,
-    "Crashed while acquiring a Direct3D11 device");
+    "Crashed while acquiring a Direct3D11 device",
+    NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_CRASH");
   ResetD3D11Devices();
 }
 
 void
 gfxWindowsPlatform::ResetD3D11Devices()
 {
   MutexAutoLock lock(mDeviceLock);
 
@@ -2496,32 +2503,35 @@ gfxWindowsPlatform::ResetD3D11Devices()
 }
 
 void
 gfxWindowsPlatform::InitializeD2DConfig()
 {
   FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
 
   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
-    d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D requires Direct3D 11 compositing");
+    d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D requires Direct3D 11 compositing",
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
     return;
   }
   if (!IsVistaOrLater()) {
-    d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D is not available on Windows XP");
+    d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D is not available on Windows XP",
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_XP"));
     return;
   }
 
   d2d1.SetDefaultFromPref(
     gfxPrefs::GetDirect2DDisabledPrefName(),
     false,
     gfxPrefs::GetDirect2DDisabledPrefDefault());
 
   nsCString message;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message)) {
-    d2d1.Disable(FeatureStatus::Blacklisted, message.get());
+  nsCString failureId;
+  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message, failureId)) {
+    d2d1.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
   }
 
   if (!d2d1.IsEnabled() && gfxPrefs::Direct2DForceEnabled()) {
     d2d1.UserForceEnable("Force-enabled via user-preference");
   }
 }
 
 void
@@ -2529,48 +2539,54 @@ gfxWindowsPlatform::InitializeD2D()
 {
   ScopedGfxFeatureReporter d2d1_1("D2D1.1");
 
   FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
 
   // We don't know this value ahead of time, but the user can force-override
   // it, so we use Disable instead of SetFailed.
   if (mIsWARP) {
-    d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP");
+    d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP",
+                 NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_WARP_BLOCK"));
   }
 
   // If we pass all the initial checks, we can proceed to runtime decisions.
   if (!d2d1.IsEnabled()) {
     return;
   }
 
   if (!Factory::SupportsD2D1()) {
-    d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory");
+    d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_FACTORY"));
     return;
   }
 
   if (!mD3D11ContentDevice) {
-    d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device");
+    d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DEVICE"));
     return;
   }
 
   if (!mCompositorD3D11TextureSharingWorks) {
-    d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing");
+    d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_TXT_SHARING"));
     return;
   }
 
   // Using Direct2D depends on DWrite support.
   if (!mDWriteFactory && !InitDWriteSupport()) {
-    d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support");
+    d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DWRITE"));
     return;
   }
 
   // Verify that Direct2D device creation succeeded.
   if (!Factory::SetDirect3D11Device(mD3D11ContentDevice)) {
-    d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device");
+    d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_CREATE_FAILED"));
     return;
   }
 
   MOZ_ASSERT(d2d1.IsEnabled());
   d2d1_1.SetSuccessful();
 }
 
 bool