Bug 1262008 - Add WebGL failure causes to telemetry ping. r=dvander
authorBenoit Girard <b56girard@gmail.com>
Mon, 09 May 2016 13:44:21 -0400
changeset 296643 d5687f5a5c673520bb36ffbe22fe9181cd992acc
parent 296642 35d9edda000d6ae13ba9133792831f92faa6d81e
child 296644 277692603a94137f733916afc81780ebe1b215ba
push id76425
push userb56girard@gmail.com
push dateMon, 09 May 2016 17:46:02 +0000
treeherdermozilla-inbound@d5687f5a5c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1262008
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1262008 - Add WebGL failure causes to telemetry ping. r=dvander MozReview-Commit-ID: 9IVhVNGmaAP
gfx/thebes/gfxPlatform.cpp
toolkit/components/telemetry/TelemetryEnvironment.jsm
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
widget/GfxInfoBase.cpp
widget/GfxInfoBase.h
widget/nsIGfxInfo.idl
widget/windows/GfxInfo.cpp
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -760,16 +760,20 @@ gfxPlatform::Init()
     uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
     if (skiaCacheSize != kDefaultGlyphCacheSize) {
       SkGraphics::SetFontCacheLimit(skiaCacheSize);
     }
 #endif
 
     ScrollMetadata::sNullMetadata = new ScrollMetadata();
     ClearOnShutdown(&ScrollMetadata::sNullMetadata);
