Try updating to Khronos webgl-debug.js version

This commit is contained in:
Joshua Granick
2015-06-11 13:24:54 -07:00
parent ef808718bc
commit 61bb2516f8

View File

@@ -1,6 +1,25 @@
//Copyright (c) 2009 The Chromium Authors. All rights reserved. /*
//Use of this source code is governed by a BSD-style license that can be ** Copyright (c) 2012 The Khronos Group Inc.
//found in the LICENSE file. **
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
// Various functions for helping debug WebGL apps. // Various functions for helping debug WebGL apps.
@@ -17,84 +36,123 @@ var log = function(msg) {
}; };
/** /**
* Which arguements are enums. * Wrapped error logging function.
* @type {!Object.<number, string>} * @param {string} msg Message to log.
*/
var error = function(msg) {
if (window.console && window.console.error) {
window.console.error(msg);
} else {
log(msg);
}
};
/**
* Which arguments are enums based on the number of arguments to the function.
* So
* 'texImage2D': {
* 9: { 0:true, 2:true, 6:true, 7:true },
* 6: { 0:true, 2:true, 3:true, 4:true },
* },
*
* means if there are 9 arguments then 6 and 7 are enums, if there are 6
* arguments 3 and 4 are enums
*
* @type {!Object.<number, !Object.<number, string>}
*/ */
var glValidEnumContexts = { var glValidEnumContexts = {
// Generic setters and getters // Generic setters and getters
'enable': { 0:true }, 'enable': {1: { 0:true }},
'disable': { 0:true }, 'disable': {1: { 0:true }},
'getParameter': { 0:true }, 'getParameter': {1: { 0:true }},
// Rendering // Rendering
'drawArrays': { 0:true }, 'drawArrays': {3:{ 0:true }},
'drawElements': { 0:true, 2:true }, 'drawElements': {4:{ 0:true, 2:true }},
// Shaders // Shaders
'createShader': { 0:true }, 'createShader': {1: { 0:true }},
'getShaderParameter': { 1:true }, 'getShaderParameter': {2: { 1:true }},
'getProgramParameter': { 1:true }, 'getProgramParameter': {2: { 1:true }},
'getShaderPrecisionFormat': {2: { 0: true, 1:true }},
// Vertex attributes // Vertex attributes
'getVertexAttrib': { 1:true }, 'getVertexAttrib': {2: { 1:true }},
'vertexAttribPointer': { 2:true }, 'vertexAttribPointer': {6: { 2:true }},
// Textures // Textures
'bindTexture': { 0:true }, 'bindTexture': {2: { 0:true }},
'activeTexture': { 0:true }, 'activeTexture': {1: { 0:true }},
'getTexParameter': { 0:true, 1:true }, 'getTexParameter': {2: { 0:true, 1:true }},
'texParameterf': { 0:true, 1:true }, 'texParameterf': {3: { 0:true, 1:true }},
'texParameteri': { 0:true, 1:true, 2:true }, 'texParameteri': {3: { 0:true, 1:true, 2:true }},
'texImage2D': { 0:true, 2:true, 6:true, 7:true }, 'texImage2D': {
'texSubImage2D': { 0:true, 6:true, 7:true }, 9: { 0:true, 2:true, 6:true, 7:true },
'copyTexImage2D': { 0:true, 2:true }, 6: { 0:true, 2:true, 3:true, 4:true }
'copyTexSubImage2D': { 0:true }, },
'generateMipmap': { 0:true }, 'texSubImage2D': {
9: { 0:true, 6:true, 7:true },
7: { 0:true, 4:true, 5:true }
},
'copyTexImage2D': {8: { 0:true, 2:true }},
'copyTexSubImage2D': {8: { 0:true }},
'generateMipmap': {1: { 0:true }},
'compressedTexImage2D': {7: { 0: true, 2:true }},
'compressedTexSubImage2D': {8: { 0: true, 6:true }},
// Buffer objects // Buffer objects
'bindBuffer': { 0:true }, 'bindBuffer': {2: { 0:true }},
'bufferData': { 0:true, 2:true }, 'bufferData': {3: { 0:true, 2:true }},
'bufferSubData': { 0:true }, 'bufferSubData': {3: { 0:true }},
'getBufferParameter': { 0:true, 1:true }, 'getBufferParameter': {2: { 0:true, 1:true }},
// Renderbuffers and framebuffers // Renderbuffers and framebuffers
'pixelStorei': { 0:true, 1:true }, 'pixelStorei': {2: { 0:true, 1:true }},
'readPixels': { 4:true, 5:true }, 'readPixels': {7: { 4:true, 5:true }},
'bindRenderbuffer': { 0:true }, 'bindRenderbuffer': {2: { 0:true }},
'bindFramebuffer': { 0:true }, 'bindFramebuffer': {2: { 0:true }},
'checkFramebufferStatus': { 0:true }, 'checkFramebufferStatus': {1: { 0:true }},
'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, 'framebufferRenderbuffer': {4: { 0:true, 1:true, 2:true }},
'framebufferTexture2D': { 0:true, 1:true, 2:true }, 'framebufferTexture2D': {5: { 0:true, 1:true, 2:true }},
'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, 'getFramebufferAttachmentParameter': {3: { 0:true, 1:true, 2:true }},
'getRenderbufferParameter': { 0:true, 1:true }, 'getRenderbufferParameter': {2: { 0:true, 1:true }},
'renderbufferStorage': { 0:true, 1:true }, 'renderbufferStorage': {4: { 0:true, 1:true }},
// Frame buffer operations (clear, blend, depth test, stencil) // Frame buffer operations (clear, blend, depth test, stencil)
'clear': { 0:true }, 'clear': {1: { 0: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }}},
'depthFunc': { 0:true }, 'depthFunc': {1: { 0:true }},
'blendFunc': { 0:true, 1:true }, 'blendFunc': {2: { 0:true, 1:true }},
'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, 'blendFuncSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
'blendEquation': { 0:true }, 'blendEquation': {1: { 0:true }},
'blendEquationSeparate': { 0:true, 1:true }, 'blendEquationSeparate': {2: { 0:true, 1:true }},
'stencilFunc': { 0:true }, 'stencilFunc': {3: { 0:true }},
'stencilFuncSeparate': { 0:true, 1:true }, 'stencilFuncSeparate': {4: { 0:true, 1:true }},
'stencilMaskSeparate': { 0:true }, 'stencilMaskSeparate': {2: { 0:true }},
'stencilOp': { 0:true, 1:true, 2:true }, 'stencilOp': {3: { 0:true, 1:true, 2:true }},
'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, 'stencilOpSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
// Culling // Culling
'cullFace': { 0:true }, 'cullFace': {1: { 0:true }},
'frontFace': { 0:true }, 'frontFace': {1: { 0:true }},
// ANGLE_instanced_arrays extension
'drawArraysInstancedANGLE': {4: { 0:true }},
'drawElementsInstancedANGLE': {5: { 0:true, 2:true }},
// EXT_blend_minmax extension
'blendEquationEXT': {1: { 0:true }}
}; };
/** /**
@@ -103,6 +161,12 @@ var glValidEnumContexts = {
*/ */
var glEnums = null; var glEnums = null;
/**
* Map of names to numbers.
* @type {Object}
*/
var enumStringToValue = null;
/** /**
* Initializes this module. Safe to call more than once. * Initializes this module. Safe to call more than once.
* @param {!WebGLRenderingContext} ctx A WebGL context. If * @param {!WebGLRenderingContext} ctx A WebGL context. If
@@ -112,9 +176,11 @@ var glEnums = null;
function init(ctx) { function init(ctx) {
if (glEnums == null) { if (glEnums == null) {
glEnums = { }; glEnums = { };
enumStringToValue = { };
for (var propertyName in ctx) { for (var propertyName in ctx) {
if (typeof ctx[propertyName] == 'number') { if (typeof ctx[propertyName] == 'number') {
glEnums[ctx[propertyName]] = propertyName; glEnums[ctx[propertyName]] = propertyName;
enumStringToValue[propertyName] = ctx[propertyName];
} }
} }
} }
@@ -151,23 +217,46 @@ function mightBeEnum(value) {
function glEnumToString(value) { function glEnumToString(value) {
checkInit(); checkInit();
var name = glEnums[value]; var name = glEnums[value];
return (name !== undefined) ? name : return (name !== undefined) ? ("gl." + name) :
("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")"); ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + "");
} }
/** /**
* Returns the string version of a WebGL argument. * Returns the string version of a WebGL argument.
* Attempts to convert enum arguments to strings. * Attempts to convert enum arguments to strings.
* @param {string} functionName the name of the WebGL function. * @param {string} functionName the name of the WebGL function.
* @param {number} numArgs the number of arguments passed to the function.
* @param {number} argumentIndx the index of the argument. * @param {number} argumentIndx the index of the argument.
* @param {*} value The value of the argument. * @param {*} value The value of the argument.
* @return {string} The value as a string. * @return {string} The value as a string.
*/ */
function glFunctionArgToString(functionName, argumentIndex, value) { function glFunctionArgToString(functionName, numArgs, argumentIndex, value) {
var funcInfo = glValidEnumContexts[functionName]; var funcInfo = glValidEnumContexts[functionName];
if (funcInfo !== undefined) { if (funcInfo !== undefined) {
if (funcInfo[argumentIndex]) { var funcInfo = funcInfo[numArgs];
return glEnumToString(value); if (funcInfo !== undefined) {
if (funcInfo[argumentIndex]) {
if (typeof funcInfo[argumentIndex] === 'object' &&
funcInfo[argumentIndex]['enumBitwiseOr'] !== undefined) {
var enums = funcInfo[argumentIndex]['enumBitwiseOr'];
var orResult = 0;
var orEnums = [];
for (var i = 0; i < enums.length; ++i) {
var enumValue = enumStringToValue[enums[i]];
if ((value & enumValue) !== 0) {
orResult |= enumValue;
orEnums.push(glEnumToString(enumValue));
}
}
if (orResult === value) {
return orEnums.join(' | ');
} else {
return glEnumToString(value);
}
} else {
return glEnumToString(value);
}
}
} }
} }
if (value === null) { if (value === null) {
@@ -179,6 +268,26 @@ function glFunctionArgToString(functionName, argumentIndex, value) {
} }
} }
/**
* Converts the arguments of a WebGL function to a string.
* Attempts to convert enum arguments to strings.
*
* @param {string} functionName the name of the WebGL function.
* @param {number} args The arguments.
* @return {string} The arguments as a string.
*/
function glFunctionArgsToString(functionName, args) {
// apparently we can't do args.join(",");
var argStr = "";
var numArgs = args.length;
for (var ii = 0; ii < numArgs; ++ii) {
argStr += ((ii == 0) ? '' : ', ') +
glFunctionArgToString(functionName, numArgs, ii, args[ii]);
}
return argStr;
};
function makePropertyWrapper(wrapper, original, propertyName) { function makePropertyWrapper(wrapper, original, propertyName) {
//log("wrap prop: " + propertyName); //log("wrap prop: " + propertyName);
wrapper.__defineGetter__(propertyName, function() { wrapper.__defineGetter__(propertyName, function() {
@@ -214,18 +323,25 @@ function makeFunctionWrapper(original, functionName) {
* The function to call when gl.getError returns an * The function to call when gl.getError returns an
* error. If not specified the default function calls * error. If not specified the default function calls
* console.log with a message. * console.log with a message.
* @param {!function(funcName, args): void} opt_onFunc The
* function to call when each webgl function is called.
* You can use this to log all calls for example.
* @param {!WebGLRenderingContext} opt_err_ctx The webgl context
* to call getError on if different than ctx.
*/ */
function makeDebugContext(ctx, opt_onErrorFunc) { function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc, opt_err_ctx) {
opt_err_ctx = opt_err_ctx || ctx;
init(ctx); init(ctx);
opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
// apparently we can't do args.join(","); // apparently we can't do args.join(",");
var argStr = ""; var argStr = "";
for (var ii = 0; ii < args.length; ++ii) { var numArgs = args.length;
for (var ii = 0; ii < numArgs; ++ii) {
argStr += ((ii == 0) ? '' : ', ') + argStr += ((ii == 0) ? '' : ', ') +
glFunctionArgToString(functionName, ii, args[ii]); glFunctionArgToString(functionName, numArgs, ii, args[ii]);
} }
log("WebGL error "+ glEnumToString(err) + " in "+ functionName + error("WebGL error "+ glEnumToString(err) + " in "+ functionName +
"(" + argStr + ")"); "(" + argStr + ")");
}; };
// Holds booleans for each GL error so after we get the error ourselves // Holds booleans for each GL error so after we get the error ourselves
@@ -235,8 +351,11 @@ function makeDebugContext(ctx, opt_onErrorFunc) {
// Makes a function that calls a WebGL function and then calls getError. // Makes a function that calls a WebGL function and then calls getError.
function makeErrorWrapper(ctx, functionName) { function makeErrorWrapper(ctx, functionName) {
return function() { return function() {
if (opt_onFunc) {
opt_onFunc(functionName, arguments);
}
var result = ctx[functionName].apply(ctx, arguments); var result = ctx[functionName].apply(ctx, arguments);
var err = ctx.getError(); var err = opt_err_ctx.getError();
if (err != 0) { if (err != 0) {
glErrorShadow[err] = true; glErrorShadow[err] = true;
opt_onErrorFunc(err, functionName, arguments); opt_onErrorFunc(err, functionName, arguments);
@@ -250,18 +369,28 @@ function makeDebugContext(ctx, opt_onErrorFunc) {
var wrapper = {}; var wrapper = {};
for (var propertyName in ctx) { for (var propertyName in ctx) {
if (typeof ctx[propertyName] == 'function') { if (typeof ctx[propertyName] == 'function') {
wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); if (propertyName != 'getExtension') {
} else { wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
makePropertyWrapper(wrapper, ctx, propertyName); } else {
} var wrapped = makeErrorWrapper(ctx, propertyName);
wrapper[propertyName] = function () {
var result = wrapped.apply(ctx, arguments);
return makeDebugContext(result, opt_onErrorFunc, opt_onFunc, opt_err_ctx);
};
}
} else {
makePropertyWrapper(wrapper, ctx, propertyName);
}
} }
// Override the getError function with one that returns our saved results. // Override the getError function with one that returns our saved results.
wrapper.getError = function() { wrapper.getError = function() {
for (var err in glErrorShadow) { for (var err in glErrorShadow) {
if (glErrorShadow[err]) { if (glErrorShadow.hasOwnProperty(err)) {
glErrorShadow[err] = false; if (glErrorShadow[err]) {
return err; glErrorShadow[err] = false;
return err;
}
} }
} }
return ctx.NO_ERROR; return ctx.NO_ERROR;
@@ -699,10 +828,9 @@ function makeLostContextSimulatingCanvas(canvas) {
} }
return { return {
/** /**
* Initializes this module. Safe to call more than once. * Initializes this module. Safe to call more than once.
* @param {!WebGLRenderingContext} ctx A WebGL context. If * @param {!WebGLRenderingContext} ctx A WebGL context. If
}
* you have more than one context it doesn't matter which one * you have more than one context it doesn't matter which one
* you pass in, it is only used to pull out constants. * you pass in, it is only used to pull out constants.
*/ */
@@ -733,17 +861,28 @@ return {
* *
* Example: * Example:
* WebGLDebugUtil.init(ctx); * WebGLDebugUtil.init(ctx);
* var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D); * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 2, 0, gl.TEXTURE_2D);
* *
* would return 'TEXTURE_2D' * would return 'TEXTURE_2D'
* *
* @param {string} functionName the name of the WebGL function. * @param {string} functionName the name of the WebGL function.
* @param {number} numArgs The number of arguments
* @param {number} argumentIndx the index of the argument. * @param {number} argumentIndx the index of the argument.
* @param {*} value The value of the argument. * @param {*} value The value of the argument.
* @return {string} The value as a string. * @return {string} The value as a string.
*/ */
'glFunctionArgToString': glFunctionArgToString, 'glFunctionArgToString': glFunctionArgToString,
/**
* Converts the arguments of a WebGL function to a string.
* Attempts to convert enum arguments to strings.
*
* @param {string} functionName the name of the WebGL function.
* @param {number} args The arguments.
* @return {string} The arguments as a string.
*/
'glFunctionArgsToString': glFunctionArgsToString,
/** /**
* Given a WebGL context returns a wrapped context that calls * Given a WebGL context returns a wrapped context that calls
* gl.getError after every command and calls a function if the * gl.getError after every command and calls a function if the
@@ -753,17 +892,20 @@ return {
* an exception thrown on any GL error you could do this * an exception thrown on any GL error you could do this
* *
* function throwOnGLError(err, funcName, args) { * function throwOnGLError(err, funcName, args) {
* throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" + * throw WebGLDebugUtils.glEnumToString(err) +
* funcName; * " was caused by call to " + funcName;
* }; * };
* *
* ctx = WebGLDebugUtils.makeDebugContext( * ctx = WebGLDebugUtils.makeDebugContext(
* canvas.getContext ("webgl"), throwOnGLError); * canvas.getContext("webgl"), throwOnGLError);
* *
* @param {!WebGLRenderingContext} ctx The webgl context to wrap. * @param {!WebGLRenderingContext} ctx The webgl context to wrap.
* @param {!function(err, funcName, args): void} opt_onErrorFunc The function * @param {!function(err, funcName, args): void} opt_onErrorFunc The function
* to call when gl.getError returns an error. If not specified the default * to call when gl.getError returns an error. If not specified the default
* function calls console.log with a message. * function calls console.log with a message.
* @param {!function(funcName, args): void} opt_onFunc The
* function to call when each webgl function is called. You
* can use this to log all calls for example.
*/ */
'makeDebugContext': makeDebugContext, 'makeDebugContext': makeDebugContext,