You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
695 lines
19 KiB
JavaScript
695 lines
19 KiB
JavaScript
/*
|
|
* Copyright 2012, Gregg Tavares.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Gregg Tavares. nor the names of his
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* global define, globalThis */
|
|
|
|
(function(root, factory) { // eslint-disable-line
|
|
if ( typeof define === 'function' && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [], function () {
|
|
|
|
return factory.call( root );
|
|
|
|
} );
|
|
|
|
} else {
|
|
|
|
// Browser globals
|
|
root.webglDebugHelper = factory.call( root );
|
|
|
|
}
|
|
|
|
}( this || globalThis, function () {
|
|
|
|
'use strict'; // eslint-disable-line
|
|
|
|
//------------ [ from https://github.com/KhronosGroup/WebGLDeveloperTools ]
|
|
|
|
/*
|
|
** 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.
|
|
*/
|
|
|
|
/**
|
|
* Types of contexts we have added to map
|
|
*/
|
|
const mappedContextTypes = {};
|
|
|
|
/**
|
|
* Map of numbers to names.
|
|
* @type {Object}
|
|
*/
|
|
const glEnums = {};
|
|
|
|
/**
|
|
* Map of names to numbers.
|
|
* @type {Object}
|
|
*/
|
|
const enumStringToValue = {};
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
function addEnumsForContext( ctx, type ) {
|
|
|
|
if ( ! mappedContextTypes[ type ] ) {
|
|
|
|
mappedContextTypes[ type ] = true;
|
|
for ( const propertyName in ctx ) {
|
|
|
|
if ( typeof ctx[ propertyName ] === 'number' ) {
|
|
|
|
glEnums[ ctx[ propertyName ] ] = propertyName;
|
|
enumStringToValue[ propertyName ] = ctx[ propertyName ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function enumArrayToString( enums ) {
|
|
|
|
const enumStrings = [];
|
|
if ( enums.length ) {
|
|
|
|
for ( let i = 0; i < enums.length; ++ i ) {
|
|
|
|
enums.push(glEnumToString(enums[i])); // eslint-disable-line
|
|
}
|
|
|
|
return '[' + enumStrings.join( ', ' ) + ']';
|
|
|
|
}
|
|
|
|
return enumStrings.toString();
|
|
|
|
}
|
|
|
|
function makeBitFieldToStringFunc( enums ) {
|
|
|
|
return function ( value ) {
|
|
|
|
let orResult = 0;
|
|
const orEnums = [];
|
|
for ( let i = 0; i < enums.length; ++ i ) {
|
|
|
|
const enumValue = enumStringToValue[ enums[ i ] ];
|
|
if ( ( value & enumValue ) !== 0 ) {
|
|
|
|
orResult |= enumValue;
|
|
orEnums.push(glEnumToString(enumValue)); // eslint-disable-line
|
|
}
|
|
|
|
}
|
|
|
|
if ( orResult === value ) {
|
|
|
|
return orEnums.join( ' | ' );
|
|
|
|
} else {
|
|
|
|
return glEnumToString(value); // eslint-disable-line
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
const destBufferBitFieldToString = makeBitFieldToStringFunc( [
|
|
'COLOR_BUFFER_BIT',
|
|
'DEPTH_BUFFER_BIT',
|
|
'STENCIL_BUFFER_BIT',
|
|
] );
|
|
|
|
/**
|
|
* 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. Maybe a function as well in which case
|
|
* value is passed to function and returns a string
|
|
*
|
|
* @type {!Object.<number, (!Object.<number, string>|function)}
|
|
*/
|
|
const glValidEnumContexts = {
|
|
// Generic setters and getters
|
|
|
|
'enable': { 1: { 0: true } },
|
|
'disable': { 1: { 0: true } },
|
|
'getParameter': { 1: { 0: true } },
|
|
|
|
// Rendering
|
|
|
|
'drawArrays': { 3: { 0: true } },
|
|
'drawElements': { 4: { 0: true, 2: true } },
|
|
'drawArraysInstanced': { 4: { 0: true } },
|
|
'drawElementsInstanced': { 5: { 0: true, 2: true } },
|
|
'drawRangeElements': { 6: { 0: true, 4: true } },
|
|
|
|
// Shaders
|
|
|
|
'createShader': { 1: { 0: true } },
|
|
'getShaderParameter': { 2: { 1: true } },
|
|
'getProgramParameter': { 2: { 1: true } },
|
|
'getShaderPrecisionFormat': { 2: { 0: true, 1: true } },
|
|
|
|
// Vertex attributes
|
|
|
|
'getVertexAttrib': { 2: { 1: true } },
|
|
'vertexAttribPointer': { 6: { 2: true } },
|
|
'vertexAttribIPointer': { 5: { 2: true } }, // WebGL2
|
|
|
|
// Textures
|
|
|
|
'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 },
|
|
10: { 0: true, 2: true, 6: true, 7: true }, // WebGL2
|
|
},
|
|
'texImage3D': {
|
|
10: { 0: true, 2: true, 7: true, 8: true }, // WebGL2
|
|
11: { 0: true, 2: true, 7: true, 8: true }, // WebGL2
|
|
},
|
|
'texSubImage2D': {
|
|
9: { 0: true, 6: true, 7: true },
|
|
7: { 0: true, 4: true, 5: true },
|
|
10: { 0: true, 6: true, 7: true }, // WebGL2
|
|
},
|
|
'texSubImage3D': {
|
|
11: { 0: true, 8: true, 9: true }, // WebGL2
|
|
12: { 0: true, 8: true, 9: true }, // WebGL2
|
|
},
|
|
'texStorage2D': { 5: { 0: true, 2: true } }, // WebGL2
|
|
'texStorage3D': { 6: { 0: true, 2: true } }, // WebGL2
|
|
'copyTexImage2D': { 8: { 0: true, 2: true } },
|
|
'copyTexSubImage2D': { 8: { 0: true } },
|
|
'copyTexSubImage3D': { 9: { 0: true } }, // WebGL2
|
|
'generateMipmap': { 1: { 0: true } },
|
|
'compressedTexImage2D': {
|
|
7: { 0: true, 2: true },
|
|
8: { 0: true, 2: true }, // WebGL2
|
|
},
|
|
'compressedTexSubImage2D': {
|
|
8: { 0: true, 6: true },
|
|
9: { 0: true, 6: true }, // WebGL2
|
|
},
|
|
'compressedTexImage3D': {
|
|
8: { 0: true, 2: true, }, // WebGL2
|
|
9: { 0: true, 2: true, }, // WebGL2
|
|
},
|
|
'compressedTexSubImage3D': {
|
|
9: { 0: true, 8: true, }, // WebGL2
|
|
10: { 0: true, 8: true, }, // WebGL2
|
|
},
|
|
|
|
// Buffer objects
|
|
|
|
'bindBuffer': { 2: { 0: true } },
|
|
'bufferData': {
|
|
3: { 0: true, 2: true },
|
|
4: { 0: true, 2: true }, // WebGL2
|
|
5: { 0: true, 2: true }, // WebGL2
|
|
},
|
|
'bufferSubData': {
|
|
3: { 0: true },
|
|
4: { 0: true }, // WebGL2
|
|
5: { 0: true }, // WebGL2
|
|
},
|
|
'copyBufferSubData': {
|
|
5: { 0: true }, // WeBGL2
|
|
},
|
|
'getBufferParameter': { 2: { 0: true, 1: true } },
|
|
'getBufferSubData': {
|
|
3: { 0: true, }, // WebGL2
|
|
4: { 0: true, }, // WebGL2
|
|
5: { 0: true, }, // WebGL2
|
|
},
|
|
|
|
// Renderbuffers and framebuffers
|
|
|
|
'pixelStorei': { 2: { 0: true, 1: true } },
|
|
'readPixels': {
|
|
7: { 4: true, 5: true },
|
|
8: { 4: true, 5: true }, // WebGL2
|
|
},
|
|
'bindRenderbuffer': { 2: { 0: true } },
|
|
'bindFramebuffer': { 2: { 0: true } },
|
|
'blitFramebuffer': { 10: { 8: destBufferBitFieldToString, 9: true } }, // WebGL2
|
|
'checkFramebufferStatus': { 1: { 0: true } },
|
|
'framebufferRenderbuffer': { 4: { 0: true, 1: true, 2: true } },
|
|
'framebufferTexture2D': { 5: { 0: true, 1: true, 2: true } },
|
|
'framebufferTextureLayer': { 5: { 0: true, 1: true } }, // WebGL2
|
|
'getFramebufferAttachmentParameter': { 3: { 0: true, 1: true, 2: true } },
|
|
'getInternalformatParameter': { 3: { 0: true, 1: true, 2: true } }, // WebGL2
|
|
'getRenderbufferParameter': { 2: { 0: true, 1: true } },
|
|
'invalidateFramebuffer': { 2: { 0: true, 1: enumArrayToString, } }, // WebGL2
|
|
'invalidateSubFramebuffer': { 6: { 0: true, 1: enumArrayToString, } }, // WebGL2
|
|
'readBuffer': { 1: { 0: true } }, // WebGL2
|
|
'renderbufferStorage': { 4: { 0: true, 1: true } },
|
|
'renderbufferStorageMultisample': { 5: { 0: true, 2: true } }, // WebGL2
|
|
|
|
// Frame buffer operations (clear, blend, depth test, stencil)
|
|
|
|
'clear': { 1: { 0: destBufferBitFieldToString } },
|
|
'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': { 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 } },
|
|
|
|
// Multiple Render Targets
|
|
|
|
'drawBuffersWebGL': { 1: { 0: enumArrayToString, } }, // WEBGL_draw_bufers
|
|
'drawBuffers': { 1: { 0: enumArrayToString, } }, // WebGL2
|
|
'clearBufferfv': {
|
|
4: { 0: true }, // WebGL2
|
|
5: { 0: true }, // WebGL2
|
|
},
|
|
'clearBufferiv': {
|
|
4: { 0: true }, // WebGL2
|
|
5: { 0: true }, // WebGL2
|
|
},
|
|
'clearBufferuiv': {
|
|
4: { 0: true }, // WebGL2
|
|
5: { 0: true }, // WebGL2
|
|
},
|
|
'clearBufferfi': { 4: { 0: true } }, // WebGL2
|
|
|
|
// QueryObjects
|
|
|
|
'beginQuery': { 2: { 0: true } }, // WebGL2
|
|
'endQuery': { 1: { 0: true } }, // WebGL2
|
|
'getQuery': { 2: { 0: true, 1: true } }, // WebGL2
|
|
'getQueryParameter': { 2: { 1: true } }, // WebGL2
|
|
|
|
// Sampler Objects
|
|
|
|
'samplerParameteri': { 3: { 1: true } }, // WebGL2
|
|
'samplerParameterf': { 3: { 1: true } }, // WebGL2
|
|
'getSamplerParameter': { 2: { 1: true } }, // WebGL2
|
|
|
|
// Sync objects
|
|
|
|
'clientWaitSync': { 3: { 1: makeBitFieldToStringFunc( [ 'SYNC_FLUSH_COMMANDS_BIT' ] ) } }, // WebGL2
|
|
'fenceSync': { 2: { 0: true } }, // WebGL2
|
|
'getSyncParameter': { 2: { 1: true } }, // WebGL2
|
|
|
|
// Transform Feedback
|
|
|
|
'bindTransformFeedback': { 2: { 0: true } }, // WebGL2
|
|
'beginTransformFeedback': { 1: { 0: true } }, // WebGL2
|
|
|
|
// Uniform Buffer Objects and Transform Feedback Buffers
|
|
'bindBufferBase': { 3: { 0: true } }, // WebGL2
|
|
'bindBufferRange': { 5: { 0: true } }, // WebGL2
|
|
'getIndexedParameter': { 2: { 0: true } }, // WebGL2
|
|
'getActiveUniforms': { 3: { 2: true } }, // WebGL2
|
|
'getActiveUniformBlockParameter': { 3: { 2: true } }, // WebGL2
|
|
};
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
function glEnumToString( value ) {
|
|
|
|
const name = glEnums[ value ];
|
|
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, numArgs, argumentIndex, value ) {
|
|
|
|
const funcInfos = glValidEnumContexts[ functionName ];
|
|
if ( funcInfos !== undefined ) {
|
|
|
|
const funcInfo = funcInfos[ numArgs ];
|
|
if ( funcInfo !== undefined ) {
|
|
|
|
const argType = funcInfo[ argumentIndex ];
|
|
if ( argType ) {
|
|
|
|
if ( typeof argType === 'function' ) {
|
|
|
|
return argType( value );
|
|
|
|
} else {
|
|
|
|
return glEnumToString( value );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( value === null ) {
|
|
|
|
return 'null';
|
|
|
|
} else if ( value === undefined ) {
|
|
|
|
return 'undefined';
|
|
|
|
} else {
|
|
|
|
return value.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 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(",");
|
|
const argStrs = [];
|
|
const numArgs = args.length;
|
|
for ( let ii = 0; ii < numArgs; ++ ii ) {
|
|
|
|
argStrs.push( glFunctionArgToString( functionName, numArgs, ii, args[ ii ] ) );
|
|
|
|
}
|
|
|
|
return argStrs.join( ', ' );
|
|
|
|
}
|
|
|
|
function makePropertyWrapper( wrapper, original, propertyName ) {
|
|
|
|
wrapper.__defineGetter__(propertyName, function() { // eslint-disable-line
|
|
return original[ propertyName ];
|
|
|
|
} );
|
|
// TODO(gmane): this needs to handle properties that take more than
|
|
// one value?
|
|
wrapper.__defineSetter__(propertyName, function(value) { // eslint-disable-line
|
|
original[ propertyName ] = value;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* @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, options ) {
|
|
|
|
options = options || {};
|
|
const errCtx = options.errCtx || ctx;
|
|
const onFunc = options.funcFunc;
|
|
const sharedState = options.sharedState || {
|
|
numDrawCallsRemaining: options.maxDrawCalls || - 1,
|
|
wrappers: {},
|
|
};
|
|
options.sharedState = sharedState;
|
|
|
|
const errorFunc = options.errorFunc || function ( err, functionName, args ) {
|
|
|
|
console.error( `WebGL error ${glEnumToString( err )} in ${functionName}(${glFunctionArgsToString( functionName, args )})` ); /* eslint-disable-line no-console */
|
|
|
|
};
|
|
|
|
// Holds booleans for each GL error so after we get the error ourselves
|
|
// we can still return it to the client app.
|
|
const glErrorShadow = { };
|
|
const wrapper = {};
|
|
|
|
function removeChecks() {
|
|
|
|
Object.keys( sharedState.wrappers ).forEach( function ( name ) {
|
|
|
|
const pair = sharedState.wrappers[ name ];
|
|
const wrapper = pair.wrapper;
|
|
const orig = pair.orig;
|
|
for ( const propertyName in wrapper ) {
|
|
|
|
if ( typeof wrapper[ propertyName ] === 'function' ) {
|
|
|
|
wrapper[ propertyName ] = orig[ propertyName ].bind( orig );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
function checkMaxDrawCalls() {
|
|
|
|
if ( sharedState.numDrawCallsRemaining === 0 ) {
|
|
|
|
removeChecks();
|
|
|
|
}
|
|
|
|
-- sharedState.numDrawCallsRemaining;
|
|
|
|
}
|
|
|
|
function noop() {
|
|
}
|
|
|
|
// Makes a function that calls a WebGL function and then calls getError.
|
|
function makeErrorWrapper( ctx, functionName ) {
|
|
|
|
const check = functionName.substring( 0, 4 ) === 'draw' ? checkMaxDrawCalls : noop;
|
|
return function () {
|
|
|
|
if ( onFunc ) {
|
|
|
|
onFunc( functionName, arguments );
|
|
|
|
}
|
|
|
|
const result = ctx[ functionName ].apply( ctx, arguments );
|
|
const err = errCtx.getError();
|
|
if ( err !== 0 ) {
|
|
|
|
glErrorShadow[ err ] = true;
|
|
errorFunc( err, functionName, arguments );
|
|
|
|
}
|
|
|
|
check();
|
|
return result;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function makeGetExtensionWrapper( ctx, wrapped ) {
|
|
|
|
return function () {
|
|
|
|
const extensionName = arguments[ 0 ];
|
|
let ext = sharedState.wrappers[ extensionName ];
|
|
if ( ! ext ) {
|
|
|
|
ext = wrapped.apply( ctx, arguments );
|
|
if ( ext ) {
|
|
|
|
const origExt = ext;
|
|
ext = makeDebugContext( ext, { ...options, errCtx: ctx } );
|
|
sharedState.wrappers[ extensionName ] = { wrapper: ext, orig: origExt };
|
|
addEnumsForContext( origExt, extensionName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ext;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// Make an object that has a copy of every property of the WebGL context
|
|
// but wraps all functions.
|
|
for ( const propertyName in ctx ) {
|
|
|
|
if ( typeof ctx[ propertyName ] === 'function' ) {
|
|
|
|
if ( propertyName !== 'getExtension' ) {
|
|
|
|
wrapper[ propertyName ] = makeErrorWrapper( ctx, propertyName );
|
|
|
|
} else {
|
|
|
|
const wrapped = makeErrorWrapper( ctx, propertyName );
|
|
wrapper[ propertyName ] = makeGetExtensionWrapper( ctx, wrapped );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
makePropertyWrapper( wrapper, ctx, propertyName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Override the getError function with one that returns our saved results.
|
|
if ( wrapper.getError ) {
|
|
|
|
wrapper.getError = function () {
|
|
|
|
for ( const err of Object.keys( glErrorShadow ) ) {
|
|
|
|
if ( glErrorShadow[ err ] ) {
|
|
|
|
glErrorShadow[ err ] = false;
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ctx.NO_ERROR;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if ( wrapper.bindBuffer ) {
|
|
|
|
sharedState.wrappers[ 'webgl' ] = { wrapper: wrapper, orig: ctx };
|
|
addEnumsForContext( ctx, ctx.bindBufferBase ? 'WebGL2' : 'WebGL' );
|
|
|
|
}
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
return {
|
|
makeDebugContext,
|
|
glFunctionArgsToString,
|
|
glFunctionArgToString,
|
|
glEnumToString,
|
|
};
|
|
|
|
} ) );
|
|
|