+
+    if (obs) {
+      obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
+    }
 }
 
 static bool sLayersIPCIsUp = false;
 
 void
 gfxPlatform::Shutdown()
 {
     if (!gPlatform) {
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -176,21 +176,22 @@ const PREF_DISTRIBUTOR_CHANNEL = "app.di
 const PREF_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion";
 const PREF_APP_PARTNER_BRANCH = "app.partner.";
 const PREF_PARTNER_ID = "mozilla.partner.id";
 const PREF_UPDATE_ENABLED = "app.update.enabled";
 const PREF_UPDATE_AUTODOWNLOAD = "app.update.auto";
 const PREF_SEARCH_COHORT = "browser.search.cohort";
 const PREF_E10S_COHORT = "e10s.rollout.cohort";
 
+const COMPOSITOR_CREATED_TOPIC = "compositor:created";
+const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete";
 const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed";
+const GFX_FEATURES_READY_TOPIC = "gfx-features-ready";
 const SEARCH_ENGINE_MODIFIED_TOPIC = "browser-search-engine-modified";
 const SEARCH_SERVICE_TOPIC = "browser-search-service";
-const COMPOSITOR_CREATED_TOPIC = "compositor:created";
-const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete";
 
 /**
  * Enforces the parameter to a boolean value.
  * @param aValue The input value.
  * @return {Boolean|Object} If aValue is a boolean or a number, returns its truthfulness
  *         value. Otherwise, return null.
  */
 function enforceBoolean(aValue) {
@@ -897,30 +898,31 @@ EnvironmentCache.prototype = {
       if(!("requiresRestart" in options) || !options.requiresRestart) {
         Preferences.ignore(pref, this._onPrefChanged, this);
       }
     }
   },
 
   _addObservers: function () {
     // Watch the search engine change and service topics.
+    Services.obs.addObserver(this, COMPOSITOR_CREATED_TOPIC, false);
+    Services.obs.addObserver(this, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, false);
+    Services.obs.addObserver(this, GFX_FEATURES_READY_TOPIC, false);
     Services.obs.addObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC, false);
     Services.obs.addObserver(this, SEARCH_SERVICE_TOPIC, false);
-    Services.obs.addObserver(this, COMPOSITOR_CREATED_TOPIC, false);
-    Services.obs.addObserver(this, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, false);
   },
 
   _removeObservers: function () {
-    // Remove the search engine change and service observers.
-    Services.obs.removeObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC);
-    Services.obs.removeObserver(this, SEARCH_SERVICE_TOPIC);
     Services.obs.removeObserver(this, COMPOSITOR_CREATED_TOPIC);
     try {
       Services.obs.removeObserver(this, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC);
     } catch(ex) {}
+    Services.obs.removeObserver(this, GFX_FEATURES_READY_TOPIC);
+    Services.obs.removeObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC);
+    Services.obs.removeObserver(this, SEARCH_SERVICE_TOPIC);
   },
 
   observe: function (aSubject, aTopic, aData) {
     this._log.trace("observe - aTopic: " + aTopic + ", aData: " + aData);
     switch (aTopic) {
       case SEARCH_ENGINE_MODIFIED_TOPIC:
         if (aData != "engine-current") {
           return;
@@ -930,16 +932,17 @@ EnvironmentCache.prototype = {
         break;
       case SEARCH_SERVICE_TOPIC:
         if (aData != "init-complete") {
           return;
         }
         // Now that the search engine init is complete, record the default search choice.
         this._updateSearchEngine();
         break;
+      case GFX_FEATURES_READY_TOPIC:
       case COMPOSITOR_CREATED_TOPIC:
         // Full graphics information is not available until we have created at
         // least one off-main-thread-composited window. Thus we wait for the
         // first compositor to be created and then query nsIGfxInfo again.
         this._updateGraphicsFeatures();
         break;
       case DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC:
         // Distribution customizations are applied after final-ui-startup. query
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -576,16 +576,18 @@ function checkSystemSection(data) {
 
     if (gIsWindows || gIsMac) {
       Assert.equal(GFX_VENDOR_ID, gfxData.adapters[0].vendorID);
       Assert.equal(GFX_DEVICE_ID, gfxData.adapters[0].deviceID);
     }
 
     let features = gfxInfo.getFeatures();
     Assert.equal(features.compositor, gfxData.features.compositor);
+    Assert.equal(features.opengl, gfxData.features.opengl);
+    Assert.equal(features.webgl, gfxData.features.webgl);
   }
   catch (e) {}
 }
 
 function checkActiveAddon(data){
   let signedState = mozinfo.addon_signing ? "number" : "undefined";
   // system add-ons have an undefined signState
   if (data.isSystem)
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -1280,41 +1280,58 @@ GfxInfoBase::BuildFeatureStateLog(JSCont
       return;
     }
   });
 
   return true;
 }
 
 void
-GfxInfoBase::DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut)
+GfxInfoBase::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj)
 {
+  JS::Rooted<JSObject*> obj(aCx);
+
+  InitFeatureObject(aCx, aObj, "opengl", nsIGfxInfo::FEATURE_OPENGL_LAYERS, Nothing(), &obj);
+  InitFeatureObject(aCx, aObj, "webgl", nsIGfxInfo::FEATURE_WEBGL_OPENGL, Nothing(), &obj);
 }
 
 bool
 GfxInfoBase::InitFeatureObject(JSContext* aCx,
                                JS::Handle<JSObject*> aContainer,
                                const char* aName,
-                               mozilla::gfx::FeatureStatus aFeatureStatus,
+                               int32_t aFeature,
+                               Maybe<mozilla::gfx::FeatureStatus> aFeatureStatus,
                                JS::MutableHandle<JSObject*> aOutObj)
 {
   JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
   if (!obj) {
     return false;
   }
 
-  const char* status = FeatureStatusToString(aFeatureStatus);
+  nsCString failureId = NS_LITERAL_CSTRING("OK");
+  int32_t unused;
+  if (!NS_SUCCEEDED(GetFeatureStatus(aFeature, failureId, &unused))) {
+    return false;
+  }
 
   // Set "status".
-  {
+  if (aFeatureStatus) {
+    const char* status = FeatureStatusToString(aFeatureStatus.value());
+
     JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, status));
     JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
     JS_SetProperty(aCx, obj, "status", val);
   }
 
+  if (!failureId.IsEmpty()) {
+    JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, failureId.get()));
+    JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
+    JS_SetProperty(aCx, obj, "failureId", val);
+  }
+
   // Add the feature object to the container.
   {
     JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*obj));
     JS_SetProperty(aCx, aContainer, aName, val);
   }
 
   aOutObj.set(obj);
   return true;
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -3,30 +3,31 @@
  *
  * 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_widget_GfxInfoBase_h__
 #define __mozilla_widget_GfxInfoBase_h__
 
