@@ -410,7 +410,78 @@ var LibraryGL = {
410410 }
411411 } ,
412412#endif
413-
413+
414+ #if TRACE_WEBGL_CALLS
415+ webGLFunctionLengths : { 'getContextAttributes' : 0 , 'isContextLost' : 0 , 'getSupportedExtensions' : 0 , 'createBuffer' : 0 , 'createFramebuffer' : 0 , 'createProgram' : 0 , 'createRenderbuffer' : 0 , 'createTexture' : 0 , 'finish' : 0 , 'flush' : 0 , 'getError' : 0 , 'createVertexArray' : 0 , 'createQuery' : 0 , 'createSampler' : 0 , 'createTransformFeedback' : 0 , 'endTransformFeedback' : 0 , 'pauseTransformFeedback' : 0 , 'resumeTransformFeedback' : 0 , 'commit' : 0 ,
416+ 'getExtension' : 1 , 'activeTexture' : 1 , 'blendEquation' : 1 , 'checkFramebufferStatus' : 1 , 'clear' : 1 , 'clearDepth' : 1 , 'clearStencil' : 1 , 'compileShader' : 1 , 'createShader' : 1 , 'cullFace' : 1 , 'deleteBuffer' : 1 , 'deleteFramebuffer' : 1 , 'deleteProgram' : 1 , 'deleteRenderbuffer' : 1 , 'deleteShader' : 1 , 'deleteTexture' : 1 , 'depthFunc' : 1 , 'depthMask' : 1 , 'disable' : 1 , 'disableVertexAttribArray' : 1 , 'enable' : 1 , 'enableVertexAttribArray' : 1 , 'frontFace' : 1 , 'generateMipmap' : 1 , 'getAttachedShaders' : 1 , 'getParameter' : 1 , 'getProgramInfoLog' : 1 , 'getShaderInfoLog' : 1 , 'getShaderSource' : 1 , 'isBuffer' : 1 , 'isEnabled' : 1 , 'isFramebuffer' : 1 , 'isProgram' : 1 , 'isRenderbuffer' : 1 , 'isShader' : 1 , 'isTexture' : 1 , 'lineWidth' : 1 , 'linkProgram' : 1 , 'stencilMask' : 1 , 'useProgram' : 1 , 'validateProgram' : 1 , 'deleteQuery' : 1 , 'isQuery' : 1 , 'deleteVertexArray' : 1 , 'bindVertexArray' : 1 , 'isVertexArray' : 1 , 'drawBuffers' : 1 , 'readBuffer' : 1 , 'endQuery' : 1 , 'deleteSampler' : 1 , 'isSampler' : 1 , 'isSync' : 1 , 'deleteSync' : 1 , 'deleteTransformFeedback' : 1 , 'isTransformFeedback' : 1 , 'beginTransformFeedback' : 1 ,
417+ 'attachShader' : 2 , 'bindBuffer' : 2 , 'bindFramebuffer' : 2 , 'bindRenderbuffer' : 2 , 'bindTexture' : 2 , 'blendEquationSeparate' : 2 , 'blendFunc' : 2 , 'depthRange' : 2 , 'detachShader' : 2 , 'getActiveAttrib' : 2 , 'getActiveUniform' : 2 , 'getAttribLocation' : 2 , 'getBufferParameter' : 2 , 'getProgramParameter' : 2 , 'getRenderbufferParameter' : 2 , 'getShaderParameter' : 2 , 'getShaderPrecisionFormat' : 2 , 'getTexParameter' : 2 , 'getUniform' : 2 , 'getUniformLocation' : 2 , 'getVertexAttrib' : 2 , 'getVertexAttribOffset' : 2 , 'hint' : 2 , 'pixelStorei' : 2 , 'polygonOffset' : 2 , 'sampleCoverage' : 2 , 'shaderSource' : 2 , 'stencilMaskSeparate' : 2 , 'uniform1f' : 2 , 'uniform1fv' : 2 , 'uniform1i' : 2 , 'uniform1iv' : 2 , 'uniform2fv' : 2 , 'uniform2iv' : 2 , 'uniform3fv' : 2 , 'uniform3iv' : 2 , 'uniform4fv' : 2 , 'uniform4iv' : 2 , 'vertexAttrib1f' : 2 , 'vertexAttrib1fv' : 2 , 'vertexAttrib2fv' : 2 , 'vertexAttrib3fv' : 2 , 'vertexAttrib4fv' : 2 , 'vertexAttribDivisor' : 2 , 'beginQuery' : 2 , 'invalidateFramebuffer' : 2 , 'getFragDataLocation' : 2 , 'uniform1ui' : 2 , 'uniform1uiv' : 2 , 'uniform2uiv' : 2 , 'uniform3uiv' : 2 , 'uniform4uiv' : 2 , 'vertexAttribI4iv' : 2 , 'vertexAttribI4uiv' : 2 , 'getQuery' : 2 , 'getQueryParameter' : 2 , 'bindSampler' : 2 , 'getSamplerParameter' : 2 , 'fenceSync' : 2 , 'getSyncParameter' : 2 , 'bindTransformFeedback' : 2 , 'getTransformFeedbackVarying' : 2 , 'getIndexedParameter' : 2 , 'getUniformIndices' : 2 , 'getUniformBlockIndex' : 2 , 'getActiveUniformBlockName' : 2 ,
418+ 'bindAttribLocation' : 3 , 'bufferData' : 3 , 'bufferSubData' : 3 , 'drawArrays' : 3 , 'getFramebufferAttachmentParameter' : 3 , 'stencilFunc' : 3 , 'stencilOp' : 3 , 'texParameterf' : 3 , 'texParameteri' : 3 , 'uniform2f' : 3 , 'uniform2i' : 3 , 'uniformMatrix2fv' : 3 , 'uniformMatrix3fv' : 3 , 'uniformMatrix4fv' : 3 , 'vertexAttrib2f' : 3 , 'getBufferSubData' : 3 , 'getInternalformatParameter' : 3 , 'uniform2ui' : 3 , 'uniformMatrix2x3fv' : 3 , 'uniformMatrix3x2fv' : 3 , 'uniformMatrix2x4fv' : 3 , 'uniformMatrix4x2fv' : 3 , 'uniformMatrix3x4fv' : 3 , 'uniformMatrix4x3fv' : 3 , 'clearBufferiv' : 3 , 'clearBufferuiv' : 3 , 'clearBufferfv' : 3 , 'samplerParameteri' : 3 , 'samplerParameterf' : 3 , 'clientWaitSync' : 3 , 'waitSync' : 3 , 'transformFeedbackVaryings' : 3 , 'bindBufferBase' : 3 , 'getActiveUniforms' : 3 , 'getActiveUniformBlockParameter' : 3 , 'uniformBlockBinding' : 3 ,
419+ 'blendColor' : 4 , 'blendFuncSeparate' : 4 , 'clearColor' : 4 , 'colorMask' : 4 , 'drawElements' : 4 , 'framebufferRenderbuffer' : 4 , 'renderbufferStorage' : 4 , 'scissor' : 4 , 'stencilFuncSeparate' : 4 , 'stencilOpSeparate' : 4 , 'uniform3f' : 4 , 'uniform3i' : 4 , 'vertexAttrib3f' : 4 , 'viewport' : 4 , 'drawArraysInstanced' : 4 , 'uniform3ui' : 4 , 'clearBufferfi' : 4 ,
420+ 'framebufferTexture2D' : 5 , 'uniform4f' : 5 , 'uniform4i' : 5 , 'vertexAttrib4f' : 5 , 'drawElementsInstanced' : 5 , 'copyBufferSubData' : 5 , 'framebufferTextureLayer' : 5 , 'renderbufferStorageMultisample' : 5 , 'texStorage2D' : 5 , 'uniform4ui' : 5 , 'vertexAttribI4i' : 5 , 'vertexAttribI4ui' : 5 , 'vertexAttribIPointer' : 5 , 'bindBufferRange' : 5 ,
421+ 'texImage2D' : 6 , 'vertexAttribPointer' : 6 , 'invalidateSubFramebuffer' : 6 , 'texStorage3D' : 6 , 'drawRangeElements' : 6 ,
422+ 'compressedTexImage2D' : 7 , 'readPixels' : 7 , 'texSubImage2D' : 7 ,
423+ 'compressedTexSubImage2D' : 8 , 'copyTexImage2D' : 8 , 'copyTexSubImage2D' : 8 , 'compressedTexImage3D' : 8 ,
424+ 'copyTexSubImage3D' : 9 ,
425+ 'blitFramebuffer' : 10 , 'texImage3D' : 10 , 'compressedTexSubImage3D' : 10 ,
426+ 'texSubImage3D' : 11 } ,
427+
428+ hookWebGLFunction : function ( f , glCtx ) {
429+ var realf = 'real_ ' + f ;
430+ glCtx [ realf ] = glCtx [ f ] ;
431+ var numArgs = GL . webGLFunctionLengths [ f ] ; // On Firefox & Chrome, could do "glCtx[realf].length", but that doesn't work on Edge, which always reports 0.
432+ if ( numArgs === undefined ) throw 'Unexpected WebGL function ' + f ;
433+ var contextHandle = glCtx . canvas . GLctxObject . handle ;
434+ var threadId = ( typeof _pthread_self !== 'undefined' ) ? _pthread_self : function ( ) { return 1 ; } ;
435+ // Accessing 'arguments' is super slow, so to avoid overhead, statically reason the number of arguments.
436+ switch ( numArgs ) {
437+ case 0 : glCtx [ f ] = function webgl_0 ( ) { var ret = glCtx [ realf ] ( ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '() -> ' + ret ) ; return ret ; } ; break ;
438+ case 1 : glCtx [ f ] = function webgl_1 ( a1 ) { var ret = glCtx [ realf ] ( a1 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ') -> ' + ret ) ; return ret ; } ; break ;
439+ case 2 : glCtx [ f ] = function webgl_2 ( a1 , a2 ) { var ret = glCtx [ realf ] ( a1 , a2 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ') -> ' + ret ) ; return ret ; } ; break ;
440+ case 3 : glCtx [ f ] = function webgl_3 ( a1 , a2 , a3 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ') -> ' + ret ) ; return ret ; } ; break ;
441+ case 4 : glCtx [ f ] = function webgl_4 ( a1 , a2 , a3 , a4 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ') -> ' + ret ) ; return ret ; } ; break ;
442+ case 5 : glCtx [ f ] = function webgl_5 ( a1 , a2 , a3 , a4 , a5 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ') -> ' + ret ) ; return ret ; } ; break ;
443+ case 6 : glCtx [ f ] = function webgl_6 ( a1 , a2 , a3 , a4 , a5 , a6 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ') -> ' + ret ) ; return ret ; } ; break ;
444+ case 7 : glCtx [ f ] = function webgl_7 ( a1 , a2 , a3 , a4 , a5 , a6 , a7 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ', ' + a7 + ') -> ' + ret ) ; return ret ; } ; break ;
445+ case 8 : glCtx [ f ] = function webgl_8 ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ', ' + a7 + ', ' + a8 + ') -> ' + ret ) ; return ret ; } ; break ;
446+ case 9 : glCtx [ f ] = function webgl_9 ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ', ' + a7 + ', ' + a8 + ', ' + a9 + ') -> ' + ret ) ; return ret ; } ; break ;
447+ case 10 : glCtx [ f ] = function webgl_10 ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ', ' + a7 + ', ' + a8 + ', ' + a9 + ', ' + a10 + ') -> ' + ret ) ; return ret ; } ; break ;
448+ case 11 : glCtx [ f ] = function webgl_11 ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 ) { var ret = glCtx [ realf ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 ) ; console . error ( '[Thread ' + threadId ( ) + ', GL ctx: ' + contextHandle + ']: ' + f + '(' + a1 + ', ' + a2 + ', ' + a3 + ', ' + a4 + ', ' + a5 + ', ' + a6 + ', ' + a7 + ', ' + a8 + ', ' + a9 + ', ' + a10 + ', ' + a11 + ') -> ' + ret ) ; return ret ; } ; break ;
449+ default : throw 'hookWebGL failed! Unexpected length ' + glCtx [ realf ] . length ;
450+ }
451+ } ,
452+
453+ hookWebGL : function ( glCtx ) {
454+ if ( ! glCtx ) glCtx = this . detectWebGLContext ( ) ;
455+ if ( ! glCtx ) return ;
456+ if ( ! ( ( typeof WebGLRenderingContext !== 'undefined' && glCtx instanceof WebGLRenderingContext )
457+ || ( typeof WebGL2RenderingContext !== 'undefined' && glCtx instanceof WebGL2RenderingContext ) ) ) {
458+ return ;
459+ }
460+
461+ if ( glCtx . webGlTracerAlreadyHooked ) return ;
462+ glCtx . webGlTracerAlreadyHooked = true ;
463+
464+ // Hot GL functions are ones that you'd expect to find during render loops (render calls, dynamic resource uploads), cold GL functions are load time functions (shader compilation, texture/mesh creation)
465+ // Distinguishing between these two allows pinpointing locations of troublesome GL usage that might cause performance issues.
466+ for ( var f in glCtx ) {
467+ if ( typeof glCtx [ f ] !== 'function' || f . indexOf ( 'real_' ) == 0 ) continue ;
468+ this . hookWebGLFunction ( f , glCtx ) ;
469+ }
470+ // The above injection won't work for texImage2D and texSubImage2D, which have multiple overloads.
471+ glCtx [ 'texImage2D' ] = function ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) {
472+ var ret = ( a7 !== undefined ) ? glCtx [ 'real_texImage2D' ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) : glCtx [ 'real_texImage2D' ] ( a1 , a2 , a3 , a4 , a5 , a6 ) ;
473+ return ret ;
474+ } ;
475+ glCtx [ 'texSubImage2D' ] = function ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) {
476+ var ret = ( a8 !== undefined ) ? glCtx [ 'real_texSubImage2D' ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ) : glCtx [ 'real_texSubImage2D' ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 ) ;
477+ return ret ;
478+ } ;
479+ glCtx [ 'texSubImage3D' ] = function ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 ) {
480+ var ret = ( a9 !== undefined ) ? glCtx [ 'real_texSubImage3D' ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 ) : glCtx [ 'real_texSubImage2D' ] ( a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 ) ;
481+ return ret ;
482+ } ;
483+ } ,
484+ #endif
414485 // Returns the context handle to the new context.
415486 createContext : function ( canvas , webGLContextAttributes ) {
416487 if ( typeof webGLContextAttributes [ 'majorVersion' ] === 'undefined' && typeof webGLContextAttributes [ 'minorVersion' ] === 'undefined' ) {
@@ -462,94 +533,13 @@ var LibraryGL = {
462533 Module . print ( 'Could not create canvas: ' + [ errorInfo , e , JSON . stringify ( webGLContextAttributes ) ] ) ;
463534 return 0 ;
464535 }
465- #if GL_DEBUG
466- function wrapDebugGL ( ctx ) {
467-
468- var printObjectList = [ ] ;
469-
470- function prettyPrint ( arg ) {
471- if ( typeof arg == 'undefined' ) return '!UNDEFINED!' ;
472- if ( typeof arg == 'boolean' ) arg = arg + 0 ;
473- if ( ! arg ) return arg ;
474- var index = printObjectList . indexOf ( arg ) ;
475- if ( index >= 0 ) return '<' + arg + '|' ; // + index + '>';
476- if ( arg . toString ( ) == '[object HTMLImageElement]' ) {
477- return arg + '\n\n' ;
478- }
479- if ( arg . byteLength ) {
480- return '{' + Array . prototype . slice . call ( arg , 0 , Math . min ( arg . length , 400 ) ) + '}' ; // Useful for correct arrays, less so for compiled arrays, see the code below for that
481- var buf = new ArrayBuffer ( 32 ) ;
482- var i8buf = new Int8Array ( buf ) ;
483- var i16buf = new Int16Array ( buf ) ;
484- var f32buf = new Float32Array ( buf ) ;
485- switch ( arg . toString ( ) ) {
486- case '[object Uint8Array]' :
487- i8buf . set ( arg . subarray ( 0 , 32 ) ) ;
488- break ;
489- case '[object Float32Array]' :
490- f32buf . set ( arg . subarray ( 0 , 5 ) ) ;
491- break ;
492- case '[object Uint16Array]' :
493- i16buf . set ( arg . subarray ( 0 , 16 ) ) ;
494- break ;
495- default :
496- alert ( 'unknown array for debugging: ' + arg ) ;
497- throw 'see alert' ;
498- }
499- var ret = '{' + arg . byteLength + ':\n' ;
500- var arr = Array . prototype . slice . call ( i8buf ) ;
501- ret += 'i8:' + arr . toString ( ) . replace ( / , / g, ',' ) + '\n' ;
502- arr = Array . prototype . slice . call ( f32buf , 0 , 8 ) ;
503- ret += 'f32:' + arr . toString ( ) . replace ( / , / g, ',' ) + '}' ;
504- return ret ;
505- }
506- if ( typeof arg == 'object' ) {
507- printObjectList . push ( arg ) ;
508- return '<' + arg + '|' ; // + (printObjectList.length-1) + '>';
509- }
510- if ( typeof arg == 'number' ) {
511- if ( arg > 0 ) return '0x' + arg . toString ( 16 ) + ' (' + arg + ')' ;
512- }
513- return arg ;
514- }
515-
516- var wrapper = { } ;
517- for ( var prop in ctx ) {
518- ( function ( prop ) {
519- switch ( typeof ctx [ prop ] ) {
520- case 'function' : {
521- wrapper [ prop ] = function gl_wrapper ( ) {
522- var printArgs = Array . prototype . slice . call ( arguments ) . map ( prettyPrint ) ;
523- dump ( '[gl_f:' + prop + ':' + printArgs + ']\n' ) ;
524- var ret = ctx [ prop ] . apply ( ctx , arguments ) ;
525- if ( typeof ret != 'undefined' ) {
526- dump ( '[ gl:' + prop + ':return:' + prettyPrint ( ret ) + ']\n' ) ;
527- }
528- return ret ;
529- }
530- break ;
531- }
532- case 'number' : case 'string' : {
533- wrapper . __defineGetter__ ( prop , function ( ) {
534- //dump('[gl_g:' + prop + ':' + ctx[prop] + ']\n');
535- return ctx [ prop ] ;
536- } ) ;
537- wrapper . __defineSetter__ ( prop , function ( value ) {
538- dump ( '[gl_s:' + prop + ':' + value + ']\n' ) ;
539- ctx [ prop ] = value ;
540- } ) ;
541- break ;
542- }
543- }
544- } ) ( prop ) ;
545- }
546- return wrapper ;
547- }
548- #endif
549- // possible GL_DEBUG entry point: ctx = wrapDebugGL(ctx);
550536
551537 if ( ! ctx ) return 0 ;
552- return GL . registerContext ( ctx , webGLContextAttributes ) ;
538+ var context = GL . registerContext ( ctx , webGLContextAttributes ) ;
539+ #if TRACE_WEBGL_CALLS
540+ GL . hookWebGL ( ctx ) ;
541+ #endif
542+ return context ;
553543 } ,
554544
555545 registerContext : function ( ctx , webGLContextAttributes ) {
0 commit comments