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 296696 d5687f5a5c673520bb36ffbe22fe9181cd992acc
parent 296695 35d9edda000d6ae13ba9133792831f92faa6d81e
child 296697 277692603a94137f733916afc81780ebe1b215ba
push id19157
push usercbook@mozilla.com
push dateTue, 10 May 2016 10:16:09 +0000
treeherderfx-team@8b4e5ab50377 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1262008
milestone49.0a1
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);
   }