-#include "nsIGfxInfo.h"
-#include "nsCOMPtr.h"
-#include "nsIObserver.h"
-#include "nsWeakReference.h"
 #include "GfxDriverInfo.h"
-#include "nsTArray.h"
-#include "nsString.h"
 #include "GfxInfoCollector.h"
+#include "gfxFeature.h"
 #include "gfxTelemetry.h"
-#include "gfxFeature.h"
-#include "nsIGfxInfoDebug.h"
-#include "mozilla/Mutex.h"
 #include "js/Value.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Mutex.h"
+#include "nsCOMPtr.h"
+#include "nsIGfxInfo.h"
+#include "nsIGfxInfoDebug.h"
+#include "nsIObserver.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
 
 namespace mozilla {
 namespace widget {  
 
 class GfxInfoBase : public nsIGfxInfo,
                     public nsIObserver,
                     public nsSupportsWeakReference
 #ifdef DEBUG
@@ -102,17 +103,18 @@ protected:
   // (while subclasses check for more specific ones).
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() = 0;
 
   virtual void DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> obj);
   bool InitFeatureObject(
     JSContext* aCx,
     JS::Handle<JSObject*> aContainer,
     const char* aName,
-    mozilla::gfx::FeatureStatus aFeatureStatus,
+    int32_t aFeature,
+    Maybe<mozilla::gfx::FeatureStatus> aKnownStatus,
     JS::MutableHandle<JSObject*> aOutObj);
 
 private:
   virtual int32_t FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& aDriverInfo,
                                               nsAString& aSuggestedVersion,
                                               int32_t aFeature,
                                               nsACString &aFailureId,
                                               OperatingSystem os);
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -162,16 +162,17 @@ interface nsIGfxInfo : nsISupports
   // Return an object describing all features that have been configured:
   //
   //   "features": [
   //     // For each feature:
   //     {
   //       "name": <string>,
   //       "description": <string>,
   //       "status": <string>,
+  //       "failureId": <string>,    // optional, only covers static failure currently.
   //       "log": [
   //          // One or more log entries, the first denotes the default value.
   //          {
   //            "type": <string>,    // "base", "user", "env", or "runtime"
   //            "status": <string>,
   //            "message": <string>  // Set unless type is "base" and status is "available".
   //          }
   //       ]
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -1253,22 +1253,26 @@ GfxInfo::FindMonitors(JSContext* aCx, JS
     JS_SetElement(aCx, aOutArray, deviceCount++, element);
   }
   return NS_OK;
 }
 
 void
 GfxInfo::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj)
 {
+  // Add the platform neutral features
+  GfxInfoBase::DescribeFeatures(aCx, aObj);
+
   JS::Rooted<JSObject*> obj(aCx);
 
   gfxWindowsPlatform* platform = gfxWindowsPlatform::GetPlatform();
 
   gfx::FeatureStatus d3d11 = gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
-  if (!InitFeatureObject(aCx, aObj, "d3d11", d3d11, &obj)) {
+  if (!InitFeatureObject(aCx, aObj, "d3d11", FEATURE_DIRECT3D_11_ANGLE,
+                         Some(d3d11), &obj)) {
     return;
   }
   if (d3d11 == gfx::FeatureStatus::Available) {
     JS::Rooted<JS::Value> val(aCx, JS::Int32Value(platform->GetD3D11Version()));
     JS_SetProperty(aCx, obj, "version", val);
 
     val = JS::BooleanValue(platform->IsWARP());
     JS_SetProperty(aCx, obj, "warp", val);
@@ -1285,17 +1289,18 @@ GfxInfo::DescribeFeatures(JSContext* aCx
       }
     }
 
     val = JS::BooleanValue(blacklisted);
     JS_SetProperty(aCx, obj, "blacklisted", val);
   }
 
   gfx::FeatureStatus d2d = gfxConfig::GetValue(Feature::DIRECT2D);
-  if (!InitFeatureObject(aCx, aObj, "d2d", d2d, &obj)) {
+  if (!InitFeatureObject(aCx, aObj, "d2d", nsIGfxInfo::FEATURE_DIRECT2D,
+                         Some(d2d), &obj)) {
     return;
   }
   {
     const char* version = "1.1";
     JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, version));
     JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
     JS_SetProperty(aCx, obj, "version", val);
   }