<!-- AVATAR-FORGE · part 174 -->
derTarget is not THREE.WebGLRenderTarget.' );

			}

			let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
			if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {

				framebuffer = framebuffer[ activeCubeFaceIndex ];

			}

			if ( framebuffer ) {

				state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

				try {

					const texture = renderTarget.texture;
					const textureFormat = texture.format;
					const textureType = texture.type;

					if ( ! capabilities.textureFormatReadable( textureFormat ) ) {

						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );

					}

					if ( ! capabilities.textureTypeReadable( textureType ) ) {

						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );

					}

					// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
					if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {

						const glBuffer = _gl.createBuffer();
						_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
						_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
						_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
						_gl.flush();

						// check if the commands have finished every 8 ms
						const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
						await probeAsync( _gl, sync, 4 );

						try {

							_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
							_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );

						} finally {

							_gl.deleteBuffer( glBuffer );
							_gl.deleteSync( sync );

						}

						return buffer;

					}

				} finally {

					// restore framebuffer of current render target if necessary

					const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

				}

			}

		};

		this.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) {

			// support previous signature with position first
			if ( texture.isTexture !== true ) {

				// @deprecated, r165
				console.warn( 'WebGLRenderer: copyFramebufferToTexture function signature has changed.' );

				position = arguments[ 0 ] || null;
				texture = arguments[ 1 ];

			}

			const levelScale = Math.pow( 2, - level );
			const width = Math.floor( texture.image.width * levelScale );
			const height = Math.floor( texture.image.height * levelScale );

			const x = position !== null ? position.x : 0;
			const y = position !== null ? position.y : 0;

			textures.setTexture2D( texture, 0 );

			_gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, x, y, width, height );

			state.unbindTexture();

		};

		this.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {

			// support previous signature with dstPosition first
			if ( srcTexture.isTexture !== true ) {

				// @deprecated, r165
				console.warn( 'WebGLRenderer: copyTextureToTexture function signature has changed.' );

				dstPosition = arguments[ 0 ] || null;
				srcTexture = arguments[ 1 ];
				dstTexture = arguments[ 2 ];
				level = arguments[ 3 ] || 0;
				srcRegion = null;

			}

			let width, height, minX, minY;
			let dstX, dstY;
			if ( srcRegion !== null ) {

				width = srcRegion.max.x - srcRegion.min.x;
				height = srcRegion.max.y - srcRegion.min.y;
				minX = srcRegion.min.x;
				minY = srcRegion.min.y;

			} else {

				width = srcTexture.image.width;
				height = srcTexture.image.height;
				minX = 0;
				minY = 0;

			}

			if ( dstPosition !== null ) {

				dstX = dstPosition.x;
				dstY = dstPosition.y;

			} else {

				dstX = 0;
				dstY = 0;

			}

			const glFormat = utils.convert( dstTexture.format );
			const glType = utils.convert( dstTexture.type );

			textures.setTexture2D( dstTexture, 0 );

			// As another texture upload may have changed pixelStorei
			// parameters, make sure they are correct for the dstTexture
			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );

			const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
			const currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
			const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
			const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
			const currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );

			const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ]