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;

	}
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.