Created
July 30, 2010 17:31
-
-
Save bringhurst/500949 to your computer and use it in GitHub Desktop.
A webgl debug wrapper modified for use in google closure apps.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global goog, lanyard */ | |
/*jslint white: false, onevar: false, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, sub: true, nomen: false */ | |
// | |
// WARNING: Part of this file is based on code that is: | |
// | |
// 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 (located in the Khronos Group's VCS repository). | |
// | |
goog.provide('lanyard.util.WebGLDebug'); | |
/** | |
* Various functions for helping to debug WebGL apps. | |
* | |
* @param {!WebGLRenderingContext} ctx The webgl context to wrap. | |
*/ | |
lanyard.util.WebGLDebug = function (ctx) { | |
/** | |
* @private | |
*/ | |
this._logger = goog.debug.Logger.getLogger('lanyard.util.WebGLDebug'); | |
/** | |
* Which arguments are enums. | |
* @type {!Object.<number, string>} | |
*/ | |
var glValidEnumContexts = { | |
// Generic setters and getters | |
'enable': { 0:true }, | |
'disable': { 0:true }, | |
'getParameter': { 0:true }, | |
// Rendering | |
'drawArrays': { 0:true }, | |
'drawElements': { 0:true, 2:true }, | |
// Shaders | |
'createShader': { 0:true }, | |
'getShaderParameter': { 1:true }, | |
'getProgramParameter': { 1:true }, | |
// Vertex attributes | |
'getVertexAttrib': { 1:true }, | |
'vertexAttribPointer': { 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 }, | |
// Buffer objects | |
'bindBuffer': { 0:true }, | |
'bufferData': { 0:true, 2:true }, | |
'bufferSubData': { 0:true }, | |
'getBufferParameter': { 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 }, | |
// 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 }, | |
// Culling | |
'cullFace': { 0:true }, | |
'frontFace': { 0:true }, | |
}; | |
/** | |
* Map of numbers to names. | |
* @type {Object} | |
*/ | |
var glEnums = {}; | |
for (var propertyName in ctx) { | |
if (typeof ctx[propertyName] == 'number') { | |
glEnums[ctx[propertyName]] = propertyName; | |
} | |
} | |
}; | |
/** | |
* Returns true or false if value matches any WebGL enum. | |
* | |
* @param {*} value Value to check if it might be an enum. | |
* @return {boolean} True if value matches one of the WebGL defined enums | |
*/ | |
lanyard.util.WebGLDebug.prototype.mightBeEnum = function (value) { | |
return (this.glEnums[value] !== undefined); | |
}; | |
/** | |
* Gets an string version of an WebGL enum. | |
* | |
* Example: | |
* var str = WebGLDebugUtil.glEnumToString(ctx.getError()); | |
* | |
* @param {number} value Value to return an enum for | |
* @return {string} The string version of the enum. | |
*/ | |
lanyard.util.WebGLDebug.prototype.glEnumToString = function (value) { | |
var name = glEnums[value]; | |
return (name !== undefined) ? 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} argumentIndx the index of the argument. | |
* @param {*} value The value of the argument. | |
* @return {string} The value as a string. | |
*/ | |
lanyard.util.WebGLDebug.prototype.glFunctionArgToString = function (functionName, argumentIndex, value) { | |
var funcInfo = glValidEnumContexts[functionName]; | |
if (funcInfo !== undefined) { | |
if (funcInfo[argumentIndex]) { | |
return glEnumToString(value); | |
} | |
} | |
return value.toString(); | |
}; | |
/** | |
* Given a WebGL context returns a wrapped context that calls | |
* gl.getError after every command and calls a function if the | |
* result is not gl.NO_ERROR. | |
* | |
* @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. | |
*/ | |
lanyard.util.WebGLDebug.prototype.makeDebugContext = function (ctx, opt_onErrorFunc) { | |
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) { | |
argStr += ((ii == 0) ? '' : ', ') + | |
glFunctionArgToString(functionName, ii, args[ii]); | |
} | |
this._logger.severe("WebGL error "+ glEnumToString(err) + " in "+ functionName + | |
"(" + argStr + ")"); | |
}; | |
// Holds booleans for each GL error so after we get the error ourselves | |
// we can still return it to the client app. | |
var glErrorShadow = { }; | |
// Makes a function that calls a WebGL function and then calls getError. | |
function makeErrorWrapper(ctx, functionName) { | |
return function() { | |
var result = ctx[functionName].apply(ctx, arguments); | |
var err = ctx.getError(); | |
if (err != 0) { | |
glErrorShadow[err] = true; | |
opt_onErrorFunc(err, functionName, arguments); | |
} | |
return result; | |
}; | |
} | |
// Make a an object that has a copy of every property of the WebGL context | |
// but wraps all functions. | |
var wrapper = {}; | |
for (var propertyName in ctx) { | |
if (typeof ctx[propertyName] == 'function') { | |
wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); | |
} else { | |
wrapper[propertyName] = 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; | |
} | |
} | |
return ctx.NO_ERROR; | |
}; | |
return wrapper; | |
}; | |
/* EOF */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment