Skip to content

Commit ee2f616

Browse files
author
David Gillen
committed
Update and improve debugging tools for StageGL -> WebGLInspector
1 parent 3e07749 commit ee2f616

2 files changed

Lines changed: 187 additions & 86 deletions

File tree

src/easeljs/display/StageGL.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,8 @@ this.createjs = this.createjs||{};
19601960
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "pMatrix");
19611961
}
19621962

1963+
shaderProgram._type = coverShader ? "cover" : "batch";
1964+
19631965
gl.useProgram(this._activeShader);
19641966
return shaderProgram;
19651967
};
@@ -2117,6 +2119,7 @@ this.createjs = this.createjs||{};
21172119
}
21182120

21192121
this._mainShader = this._activeShader;
2122+
this._mainShader._name = "main";
21202123

21212124
// fill in blanks as it helps the renderer be stable while textures are loading and reduces need for safety code
21222125
var texture = this.getBaseTexture();
@@ -2387,6 +2390,7 @@ this.createjs = this.createjs||{};
23872390
this._setCoverMixShaderParams
23882391
) : this._builtShaders["source-over"].shader // re-use source-over when we don't need a new shader
23892392
};
2393+
if (blendSrc.shader) { shaderData.shader._name = newMode; }
23902394
} catch (e) {
23912395
this._builtShaders[newMode] = undefined;
23922396
console && console.log("SHADER SWITCH FAILURE", e);

src/easeljs/utils/WebGLInspector.js

Lines changed: 183 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,10 @@ this.createjs = this.createjs||{};
4343
* @constructor
4444
* @param {StageGL} stage The default stage to use when none is supplied.
4545
*/
46-
function WebGLInspector(stage) {
47-
this.EventDispatcher_constructor();
48-
49-
// public properties:
50-
51-
// private properties:
52-
/**
53-
* The internal reference to the default stage this Inspector is for.
54-
* @property _stage
55-
* @protected
56-
* @type {StageGL}
57-
*/
58-
this._stage = stage;
59-
60-
// and begin
61-
this._initializeWebGLInspector();
62-
}
46+
function WebGLInspector(stage) {}
6347
var p = createjs.extend(WebGLInspector, createjs.EventDispatcher);
6448

65-
// static:
49+
// properties:
6650
/**
6751
* Alternate output for debugging situations where "console" is not available, i.e. Mobile or remote debugging.
6852
* Expects object with a "log" function that takes any number of params.
@@ -72,84 +56,101 @@ this.createjs = this.createjs||{};
7256
* @static
7357
* @protected
7458
*/
75-
p.alternateOutput = undefined;
59+
WebGLInspector.alternateOutput = undefined;
7660

77-
// getter / setters:
78-
79-
// ctor:
8061
/**
81-
* @method _initializeWebGL
82-
* @protected
62+
* Default stage to assume when non provided
63+
* @type {StageGL}
64+
* @private
8365
*/
84-
p._initializeWebGLInspector = function() {};
66+
WebGLInspector.stage = undefined;
8567

8668
// public methods:
69+
/**
70+
* Utility to call the right logging
71+
* @params *
72+
*/
73+
WebGLInspector.log = function() {
74+
(WebGLInspector.alternateOutput ? WebGLInspector.alternateOutput.log : console.log).apply(this, arguments);
75+
};
76+
8777
/**
8878
* Perform all of the logging reports at once.
8979
* @method log
90-
* @param {StageGL} [stage=this._stage] The stage to log information for.
80+
* @param {StageGL} [stage=WebGLInspector.stage] The stage to log information for.
9181
*/
92-
p.log = function(stage) {
93-
if(!stage){ stage = this._stage; }
82+
WebGLInspector.logAll = function(stage) {
83+
if (!stage){ stage = WebGLInspector.stage; }
9484

95-
console.log("Batches Per Draw", (stage._batchID/stage._drawID).toFixed(4));
96-
this.logContextInfo(stage._webGLContext);
97-
this.logDepth(stage.children, "");
98-
this.logTextureFill(stage);
85+
WebGLInspector.log("Batches Per Draw", (stage._batchID/stage._drawID).toFixed(4));
86+
WebGLInspector.logContextInfo(stage._webGLContext);
87+
WebGLInspector.logDepth(stage.children, "");
88+
WebGLInspector.logTextureFill(stage);
9989
};
10090

10191
/**
102-
* Replace the stage's Draw command with an empty draw command. This is useful for testing performance, and ignoring
103-
* rendering.
104-
* @method toggleGPUDraw
105-
* @param {StageGL} [stage=this._stage] The stage to log information for.
106-
* @param {Boolean} enabled Force enabled. If left undefined, it will toggle.
92+
* Replace the stage's Draw command with a new draw command. This is useful for:
93+
* <ul>
94+
* <li> Testing performance, with no render cost. See `WebGLInspector.drawEmpty` </li>
95+
* <li> Troubleshooting and tracking loaded textures. See `WebGLInspector.drawTexOnBuffer` </li>
96+
* <li> Misc feature or troubleshooting injection </li>
97+
* </ul>
98+
* @method replaceRenderBatchCall
99+
* @param {StageGL} [stage=WebGLInspector.stage] The stage to log information for.
100+
* @param {Function} newFunc .
107101
*/
108-
p.toggleGPUDraw = function(stage, enabled) {
109-
if(!stage){ stage = this._stage; }
102+
WebGLInspector.replaceRenderBatchCall = function(stage, newFunc) {
103+
if (!stage){ stage = WebGLInspector.stage; }
110104

111-
if(enabled === undefined) {
112-
enabled = !!stage._drawBuffers_;
105+
if (newFunc === undefined && stage._renderBatch_) {
106+
stage._renderBatch = stage._renderBatch_;
107+
stage._renderBatch_ = undefined;
108+
} else {
109+
if (stage._renderBatch_ === undefined) {
110+
stage._renderBatch_ = stage._renderBatch;
111+
}
112+
stage._renderBatch = newFunc;
113113
}
114+
};
114115

115-
if(enabled) {
116-
if(stage._drawBuffers_) {
117-
stage._drawBuffers = stage._drawBuffers_;
118-
stage._drawBuffers_ = undefined;
119-
}
116+
/**
117+
* Identical to replaceRenderBatchCall, but affects the Cover command.
118+
* @method replaceRenderCoverCall
119+
* @param {StageGL} [stage=WebGLInspector.stage] The stage to log information for.
120+
* @param {Function} newFunc .
121+
*/
122+
WebGLInspector.replaceRenderCoverCall = function(stage, newFunc) {
123+
if (!stage){ stage = WebGLInspector.stage; }
124+
125+
if (newFunc === undefined && stage._renderCover_) {
126+
stage._renderCover = stage._renderCover_;
127+
stage._renderCover_ = undefined;
120128
} else {
121-
stage._drawBuffers_ = stage._drawBuffers;
122-
stage._drawBuffers = function(gl) {
123-
if(this.vocalDebug) {
124-
var output = "BlankDraw["+ this._drawID +":"+ this._batchID +"] : "+ this.batchReason;
125-
this.alternateOutput?this.alternateOutput.log(output):console.log(output);
126-
}
127-
};
129+
if (stage._renderCover_ === undefined) {
130+
stage._renderCover_ = stage._renderCover;
131+
}
132+
stage._renderCover = newFunc;
128133
}
129134
};
130135

131136
/**
132137
* Recursively walk the entire display tree, log the attached items, and display it in a tree view.
133138
* @method logDepth
134-
* @param {Array} [children=this._stage.children] The children array to walk through.
139+
* @param {Array} [children=WebGLInspector.stage.children] The children array to walk through.
135140
* @param {String} prepend What to prepend to this output from this point onwards.
136141
* @param {Function} customLog Which logging function to use, mainly for filtering or formatting output.
137142
* Fallback hierarchy is customLog -> alternateOutput -> console.log.
138143
*/
139-
p.logDepth = function(children, prepend, customLog) {
140-
if(!children){ children = this._stage.children; }
141-
if(!prepend){ prepend = ""; }
144+
WebGLInspector.logDepth = function(children, prepend, customLog) {
145+
if (!children){ children = WebGLInspector.stage.children; }
146+
if (!prepend){ prepend = ""; }
142147

143148
var l = children.length;
144-
for(var i=0; i<l; i++) {
149+
for (var i=0; i<l; i++) {
145150
var child = children[i];
146-
if(customLog !== undefined){
147-
customLog(prepend+"-", child);
148-
} else {
149-
this.alternateOutput?this.alternateOutput.log(prepend+"-", child):console.log(prepend+"-", child);
150-
}
151-
if(child.children && child.children.length) {
152-
p.logDepth(child.children, "|"+prepend, customLog);
151+
(customLog !== undefined ? customLog : WebGLInspector.log)(prepend+"-", child);
152+
if (child.children && child.children.length) {
153+
WebGLInspector.logDepth(child.children, "|"+prepend, customLog);
153154
}
154155
}
155156
};
@@ -159,8 +160,8 @@ this.createjs = this.createjs||{};
159160
* @method logContextInfo
160161
* @param {WebGLRenderingContext} gl The WebGL context to inspect.
161162
*/
162-
p.logContextInfo = function(gl) {
163-
if(!gl) { gl = this._stage._webGLContext; }
163+
WebGLInspector.logContextInfo = function(gl) {
164+
if (!gl) { gl = WebGLInspector.stage._webGLContext; }
164165
var data = "== LOG:\n";
165166
data += "Max textures per draw: " + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) +"\n";
166167
data += "Max textures active: " + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS) +"\n";
@@ -171,50 +172,48 @@ this.createjs = this.createjs||{};
171172
data += "Max attributes per vertex: " + gl.getParameter(gl.MAX_VERTEX_ATTRIBS) +"\n";
172173
data += "WebGL Version string: " + gl.getParameter(gl.VERSION) +"\n";
173174
data += "======";
174-
this.alternateOutput?this.alternateOutput.log(data):console.log(data);
175+
WebGLInspector.log(data);
175176
};
176177

177178
/**
178179
* Simulate renders and watch what happens for textures moving around between draw calls. A texture moving between
179180
* slots means it was removed and then re-added to draw calls. Performance may be better if it was allowed to stay
180-
* in place.
181+
* on GPU, consider sprite sheeting it with something stable.
181182
* @method logTextureFill
182-
* @param {StageGL} [stage=this._stage] The stage to log information for.
183+
* @param {StageGL} [stage=WebGLInspector.stage] The stage to log information for.
183184
*/
184-
p.logTextureFill = function(stage) {
185-
if(!stage){ stage = this._stage; }
185+
WebGLInspector.logTextureFill = function(stage) {
186+
if (!stage){ stage = WebGLInspector.stage; }
186187

187188
var dict = stage._textureDictionary;
188189
var count = stage._batchTextureCount;
189-
console.log("textureMax:", count);
190+
WebGLInspector.log("textureMax:", count);
190191
var output = [];
191-
for(var n in dict) {
192+
for (var n in dict) {
192193
var str = n.replace(window.location.origin, "");
193194
var tex = dict[n];
194-
var shifted = tex._lastActiveInde?tex._lastActiveIndex == tex._activeIndex:false;
195+
var shifted = tex._lastActiveIndex?tex._lastActiveIndex === tex._activeIndex:false;
195196
output.push({src:str, element:tex, shifted:shifted});
196197
tex._lastActiveIndex = tex._activeIndex;
197198
}
198199

199200
output.sort(function(a,b){
200-
if (a.element._drawID == stage._drawID) { return 1; }
201+
if (a.element._drawID === stage._drawID) { return 1; }
201202
if (a.element._drawID < b.element._drawID) { return -1; }
202203
return 0;
203204
});
204205

205206
var l = output.length;
206-
for(var i = 0; i<l; i++) {
207+
for (var i = 0; i<l; i++) {
207208
var out = output[i];
208-
var active = out.element._drawID == stage._drawID;
209-
var output = "["+out.src+"] "+ (active?"ACTIVE":"stale") +" "+ (out.shifted?"steady":"DRIFT");
210-
this.alternateOutput?this.alternateOutput.log(output, out.element):console.log(output, out.element);
209+
var active = out.element._drawID === stage._drawID;
210+
WebGLInspector.log("["+out.src+"] "+ (active?"ACTIVE":"stale") +" "+ (out.shifted?"steady":"DRIFT"), out.element);
211211
}
212212
};
213213

214-
215214
// protected methods:
216215

217-
// static methods:
216+
// utility methods:
218217
/**
219218
* Utility function for use with {{#crossLink "logDepth"))((/crossLink}}. Logs an item's position and registration.
220219
* Useful to see if something is being forced off screen or has an integer position.
@@ -224,16 +223,114 @@ this.createjs = this.createjs||{};
224223
* @static
225224
*/
226225
WebGLInspector.dispProps = function(prepend, item){
227-
if(!prepend){ prepend = ""; }
226+
if (!prepend){ prepend = ""; }
228227

229228
var p = "\tP:"+ item.x.toFixed(2)+"x"+item.y.toFixed(2) +"\t";
230229
var r = "\tR:"+ item.regX.toFixed(2)+"x"+item.regY.toFixed(2) +"\t";
231230

232-
if(!this.alternateOutput) {
233-
console.log(prepend, item.toString()+"\t", p,r);
231+
WebGLInspector.log(prepend, item.toString()+"\t", p,r);
232+
};
233+
234+
/**
235+
* Utility function for use with {{#crossLink "replaceRenderBatchCall"))((/crossLink}}.
236+
* Performs no GL draw command.
237+
*/
238+
WebGLInspector.drawEmptyBatch = function() {
239+
WebGLInspector.log("BlankBatch["+ this._drawID +":"+ this._batchID +"] : "+ this.batchReason);
240+
this._batchVertexCount = 0;
241+
this._batchID++;
242+
};
243+
244+
/**
245+
* Utility function for use with {{#crossLink "replaceRenderCoverCall"))((/crossLink}}.
246+
* Performs no GL draw command.
247+
*/
248+
WebGLInspector.drawEmptyCover = function() {
249+
WebGLInspector.log("BlankCover["+ this._drawID +":"+ this._batchID +"] : "+ this.batchReason);
250+
this._batchID++;
251+
};
252+
253+
/**
254+
* Utility function for use with {{#crossLink "replaceRenderBatchCall"))((/crossLink}}.
255+
*/
256+
WebGLInspector.drawTexBuffer = function() {
257+
var gl = this._webGLContext;
258+
var texSize = 2048;
259+
260+
// backup
261+
var batchVertexCount = this._batchVertexCount;
262+
var projectionMatrix = this._projectionMatrix;
263+
var shader = this._activeShader;
264+
var vertices = this._vertices;
265+
var indices = this._indices;
266+
var uvs = this._uvs;
267+
var alphas = this._alphas;
268+
var reason = this.batchReason;
269+
270+
// create
271+
if (this._inspectorFrame === undefined) {
272+
this._inspectorFrame = this.getRenderBufferTexture(texSize, texSize);
234273
} else {
235-
this.alternateOutput.log(prepend, item.toString()+"\t", p,r);
274+
gl.bindFramebuffer(gl.FRAMEBUFFER, this._inspectorFrame._frameBuffer);
275+
gl.clear(gl.COLOR_BUFFER_BIT);
236276
}
277+
278+
// configure
279+
this._activeShader = this._mainShader;
280+
gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
281+
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
282+
gl.viewport(0, 0, texSize, texSize);
283+
284+
this._projectionMatrix = new Float32Array([2/texSize, 0, 0, 0, 0, -2/texSize, 0, 0, 0, 0, 1, 0, -1, 1, 0, 1]);
285+
this._vertices = new Float32Array(this._batchTextureCount * 2 * createjs.StageGL.INDICIES_PER_CARD);
286+
this._indices = new Float32Array(this._batchTextureCount * 1 * createjs.StageGL.INDICIES_PER_CARD);
287+
this._uvs = new Float32Array(this._batchTextureCount * 2 * createjs.StageGL.INDICIES_PER_CARD);
288+
this._alphas = new Float32Array(this._batchTextureCount * 1 * createjs.StageGL.INDICIES_PER_CARD);
289+
this.batchReason = "LoadedTextureDebug";
290+
291+
var squareBase = Math.ceil(Math.sqrt(this._batchTextureCount));
292+
for(var i=0; i<this._batchTextureCount; i++) {
293+
var i1 = i*6, i2 = i1*2;
294+
var row = i % squareBase, col = Math.floor(i / squareBase), size = (1/squareBase) * texSize;
295+
this._vertices[i2] = (row)*size; this._vertices[i2+1] = (col)*size;
296+
this._vertices[i2+2] = (row)*size; this._vertices[i2+3] = (col+1)*size;
297+
this._vertices[i2+4] = (row+1)*size; this._vertices[i2+5] = (col)*size;
298+
this._vertices[i2+6] = this._vertices[i2+2]; this._vertices[i2+7] = this._vertices[i2+3];
299+
this._vertices[i2+8] = this._vertices[i2+4]; this._vertices[i2+9] = this._vertices[i2+5];
300+
this._vertices[i2+10] = (row+1)*size; this._vertices[i2+11] = (col+1)*size;
301+
this._uvs[i2] = 0; this._uvs[i2+1] = 1;
302+
this._uvs[i2+2] = 0; this._uvs[i2+3] = 0;
303+
this._uvs[i2+4] = 1; this._uvs[i2+5] = 1;
304+
this._uvs[i2+6] = 0; this._uvs[i2+7] = 0;
305+
this._uvs[i2+8] = 1; this._uvs[i2+9] = 1;
306+
this._uvs[i2+10] = 1; this._uvs[i2+11] = 0;
307+
this._indices[i1] = this._indices[i1+1] = this._indices[i1+2] = this._indices[i1+3] = this._indices[i1+4] = this._indices[i1+5] = i;
308+
this._alphas[i1] = this._alphas[i1+1] = this._alphas[i1+2] = this._alphas[i1+3] = this._alphas[i1+4] = this._alphas[i1+5] = 1;
309+
}
310+
311+
// output
312+
this._batchVertexCount = this._batchTextureCount * createjs.StageGL.INDICIES_PER_CARD;
313+
this._renderBatch_();
314+
this._batchID--;
315+
316+
// reset and perform
317+
gl.bindFramebuffer(gl.FRAMEBUFFER, this._batchTextureOutput._frameBuffer);
318+
319+
var shaderData = this._builtShaders[this._renderMode];
320+
gl.blendEquationSeparate(shaderData.eqRGB, shaderData.eqA);
321+
gl.blendFuncSeparate(shaderData.srcRGB, shaderData.dstRGB, shaderData.srcA, shaderData.dstA);
322+
gl.viewport(0, 0, this._viewportWidth, this._viewportHeight);
323+
324+
this._activeShader = shader;
325+
this._batchVertexCount = batchVertexCount;
326+
this._projectionMatrix = projectionMatrix;
327+
this._vertices = vertices;
328+
this._indices = indices;
329+
this._uvs = uvs;
330+
this._alphas = alphas;
331+
this.batchReason = reason;
332+
333+
this._renderBatch_();
237334
};
238335

239336
createjs.WebGLInspector = createjs.promote(WebGLInspector, "EventDispatcher");

0 commit comments

Comments
 (0)