diff --git a/dependencies/webgl-debug.js b/dependencies/webgl-debug.js index 5f2a620b2..a7e445d40 100644 --- a/dependencies/webgl-debug.js +++ b/dependencies/webgl-debug.js @@ -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 -//found in the LICENSE file. +/* +** Copyright (c) 2012 The Khronos Group Inc. +** +** 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. @@ -17,84 +36,123 @@ var log = function(msg) { }; /** - * Which arguements are enums. - * @type {!Object.} + * Wrapped error logging function. + * @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.} */ var glValidEnumContexts = { - // Generic setters and getters - 'enable': { 0:true }, - 'disable': { 0:true }, - 'getParameter': { 0:true }, + 'enable': {1: { 0:true }}, + 'disable': {1: { 0:true }}, + 'getParameter': {1: { 0:true }}, // Rendering - 'drawArrays': { 0:true }, - 'drawElements': { 0:true, 2:true }, + 'drawArrays': {3:{ 0:true }}, + 'drawElements': {4:{ 0:true, 2:true }}, // Shaders - 'createShader': { 0:true }, - 'getShaderParameter': { 1:true }, - 'getProgramParameter': { 1:true }, + 'createShader': {1: { 0:true }}, + 'getShaderParameter': {2: { 1:true }}, + 'getProgramParameter': {2: { 1:true }}, + 'getShaderPrecisionFormat': {2: { 0: true, 1:true }}, // Vertex attributes - 'getVertexAttrib': { 1:true }, - 'vertexAttribPointer': { 2:true }, + 'getVertexAttrib': {2: { 1:true }}, + 'vertexAttribPointer': {6: { 2:true }}, // Textures - 'bindTexture': { 0:true }, - 'activeTexture': { 0:true }, - 'getTexParameter': { 0:true, 1:true }, - 'texParameterf': { 0:true, 1:true }, - 'texParameteri': { 0:true, 1:true, 2:true }, - 'texImage2D': { 0:true, 2:true, 6:true, 7:true }, - 'texSubImage2D': { 0:true, 6:true, 7:true }, - 'copyTexImage2D': { 0:true, 2:true }, - 'copyTexSubImage2D': { 0:true }, - 'generateMipmap': { 0:true }, + 'bindTexture': {2: { 0:true }}, + 'activeTexture': {1: { 0:true }}, + 'getTexParameter': {2: { 0:true, 1:true }}, + 'texParameterf': {3: { 0:true, 1:true }}, + 'texParameteri': {3: { 0:true, 1:true, 2:true }}, + 'texImage2D': { + 9: { 0:true, 2:true, 6:true, 7:true }, + 6: { 0:true, 2:true, 3:true, 4: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 - 'bindBuffer': { 0:true }, - 'bufferData': { 0:true, 2:true }, - 'bufferSubData': { 0:true }, - 'getBufferParameter': { 0:true, 1:true }, + 'bindBuffer': {2: { 0:true }}, + 'bufferData': {3: { 0:true, 2:true }}, + 'bufferSubData': {3: { 0:true }}, + 'getBufferParameter': {2: { 0:true, 1:true }}, // Renderbuffers and framebuffers - 'pixelStorei': { 0:true, 1:true }, - 'readPixels': { 4:true, 5:true }, - 'bindRenderbuffer': { 0:true }, - 'bindFramebuffer': { 0:true }, - 'checkFramebufferStatus': { 0:true }, - 'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, - 'framebufferTexture2D': { 0:true, 1:true, 2:true }, - 'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, - 'getRenderbufferParameter': { 0:true, 1:true }, - 'renderbufferStorage': { 0:true, 1:true }, + 'pixelStorei': {2: { 0:true, 1:true }}, + 'readPixels': {7: { 4:true, 5:true }}, + 'bindRenderbuffer': {2: { 0:true }}, + 'bindFramebuffer': {2: { 0:true }}, + 'checkFramebufferStatus': {1: { 0:true }}, + 'framebufferRenderbuffer': {4: { 0:true, 1:true, 2:true }}, + 'framebufferTexture2D': {5: { 0:true, 1:true, 2:true }}, + 'getFramebufferAttachmentParameter': {3: { 0:true, 1:true, 2:true }}, + 'getRenderbufferParameter': {2: { 0:true, 1:true }}, + 'renderbufferStorage': {4: { 0:true, 1:true }}, // Frame buffer operations (clear, blend, depth test, stencil) - 'clear': { 0:true }, - 'depthFunc': { 0:true }, - 'blendFunc': { 0:true, 1:true }, - 'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, - 'blendEquation': { 0:true }, - 'blendEquationSeparate': { 0:true, 1:true }, - 'stencilFunc': { 0:true }, - 'stencilFuncSeparate': { 0:true, 1:true }, - 'stencilMaskSeparate': { 0:true }, - 'stencilOp': { 0:true, 1:true, 2:true }, - 'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, + 'clear': {1: { 0: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }}}, + 'depthFunc': {1: { 0:true }}, + 'blendFunc': {2: { 0:true, 1:true }}, + 'blendFuncSeparate': {4: { 0:true, 1:true, 2:true, 3:true }}, + 'blendEquation': {1: { 0:true }}, + 'blendEquationSeparate': {2: { 0:true, 1:true }}, + 'stencilFunc': {3: { 0:true }}, + 'stencilFuncSeparate': {4: { 0:true, 1:true }}, + 'stencilMaskSeparate': {2: { 0:true }}, + 'stencilOp': {3: { 0:true, 1:true, 2:true }}, + 'stencilOpSeparate': {4: { 0:true, 1:true, 2:true, 3:true }}, // Culling - 'cullFace': { 0:true }, - 'frontFace': { 0:true }, + 'cullFace': {1: { 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; +/** + * Map of names to numbers. + * @type {Object} + */ +var enumStringToValue = null; + /** * Initializes this module. Safe to call more than once. * @param {!WebGLRenderingContext} ctx A WebGL context. If @@ -112,9 +176,11 @@ var glEnums = null; function init(ctx) { if (glEnums == null) { glEnums = { }; + enumStringToValue = { }; for (var propertyName in ctx) { if (typeof ctx[propertyName] == 'number') { glEnums[ctx[propertyName]] = propertyName; + enumStringToValue[propertyName] = ctx[propertyName]; } } } @@ -151,23 +217,46 @@ function mightBeEnum(value) { function glEnumToString(value) { checkInit(); var name = glEnums[value]; - return (name !== undefined) ? name : - ("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")"); + return (name !== undefined) ? ("gl." + name) : + ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + ""); } /** * Returns the string version of a WebGL argument. * Attempts to convert enum arguments to strings. * @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 {*} value The value of the argument. * @return {string} The value as a string. */ -function glFunctionArgToString(functionName, argumentIndex, value) { +function glFunctionArgToString(functionName, numArgs, argumentIndex, value) { var funcInfo = glValidEnumContexts[functionName]; if (funcInfo !== undefined) { - if (funcInfo[argumentIndex]) { - return glEnumToString(value); + var funcInfo = funcInfo[numArgs]; + 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) { @@ -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) { //log("wrap prop: " + propertyName); wrapper.__defineGetter__(propertyName, function() { @@ -214,18 +323,25 @@ function makeFunctionWrapper(original, functionName) { * The function to call when gl.getError returns an * error. If not specified the default 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. + * @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); opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { // apparently we can't do args.join(","); var argStr = ""; - for (var ii = 0; ii < args.length; ++ii) { + var numArgs = args.length; + for (var ii = 0; ii < numArgs; ++ii) { argStr += ((ii == 0) ? '' : ', ') + - glFunctionArgToString(functionName, ii, args[ii]); + glFunctionArgToString(functionName, numArgs, ii, args[ii]); } - log("WebGL error "+ glEnumToString(err) + " in "+ functionName + - "(" + argStr + ")"); + error("WebGL error "+ glEnumToString(err) + " in "+ functionName + + "(" + argStr + ")"); }; // 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. function makeErrorWrapper(ctx, functionName) { return function() { + if (opt_onFunc) { + opt_onFunc(functionName, arguments); + } var result = ctx[functionName].apply(ctx, arguments); - var err = ctx.getError(); + var err = opt_err_ctx.getError(); if (err != 0) { glErrorShadow[err] = true; opt_onErrorFunc(err, functionName, arguments); @@ -250,18 +369,28 @@ function makeDebugContext(ctx, opt_onErrorFunc) { var wrapper = {}; for (var propertyName in ctx) { if (typeof ctx[propertyName] == 'function') { - wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); - } else { - makePropertyWrapper(wrapper, ctx, propertyName); - } + if (propertyName != 'getExtension') { + wrapper[propertyName] = makeErrorWrapper(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. wrapper.getError = function() { for (var err in glErrorShadow) { - if (glErrorShadow[err]) { - glErrorShadow[err] = false; - return err; + if (glErrorShadow.hasOwnProperty(err)) { + if (glErrorShadow[err]) { + glErrorShadow[err] = false; + return err; + } } } return ctx.NO_ERROR; @@ -699,10 +828,9 @@ function makeLostContextSimulatingCanvas(canvas) { } return { - /** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebGL context. If - } + /** + * Initializes this module. Safe to call more than once. + * @param {!WebGLRenderingContext} ctx A WebGL context. If * you have more than one context it doesn't matter which one * you pass in, it is only used to pull out constants. */ @@ -733,17 +861,28 @@ return { * * Example: * 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' * * @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 {*} value The value of the argument. * @return {string} The value as a string. */ '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 * 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 * * function throwOnGLError(err, funcName, args) { - * throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" + - * funcName; + * throw WebGLDebugUtils.glEnumToString(err) + + * " was caused by call to " + funcName; * }; * * ctx = WebGLDebugUtils.makeDebugContext( - * canvas.getContext ("webgl"), throwOnGLError); + * canvas.getContext("webgl"), throwOnGLError); * * @param {!WebGLRenderingContext} ctx The webgl context to wrap. * @param {!function(err, funcName, args): void} opt_onErrorFunc The function * to call when gl.getError returns an error. If not specified the default * 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,