Add OS snapshotting to the gfx sanity test and report whether or not it matches the compositing test results. (bug 1173117 part 4, r=mattwoodrow,vladan)
This commit is contained in:
@@ -17,6 +17,7 @@ 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";
|
||||
const OS_SNAPSHOT_TIMEOUT_SEC=3;
|
||||
|
||||
// GRAPHICS_SANITY_TEST histogram enumeration values
|
||||
const TEST_PASSED=0;
|
||||
@@ -24,6 +25,12 @@ const TEST_FAILED_RENDER=1;
|
||||
const TEST_FAILED_VIDEO=2;
|
||||
const TEST_CRASHED=3;
|
||||
|
||||
// GRAPHICS_SANITY_TEST_OS_SNAPSHOT histogram enumeration values
|
||||
const SNAPSHOT_OK=0;
|
||||
const SNAPSHOT_INCORRECT=1;
|
||||
const SNAPSHOT_ERROR=2;
|
||||
const SNAPSHOT_TIMEOUT=3;
|
||||
|
||||
function testPixel(ctx, x, y, r, g, b, a, fuzz) {
|
||||
var data = ctx.getImageData(x, y, 1, 1);
|
||||
|
||||
@@ -46,9 +53,12 @@ function reportResult(val) {
|
||||
Services.prefs.savePrefFile(null);
|
||||
}
|
||||
|
||||
function reportSnapshotResult(val) {
|
||||
let histogram = Services.telemetry.getHistogramById("GRAPHICS_SANITY_TEST_OS_SNAPSHOT");
|
||||
histogram.add(val);
|
||||
}
|
||||
|
||||
function takeWindowSnapshot(win, ctx) {
|
||||
// Take a snapshot of the window contents, and then close the window
|
||||
//
|
||||
// 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.
|
||||
@@ -56,6 +66,30 @@ function takeWindowSnapshot(win, ctx) {
|
||||
ctx.drawWindow(win.ownerGlobal, 0, 0, PAGE_WIDTH, PAGE_HEIGHT, "rgb(255,255,255)", flags);
|
||||
}
|
||||
|
||||
function takeWidgetSnapshot(win, canvas, ctx) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawWidgetAsOnScreen(win.ownerGlobal);
|
||||
}
|
||||
|
||||
function testWidgetSnapshot(win, canvas, ctx) {
|
||||
try {
|
||||
takeWidgetSnapshot(win, canvas, ctx);
|
||||
if (verifyVideoRendering(ctx)) {
|
||||
reportSnapshotResult(SNAPSHOT_OK);
|
||||
} else {
|
||||
reportSnapshotResult(SNAPSHOT_INCORRECT);
|
||||
}
|
||||
} catch (e) {
|
||||
reportSnapshotResult(SNAPSHOT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
function setTimeout(aMs, aCallback) {
|
||||
var timer = Components.classes["@mozilla.org/timer;1"]
|
||||
.createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback(aCallback, aMs, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
// 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).
|
||||
@@ -92,11 +126,27 @@ let listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
win: null,
|
||||
utils: null,
|
||||
canvas: null,
|
||||
|
||||
// State flow:
|
||||
// onload -> WM_PAINT -> MozAfterPaint -> ready
|
||||
// WM_PAINT -> onload -> MozAfterPaint -> ready
|
||||
//
|
||||
// We always wait for the low-level paint message because this is what tells
|
||||
// us whether or not the OS has actually started drawing.
|
||||
windowLoaded: false, // onload event has fired.
|
||||
windowReady: false, // widget has received an OS-level paint request.
|
||||
|
||||
scheduleTest: function(win) {
|
||||
this.win = win;
|
||||
this.win.onload = this.onWindowLoaded.bind(this);
|
||||
this.utils = this.win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
let observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Components.interfaces.nsIObserverService);
|
||||
observerService.addObserver(this, "widget-first-paint", false);
|
||||
},
|
||||
|
||||
onWindowLoaded: function() {
|
||||
@@ -105,10 +155,83 @@ let listener = {
|
||||
this.canvas.setAttribute("height", PAGE_HEIGHT);
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
|
||||
testCompositor(this.win, this.ctx);
|
||||
// Perform the compositor backbuffer test, which currently we use for
|
||||
// actually deciding whether to enable hardware media decoding.
|
||||
if (!testCompositor(this.win, this.ctx)) {
|
||||
this.endTest();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait to perform the OS snapshot test. Since this waits for a series of
|
||||
// events to occur, we set a timeout in case nothing happens.
|
||||
setTimeout(OS_SNAPSHOT_TIMEOUT_SEC * 1000, (() => {
|
||||
if (this.win) {
|
||||
reportSnapshotResult(SNAPSHOT_TIMEOUT);
|
||||
this.endTest();
|
||||
}
|
||||
}));
|
||||
|
||||
this.windowLoaded = true;
|
||||
if (this.windowReady) {
|
||||
this.waitForPaintsFlushed();
|
||||
}
|
||||
},
|
||||
|
||||
// Watch for the first OS-level paint message to the window.
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aSubject != this.win || aTopic != "widget-first-paint") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.windowReady = true;
|
||||
if (this.windowLoaded) {
|
||||
this.waitForPaintsFlushed();
|
||||
}
|
||||
},
|
||||
|
||||
// Wait for all layout-induced paints to flush.
|
||||
waitForPaintsFlushed: function() {
|
||||
// If the test ended prematurely due to a timeout, just ignore the event.
|
||||
if (!this.win) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.utils.isMozAfterPaintPending) {
|
||||
let paintListener = (() => {
|
||||
if (this.utils && this.utils.isMozAfterPaintPending) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.win.removeEventListener("MozAfterPaint", paintListener);
|
||||
|
||||
if (this.utils) {
|
||||
// Painting is finished, we will fail the above
|
||||
// isMozAfterPaintPending test now.
|
||||
this.waitForPaintsFlushed();
|
||||
}
|
||||
});
|
||||
this.win.addEventListener("MozAfterPaint", paintListener);
|
||||
return;
|
||||
}
|
||||
|
||||
testWidgetSnapshot(this.win, this.canvas, this.ctx);
|
||||
this.endTest();
|
||||
},
|
||||
|
||||
endTest: function() {
|
||||
if (!this.win) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.win.ownerGlobal.close();
|
||||
},
|
||||
this.win = null;
|
||||
this.utils = null;
|
||||
this.canvas = null;
|
||||
|
||||
let observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Components.interfaces.nsIObserverService);
|
||||
observerService.removeObserver(this, "widget-first-paint");
|
||||
}
|
||||
};
|
||||
|
||||
function SanityTest() {}
|
||||
|
||||
Reference in New Issue
Block a user