mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
Bug 1122766 - Fix canvas debugger to continue recording frames until one with a draw call. r=vp
This commit is contained in:
parent
862950c9f9
commit
c0e7a6e6a0
@ -1,6 +1,7 @@
|
||||
[DEFAULT]
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_raf-begin.html
|
||||
doc_simple-canvas.html
|
||||
doc_simple-canvas-bitmasks.html
|
||||
doc_simple-canvas-deep-stack.html
|
||||
@ -34,6 +35,7 @@ skip-if = e10s # bug 1102301 - leaks while running as a standalone directory in
|
||||
[browser_canvas-frontend-record-01.js]
|
||||
[browser_canvas-frontend-record-02.js]
|
||||
[browser_canvas-frontend-record-03.js]
|
||||
[browser_canvas-frontend-record-04.js]
|
||||
[browser_canvas-frontend-reload-01.js]
|
||||
[browser_canvas-frontend-reload-02.js]
|
||||
[browser_canvas-frontend-slider-01.js]
|
||||
|
@ -22,7 +22,7 @@ function ifTestingSupported() {
|
||||
"A snapshot actor was sent after recording.");
|
||||
|
||||
let animationOverview = yield snapshotActor.getOverview();
|
||||
ok(snapshotActor,
|
||||
ok(animationOverview,
|
||||
"An animation overview could be retrieved after recording.");
|
||||
|
||||
let thumbnails = animationOverview.thumbnails;
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 1122766
|
||||
* Tests that the canvas actor correctly returns from recordAnimationFrame
|
||||
* in the scenario where a loop starts with rAF and has rAF in the beginning
|
||||
* of its loop, when the recording starts before the rAFs start.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_BEGIN_URL);
|
||||
let { window, EVENTS, gFront, SnapshotsListView } = panel.panelWin;
|
||||
loadFrameScripts();
|
||||
|
||||
yield reload(target);
|
||||
|
||||
let recordingFinished = once(window, EVENTS.SNAPSHOT_RECORDING_FINISHED);
|
||||
SnapshotsListView._onRecordButtonClick();
|
||||
|
||||
// Wait until after the recording started to trigger the content.
|
||||
// Use the gFront method rather than the SNAPSHOT_RECORDING_STARTED event
|
||||
// which triggers before the underlying actor call
|
||||
yield waitUntil(function*() { return !(yield gFront.isRecording()); });
|
||||
|
||||
// Start animation in content
|
||||
evalInDebuggee("start();");
|
||||
|
||||
yield recordingFinished;
|
||||
ok(true, "Finished recording a snapshot of the animation loop.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
36
browser/devtools/canvasdebugger/test/doc_raf-begin.html
Normal file
36
browser/devtools/canvasdebugger/test/doc_raf-begin.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Canvas inspector test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas width="128" height="128"></canvas>
|
||||
|
||||
<script type="text/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
var ctx = document.querySelector("canvas").getContext("2d");
|
||||
|
||||
function drawRect(fill, size) {
|
||||
ctx.fillStyle = fill;
|
||||
ctx.fillRect(size[0], size[1], size[2], size[3]);
|
||||
}
|
||||
|
||||
function drawScene() {
|
||||
window.requestAnimationFrame(drawScene);
|
||||
ctx.clearRect(0, 0, 128, 128);
|
||||
drawRect("rgb(192, 192, 192)", [0, 0, 128, 128]);
|
||||
drawRect("rgba(0, 0, 192, 0.5)", [30, 30, 55, 50]);
|
||||
drawRect("rgba(192, 0, 0, 0.5)", [10, 10, 55, 50]);
|
||||
}
|
||||
|
||||
function start () { window.requestAnimationFrame(drawScene); }
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -20,6 +20,7 @@ let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.j
|
||||
let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher");
|
||||
let { CanvasFront } = devtools.require("devtools/server/actors/canvas");
|
||||
let { setTimeout } = devtools.require("sdk/timers");
|
||||
let TiltGL = devtools.require("devtools/tilt/tilt-gl");
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let Toolbox = devtools.Toolbox;
|
||||
@ -33,6 +34,7 @@ const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transpare
|
||||
const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html";
|
||||
const WEBGL_ENUM_URL = EXAMPLE_URL + "doc_webgl-enum.html";
|
||||
const WEBGL_BINDINGS_URL = EXAMPLE_URL + "doc_webgl-bindings.html";
|
||||
const RAF_BEGIN_URL = EXAMPLE_URL + "doc_raf-begin.html";
|
||||
|
||||
// All tests are asynchronous.
|
||||
waitForExplicitFinish();
|
||||
@ -275,3 +277,22 @@ function getSourceActor(aSources, aURL) {
|
||||
let item = aSources.getItemForAttachment(a => a.source.url === aURL);
|
||||
return item ? item.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until a predicate returns true.
|
||||
*
|
||||
* @param function predicate
|
||||
* Invoked once in a while until it returns true.
|
||||
* @param number interval [optional]
|
||||
* How often the predicate is invoked, in milliseconds.
|
||||
*/
|
||||
function *waitUntil (predicate, interval = 10) {
|
||||
if (yield predicate()) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
let deferred = Promise.defer();
|
||||
setTimeout(function() {
|
||||
waitUntil(predicate).then(() => deferred.resolve(true));
|
||||
}, interval);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
@ -229,6 +229,10 @@ let FrameSnapshotFront = protocol.FrontClass(FrameSnapshotActor, {
|
||||
* made when drawing frame inside an animation loop.
|
||||
*/
|
||||
let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
// Reset for each recording, boolean indicating whether or not
|
||||
// any draw calls were called for a recording.
|
||||
_animationContainsDrawCall: false,
|
||||
|
||||
typeName: "canvas",
|
||||
initialize: function(conn, tabActor) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
@ -286,6 +290,16 @@ let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
response: { initialized: RetVal("boolean") }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Returns whether or not the CanvasActor is recording an animation.
|
||||
* Used in tests.
|
||||
*/
|
||||
isRecording: method(function() {
|
||||
return !!this._callWatcher.isRecording();
|
||||
}, {
|
||||
response: { recording: RetVal("boolean") }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Records a snapshot of all the calls made during the next animation frame.
|
||||
* The animation should be implemented via the de-facto requestAnimationFrame
|
||||
@ -300,6 +314,7 @@ let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
return this._currentAnimationFrameSnapshot.promise;
|
||||
}
|
||||
|
||||
this._recordingContainsDrawCall = false;
|
||||
this._callWatcher.eraseRecording();
|
||||
this._callWatcher.resumeRecording();
|
||||
|
||||
@ -340,7 +355,11 @@ let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
_handleAnimationFrame: function(functionCall) {
|
||||
if (!this._animationStarted) {
|
||||
this._handleAnimationFrameBegin();
|
||||
} else {
|
||||
}
|
||||
// Check to see if draw calls occurred yet, as it could be future frames,
|
||||
// like in the scenario where requestAnimationFrame is called to trigger an animation,
|
||||
// and rAF is at the beginning of the animate loop.
|
||||
else if (this._animationContainsDrawCall) {
|
||||
this._handleAnimationFrameEnd(functionCall);
|
||||
}
|
||||
},
|
||||
@ -362,6 +381,7 @@ let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
// previously recorded calls.
|
||||
let functionCalls = this._callWatcher.pauseRecording();
|
||||
this._callWatcher.eraseRecording();
|
||||
this._animationContainsDrawCall = false;
|
||||
|
||||
// Since the animation frame finished, get a hold of the (already retrieved)
|
||||
// canvas pixels to conveniently create a screenshot of the final rendering.
|
||||
@ -410,6 +430,8 @@ let CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
let dimensions = CanvasFront.THUMBNAIL_SIZE;
|
||||
let thumbnail;
|
||||
|
||||
this._animationContainsDrawCall = true;
|
||||
|
||||
// Create a thumbnail on every draw call on the canvas context, to augment
|
||||
// the respective function call actor with this additional data.
|
||||
if (global == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
|
||||
|
Loading…
Reference in New Issue
Block a user