Bug 1156135. Add runtime testing of graphics features. r=mattwoodrow,mossop
authorMason Chang <mchang@mozilla.com>
Tue, 16 Jun 2015 15:49:26 -0700 (2015-06-16)
changeset 249257 a53b5cee6b6f89f5c987b00060ab76f47614da08
parent 249256 c80271e9f1c2e44905a72214800da01590f369c8
child 249258 6c05b6375d9feba15f298a4bdb079cca9e3a4488
push id28923
push userryanvm@gmail.com
push dateWed, 17 Jun 2015 18:57:11 +0000 (2015-06-17)
treeherdermozilla-central@099d6cd6725e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, mossop
bugs1156135
milestone41.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 1156135. Add runtime testing of graphics features. r=mattwoodrow,mossop
browser/installer/package-manifest.in
toolkit/components/gfx/GfxSanityTest.manifest
toolkit/components/gfx/SanityTest.js
toolkit/components/gfx/content/sanitytest.html
toolkit/components/gfx/content/videotest.mp4
toolkit/components/gfx/jar.mn
toolkit/components/gfx/moz.build
toolkit/components/moz.build
widget/GfxInfoBase.cpp
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -906,8 +906,14 @@ bin/libfreebl_32int64_3.so
 #endif
 
 
 ; media
 #ifdef MOZ_EME
 @RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
 @RESPATH@/gmp-clearkey/0.1/clearkey.info
 #endif
+
+; gfx
+#ifdef XP_WIN
+@RESPATH@/components/GfxSanityTest.manifest
+@RESPATH@/components/SanityTest.js
+#endif
new file mode 100644
--- /dev/null
+++ b/toolkit/components/gfx/GfxSanityTest.manifest
@@ -0,0 +1,3 @@
+component {f3a8ca4d-4c83-456b-aee2-6a2cbf11e9bd} SanityTest.js process=main
+contract @mozilla.org/sanity-test;1 {f3a8ca4d-4c83-456b-aee2-6a2cbf11e9bd} process=main
+category profile-after-change SanityTest @mozilla.org/sanity-test;1 process=main
new file mode 100644
--- /dev/null
+++ b/toolkit/components/gfx/SanityTest.js
@@ -0,0 +1,150 @@
+/* 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/. */
+
+"use strict";
+
+const { utils: Cu, interfaces: Ci, classes: Cc, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import('resource://gre/modules/Preferences.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const PAGE_WIDTH=72;
+const PAGE_HEIGHT=136;
+const DRIVER_PREF="sanity-test.driver-version";
+const DEVICE_PREF="sanity-test.device-id";
+const VERSION_PREF="sanity-test.version";
+const DISABLE_VIDEO_PREF="media.hardware-video-decoding.failed";
+const RUNNING_PREF="sanity-test.running";
+
+// GRAPHICS_SANITY_TEST histogram enumeration values
+const TEST_PASSED=0;
+const TEST_FAILED_RENDER=1;
+const TEST_FAILED_VIDEO=2;
+const TEST_CRASHED=3;
+
+function testPixel(ctx, x, y, r, g, b, a, fuzz) {
+  var data = ctx.getImageData(x, y, 1, 1);
+
+  if (Math.abs(data.data[0] - r) <= fuzz &&
+      Math.abs(data.data[1] - g) <= fuzz &&
+      Math.abs(data.data[2] - b) <= fuzz &&
+      Math.abs(data.data[3] - a) <= fuzz) {
+    return true;
+  }
+  return false;
+}
+
+function reportResult(val) {
+  try {
+    let histogram = Services.telemetry.getHistogramById("GRAPHICS_SANITY_TEST");
+    histogram.add(val);
+  } catch (e) {}
+
+  Preferences.set(RUNNING_PREF, false);
+  Services.prefs.savePrefFile(null);
+}
+
+function takeWindowSnapshot(win) {
+  // Take a snapshot of the window contents, and then close the window
+  var canvas = win.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+  canvas.setAttribute("width", PAGE_WIDTH);
+  canvas.setAttribute("height", PAGE_HEIGHT);
+
+  // TODO: drawWindow reads back from the gpu's backbuffer, which won't catch issues with presenting
+  // the front buffer via the window manager. Ideally we'd use an OS level API for reading back
+  // from the desktop itself to get a more accurate test.
+  var ctx = canvas.getContext("2d");
+  var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
+  ctx.drawWindow(win.ownerGlobal, 0, 0, PAGE_WIDTH, PAGE_HEIGHT, "rgb(255,255,255)", flags);
+
+  win.ownerGlobal.close();
+  return ctx;
+}
+
+// Verify that all the 4 coloured squares of the video
+// render as expected (with a tolerance of 64 to allow for
+// yuv->rgb differences between platforms).
+//
+// The video is 64x64, and is split into quadrants of
+// different colours. The top left of the video is 8,72
+// and we test a pixel 10,10 into each quadrant to avoid
+// blending differences at the edges.
+//
+// We allow massive amounts of fuzz for the colours since
+// it can depend hugely on the yuv -> rgb conversion, and
+// we don't want to fail unnecessarily.
+function verifyVideoRendering(ctx) {
+  return testPixel(ctx, 18, 82, 255, 255, 255, 255, 64) &&
+    testPixel(ctx, 50, 82, 0, 255, 0, 255, 64) &&
+    testPixel(ctx, 18, 114, 0, 0, 255, 255, 64) &&
+    testPixel(ctx, 50, 114, 255, 0, 0, 255, 64);
+}
+
+function testGfxFeatures(event) {
+  var win = event.target;
+  var canvas = takeWindowSnapshot(win);
+
+  if (!verifyVideoRendering(canvas)) {
+    reportResult(TEST_FAILED_VIDEO);
+    Preferences.set(DISABLE_VIDEO_PREF, true);
+  } else {
+    reportResult(TEST_PASSED);
+  }
+}
+
+function SanityTest() {}
+SanityTest.prototype = {
+  classID: Components.ID("{f3a8ca4d-4c83-456b-aee2-6a2cbf11e9bd}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference]),
+
+  shouldRunTest: function() {
+    // Only test gfx features if firefox has updated, or if the user has a new
+    // gpu or drivers.
+    var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
+    var xulVersion = appInfo.version;
+    var gfxinfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+
+    if (Preferences.get(RUNNING_PREF, false)) {
+      Preferences.set(DISABLE_VIDEO_PREF, true);
+      reportResult(TEST_CRASHED);
+      return false;
+    }
+
+    // TODO: Handle dual GPU setups
+    if (Preferences.get(DRIVER_PREF, "") == gfxinfo.adapterDriverVersion &&
+        Preferences.get(DEVICE_PREF, "") == gfxinfo.adapterDeviceID &&
+        Preferences.get(VERSION_PREF, "") == xulVersion) {
+      return false;
+    }
+
+    // Enable hardware decoding so we can test again
+    // and record the driver version to detect if the driver changes.
+    Preferences.set(DISABLE_VIDEO_PREF, false);
+    Preferences.set(DRIVER_PREF, gfxinfo.adapterDriverVersion);
+    Preferences.set(DEVICE_PREF, gfxinfo.adapterDeviceID);
+    Preferences.set(VERSION_PREF, xulVersion);
+
+    // Update the prefs so that this test doesn't run again until the next update.
+    Preferences.set(RUNNING_PREF, true);
+    Services.prefs.savePrefFile(null);
+    return true;
+  },
+
+  observe: function(subject, topic, data) {
+    if (topic != "profile-after-change") return;
+    if (!this.shouldRunTest()) return;
+
+    // Open a tiny window to render our test page, and notify us when it's loaded
+    var sanityTest = Services.ww.openWindow(null,
+        "chrome://gfxsanity/content/sanitytest.html",
+        "Test Page",
+        "width=" + PAGE_WIDTH + ",height=" + PAGE_HEIGHT + ",chrome,titlebar=0,scrollbars=0",
+        null);
+    sanityTest.onload = testGfxFeatures;
+  },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SanityTest]);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/gfx/content/sanitytest.html
@@ -0,0 +1,6 @@
+<html>
+    <body>
+        <div style="width:64px; height:64px; background-color:red;"></div>
+        <video src="videotest.mp4"></video>
+    </body>
+</html>
new file mode 100644
index 0000000000000000000000000000000000000000..42cf6e1aa6dfc6260ec535813bc753c3724f96e9
GIT binary patch
literal 1563
zc$|$?UuYaf7@uouEg_;v#3~I;s%X{TWq0p##>0h33_YPiAKEA=tg|z-x7*v@nas>x
z?n)n`1QC?_qIvK^A4L?4Pl7>EDE>hTf(QmmKm<_&`XEU0q3bu7rn$ye9Cl`Y^L@YX
z`{w&*W)VU-GJTn7ks-7X*%`V=y41~N%|!?uj1=bxjog(nVt{l0z%51b!KL}%KKo^(
z`N`U`AMwV0zyHzm>NQ-(R49(!nunEFtGbv>&s1GPK+&uKVQS%-`QzmpeqwPBn2b|U
z%n8{~d1SEXIMuS}xYkW<jBHFzEiW%ux(VYVC3!`t)|8D>iA|OQM@W;1TsJT!A)&sD
z6_5NXW;{#<ZToJ+X*ihVB<*YNJH2Yd>A7wdXWWl@59>|{=us?nA538k6!YDR14c05
zEa`C;SdT7P1d8M>?z?qNV<j>YfT@d(;%S;_Kr_7=MhyVEl=%*9fv__o=f3A2b6p$}
zZ33y=iL{Ju2TL*#QKY%?%N{nd0t;~D;Z%q=iD4C76Jnhvl<x{0oU1_)nq<V-jU>6@
zDkVSyd6;$-=?7F~k{DQ1sF6`5$-xB>6|tO1k&J7oRv5@W;Dq@eV8V#BX@o(T5F3dl
ziVqT7=1D6yAs``n9<+o6?Y2;YX`A=Kx9?3mS7DGPIV`cJJm<7y{F;LY(QQo?*D;tY
z8eB`)>J{~=if|S}VQpHl@V#oq!Amw7->K9AO6zzqlb&CH41hLV`Zb(LI3>6daERcG
zEWrh^$B9<p3NP|kSJ5NImA~}a(f0A`TMtg~hh9AU(U%`zJiWPj{=%Izw=X<DzyHMP
zH($FrG4|ef>zB@Lz5VjZ+7FXYom(AUpSb+}r;`USzx&PD7vt!iuhzE~PNgSb54T=|
z$FP|R(S-<U){Pmuu8sT(!%<X1_S<cx>sfo(v*<tDKIn%M!L(i6v9hvqD|)&piYo;;
z`V-3A2Js7~J=n|04Wb<Vm&gCJpV=KydLv^A0e~~MH(zv*C7il2z~z{wYDZz8@Gx=F
zKItaOS;{S^)POUM0E~CDfz#nF+|RakhZ$U)p)HPeREn?SzqJWdnAfz?Y>4xU{fpfs
zO`FgxYQo&SDPwOtR6v=L177D!42>2)p}Si!f4K4F1FN>&`|a@c<IT0_O6Wkm_4Bt!
zKDSod7(EnYryqvh(i_Na9|zr;ZPmzayD}<<_zv`-!;C$SXEQ#SZJQh}Jsg)JQl`Uc
gJe;H&e&p!L`$kxY_riaj>=fVx=|<D_3Ot>E03pkH_5c6?
new file mode 100644
--- /dev/null
+++ b/toolkit/components/gfx/jar.mn
@@ -0,0 +1,8 @@
+# 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/.
+
+toolkit.jar:
+% content gfxsanity %content/gfxsanity/
+  content/gfxsanity/sanitytest.html   (content/sanitytest.html)
+  content/gfxsanity/videotest.mp4     (content/videotest.mp4)
new file mode 100644
--- /dev/null
+++ b/toolkit/components/gfx/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; c-basic-offset: 4; 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/.
+
+toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
+
+if toolkit == 'windows':
+    EXTRA_COMPONENTS += [
+        'GfxSanityTest.manifest',
+        'SanityTest.js',
+    ]
+
+JAR_MANIFESTS += ['jar.mn']
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -23,16 +23,17 @@ DIRS += [
     'diskspacewatcher',
     'downloads',
     'exthelper',
     'filepicker',
     'filewatcher',
     'finalizationwitness',
     'formautofill',
     'find',
+    'gfx',
     'jsdownloads',
     'mediasniffer',
     'microformats',
     'osfile',
     'parentalcontrols',
     'passwordmgr',
     'perf',
     'places',
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -650,16 +650,17 @@ GfxInfoBase::GfxInfoBase()
 GfxInfoBase::~GfxInfoBase()
 {
 }
 
 nsresult
 GfxInfoBase::Init()
 {
   InitGfxDriverInfoShutdownObserver();
+  gfxPrefs::GetSingleton();
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
     os->AddObserver(this, "blocklist-data-gfxItems", true);
   }
 
   return NS_OK;
 }