Browse Source

Merge pull request #22558 from cabanier/dev

Clean up WebXR manager by calling setRenderTarget
Mr.doob 3 years ago
parent
commit
0d9851efc7

+ 7 - 1
src/renderers/WebGLMultisampleRenderTarget.js

@@ -2,12 +2,16 @@ import { WebGLRenderTarget } from './WebGLRenderTarget.js';
 
 
 class WebGLMultisampleRenderTarget extends WebGLRenderTarget {
 class WebGLMultisampleRenderTarget extends WebGLRenderTarget {
 
 
-	constructor( width, height, options ) {
+	constructor( width, height, options = {} ) {
 
 
 		super( width, height, options );
 		super( width, height, options );
 
 
 		this.samples = 4;
 		this.samples = 4;
 
 
+		this.ignoreDepthForMultisampleCopy = options.ignoreDepth !== undefined ? options.ignoreDepth : true;
+		this.useRenderToTexture = ( options.useRenderToTexture !== undefined ) ? options.useRenderToTexture : false;
+		this.useRenderbuffer = this.useRenderToTexture === false;
+
 	}
 	}
 
 
 	copy( source ) {
 	copy( source ) {
@@ -15,6 +19,8 @@ class WebGLMultisampleRenderTarget extends WebGLRenderTarget {
 		super.copy.call( this, source );
 		super.copy.call( this, source );
 
 
 		this.samples = source.samples;
 		this.samples = source.samples;
+		this.useRenderToTexture = source.useRenderToTexture;
+		this.useRenderbuffer = source.useRenderbuffer;
 
 
 		return this;
 		return this;
 
 

+ 62 - 5
src/renderers/WebGLRenderer.js

@@ -1195,7 +1195,8 @@ function WebGLRenderer( parameters = {} ) {
 				minFilter: LinearMipmapLinearFilter,
 				minFilter: LinearMipmapLinearFilter,
 				magFilter: NearestFilter,
 				magFilter: NearestFilter,
 				wrapS: ClampToEdgeWrapping,
 				wrapS: ClampToEdgeWrapping,
-				wrapT: ClampToEdgeWrapping
+				wrapT: ClampToEdgeWrapping,
+				useRenderToTexture: extensions.has( 'WEBGL_multisampled_render_to_texture' )
 			} );
 			} );
 
 
 		}
 		}
@@ -1761,15 +1762,71 @@ function WebGLRenderer( parameters = {} ) {
 
 
 	};
 	};
 
 
+	this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {
+
+		properties.get( renderTarget.texture ).__webglTexture = colorTexture;
+		properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;
+
+		const renderTargetProperties = properties.get( renderTarget );
+		renderTargetProperties.__hasExternalTextures = true;
+
+		if ( renderTargetProperties.__hasExternalTextures ) {
+
+			renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
+
+			if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
+
+				// The multisample_render_to_texture extension doesn't work properly if there
+				// are midframe flushes and an external depth buffer. Disable use of the extension.
+				if ( renderTarget.useRenderToTexture ) {
+
+					console.warn( 'render-to-texture extension was disabled because an external texture was provided' );
+					renderTarget.useRenderToTexture = false;
+					renderTarget.useRenderbuffer = true;
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {
+
+		const renderTargetProperties = properties.get( renderTarget );
+		renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
+		renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;
+
+	};
+
 	this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
 	this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
 
 
 		_currentRenderTarget = renderTarget;
 		_currentRenderTarget = renderTarget;
 		_currentActiveCubeFace = activeCubeFace;
 		_currentActiveCubeFace = activeCubeFace;
 		_currentActiveMipmapLevel = activeMipmapLevel;
 		_currentActiveMipmapLevel = activeMipmapLevel;
+		let useDefaultFramebuffer = true;
+
+		if ( renderTarget ) {
 
 
-		if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
+			const renderTargetProperties = properties.get( renderTarget );
 
 
-			textures.setupRenderTarget( renderTarget );
+			if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {
+
+				// We need to make sure to rebind the framebuffer.
+				state.bindFramebuffer( _gl.FRAMEBUFFER, null );
+				useDefaultFramebuffer = false;
+
+			} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {
+
+				textures.setupRenderTarget( renderTarget );
+
+			} else if ( renderTargetProperties.__hasExternalTextures ) {
+
+				// Color and depth texture must be rebound in order for the swapchain to update.
+				textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );
+
+			}
 
 
 		}
 		}
 
 
@@ -1794,7 +1851,7 @@ function WebGLRenderer( parameters = {} ) {
 				framebuffer = __webglFramebuffer[ activeCubeFace ];
 				framebuffer = __webglFramebuffer[ activeCubeFace ];
 				isCube = true;
 				isCube = true;
 
 
-			} else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
+			} else if ( renderTarget.useRenderbuffer ) {
 
 
 				framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
 				framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
 
 
@@ -1818,7 +1875,7 @@ function WebGLRenderer( parameters = {} ) {
 
 
 		const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 		const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 
 
-		if ( framebufferBound && capabilities.drawBuffers ) {
+		if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) {
 
 
 			let needsUpdate = false;
 			let needsUpdate = false;
 
 

+ 1 - 0
src/renderers/webgl/WebGLExtensions.js

@@ -70,6 +70,7 @@ function WebGLExtensions( gl ) {
 
 
 			getExtension( 'OES_texture_float_linear' );
 			getExtension( 'OES_texture_float_linear' );
 			getExtension( 'EXT_color_buffer_half_float' );
 			getExtension( 'EXT_color_buffer_half_float' );
+			getExtension( 'WEBGL_multisampled_render_to_texture' );
 
 
 		},
 		},
 
 

+ 0 - 17
src/renderers/webgl/WebGLState.js

@@ -316,7 +316,6 @@ function WebGLState( gl, extensions, capabilities ) {
 
 
 	let enabledCapabilities = {};
 	let enabledCapabilities = {};
 
 
-	let xrFramebuffer = null;
 	let currentBoundFramebuffers = {};
 	let currentBoundFramebuffers = {};
 
 
 	let currentProgram = null;
 	let currentProgram = null;
@@ -428,22 +427,8 @@ function WebGLState( gl, extensions, capabilities ) {
 
 
 	}
 	}
 
 
-	function bindXRFramebuffer( framebuffer ) {
-
-		if ( framebuffer !== xrFramebuffer ) {
-
-			gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
-
-			xrFramebuffer = framebuffer;
-
-		}
-
-	}
-
 	function bindFramebuffer( target, framebuffer ) {
 	function bindFramebuffer( target, framebuffer ) {
 
 
-		if ( framebuffer === null && xrFramebuffer !== null ) framebuffer = xrFramebuffer; // use active XR framebuffer if available
-
 		if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
 		if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
 
 
 			gl.bindFramebuffer( target, framebuffer );
 			gl.bindFramebuffer( target, framebuffer );
@@ -1019,7 +1004,6 @@ function WebGLState( gl, extensions, capabilities ) {
 		currentTextureSlot = null;
 		currentTextureSlot = null;
 		currentBoundTextures = {};
 		currentBoundTextures = {};
 
 
-		xrFramebuffer = null;
 		currentBoundFramebuffers = {};
 		currentBoundFramebuffers = {};
 
 
 		currentProgram = null;
 		currentProgram = null;
@@ -1063,7 +1047,6 @@ function WebGLState( gl, extensions, capabilities ) {
 		disable: disable,
 		disable: disable,
 
 
 		bindFramebuffer: bindFramebuffer,
 		bindFramebuffer: bindFramebuffer,
-		bindXRFramebuffer: bindXRFramebuffer,
 
 
 		useProgram: useProgram,
 		useProgram: useProgram,
 
 

+ 117 - 23
src/renderers/webgl/WebGLTextures.js

@@ -9,6 +9,8 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 	const maxCubemapSize = capabilities.maxCubemapSize;
 	const maxCubemapSize = capabilities.maxCubemapSize;
 	const maxTextureSize = capabilities.maxTextureSize;
 	const maxTextureSize = capabilities.maxTextureSize;
 	const maxSamples = capabilities.maxSamples;
 	const maxSamples = capabilities.maxSamples;
+	const hasMultisampledRenderToTexture = extensions.has( 'WEBGL_multisampled_render_to_texture' );
+	const MultisampledRenderToTextureExtension = hasMultisampledRenderToTexture ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : undefined;
 
 
 	const _videoTextures = new WeakMap();
 	const _videoTextures = new WeakMap();
 	let _canvas;
 	let _canvas;
@@ -901,23 +903,38 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 		const glFormat = utils.convert( texture.format );
 		const glFormat = utils.convert( texture.format );
 		const glType = utils.convert( texture.type );
 		const glType = utils.convert( texture.type );
 		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
+		const renderTargetProperties = properties.get( renderTarget );
 
 
-		if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
+		if ( ! renderTargetProperties.__hasExternalTextures ) {
 
 
-			state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null );
+			if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
 
 
-		} else {
+				state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null );
+
+			} else {
+
+				state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 
 
-			state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
+			}
 
 
 		}
 		}
 
 
 		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 );
+		if ( renderTarget.useRenderToTexture ) {
+
+			MultisampledRenderToTextureExtension.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
+
+		} else {
+
+			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 );
+
+		}
+
 		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
 		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
 
 
 	}
 	}
 
 
+
 	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
 	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
 	function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
 	function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
 
 
@@ -927,7 +944,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 			let glInternalFormat = _gl.DEPTH_COMPONENT16;
 			let glInternalFormat = _gl.DEPTH_COMPONENT16;
 
 
-			if ( isMultisample ) {
+			if ( isMultisample || renderTarget.useRenderToTexture ) {
 
 
 				const depthTexture = renderTarget.depthTexture;
 				const depthTexture = renderTarget.depthTexture;
 
 
@@ -947,7 +964,15 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 				const samples = getRenderTargetSamples( renderTarget );
 				const samples = getRenderTargetSamples( renderTarget );
 
 
-				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
+				if ( renderTarget.useRenderToTexture ) {
+
+					MultisampledRenderToTextureExtension.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
+
+				} else {
+
+					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
+
+				}
 
 
 			} else {
 			} else {
 
 
@@ -959,12 +984,16 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
 		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
 
 
-			if ( isMultisample ) {
+			const samples = getRenderTargetSamples( renderTarget );
 
 
-				const samples = getRenderTargetSamples( renderTarget );
+			if ( isMultisample && renderTarget.useRenderbuffer ) {
 
 
 				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
 				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
 
 
+			} else if ( renderTarget.useRenderToTexture ) {
+
+				MultisampledRenderToTextureExtension.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
+
 			} else {
 			} else {
 
 
 				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
 				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
@@ -982,13 +1011,16 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 			const glFormat = utils.convert( texture.format );
 			const glFormat = utils.convert( texture.format );
 			const glType = utils.convert( texture.type );
 			const glType = utils.convert( texture.type );
 			const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 			const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
+			const samples = getRenderTargetSamples( renderTarget );
 
 
-			if ( isMultisample ) {
-
-				const samples = getRenderTargetSamples( renderTarget );
+			if ( isMultisample && renderTarget.useRenderbuffer ) {
 
 
 				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
 				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
 
 
+			} else if ( renderTarget.useRenderToTexture ) {
+
+				MultisampledRenderToTextureExtension.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
+
 			} else {
 			} else {
 
 
 				_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
 				_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
@@ -1029,14 +1061,31 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 		setTexture2D( renderTarget.depthTexture, 0 );
 		setTexture2D( renderTarget.depthTexture, 0 );
 
 
 		const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
 		const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
+		const samples = getRenderTargetSamples( renderTarget );
 
 
 		if ( renderTarget.depthTexture.format === DepthFormat ) {
 		if ( renderTarget.depthTexture.format === DepthFormat ) {
 
 
-			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
+			if ( renderTarget.useRenderToTexture ) {
+
+				MultisampledRenderToTextureExtension.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
+
+			} else {
+
+				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
+
+			}
 
 
 		} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
 		} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
 
 
-			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
+			if ( renderTarget.useRenderToTexture ) {
+
+				MultisampledRenderToTextureExtension.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
+
+			} else {
+
+				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
+
+			}
 
 
 		} else {
 		} else {
 
 
@@ -1050,10 +1099,9 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 	function setupDepthRenderbuffer( renderTarget ) {
 	function setupDepthRenderbuffer( renderTarget ) {
 
 
 		const renderTargetProperties = properties.get( renderTarget );
 		const renderTargetProperties = properties.get( renderTarget );
-
 		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
 		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
 
 
-		if ( renderTarget.depthTexture ) {
+		if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {
 
 
 			if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
 			if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
 
 
@@ -1087,6 +1135,25 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 	}
 	}
 
 
+	// rebind framebuffer with external textures
+	function rebindTextures( renderTarget, colorTexture, depthTexture ) {
+
+		const renderTargetProperties = properties.get( renderTarget );
+
+		if ( colorTexture !== undefined ) {
+
+			setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
+
+		}
+
+		if ( depthTexture !== undefined ) {
+
+			setupDepthRenderbuffer( renderTarget );
+
+		}
+
+	}
+
 	// Set up GL resources for the render target
 	// Set up GL resources for the render target
 	function setupRenderTarget( renderTarget ) {
 	function setupRenderTarget( renderTarget ) {
 
 
@@ -1099,7 +1166,12 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 		if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
 		if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
 
 
-			textureProperties.__webglTexture = _gl.createTexture();
+			if ( textureProperties.__webglTexture === undefined ) {
+
+				textureProperties.__webglTexture = _gl.createTexture();
+
+			}
+
 			textureProperties.__version = texture.version;
 			textureProperties.__version = texture.version;
 			info.memory.textures ++;
 			info.memory.textures ++;
 
 
@@ -1107,7 +1179,6 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
 		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
 		const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
 		const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
-		const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
 		const isRenderTarget3D = texture.isDataTexture3D || texture.isDataTexture2DArray;
 		const isRenderTarget3D = texture.isDataTexture3D || texture.isDataTexture2DArray;
 		const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
 		const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
 
 
@@ -1163,7 +1234,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 				}
 				}
 
 
-			} else if ( isMultisample ) {
+			} else if ( renderTarget.useRenderbuffer ) {
 
 
 				if ( isWebGL2 ) {
 				if ( isWebGL2 ) {
 
 
@@ -1318,23 +1389,43 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 	function updateMultisampleRenderTarget( renderTarget ) {
 	function updateMultisampleRenderTarget( renderTarget ) {
 
 
-		if ( renderTarget.isWebGLMultisampleRenderTarget ) {
+		if ( renderTarget.useRenderbuffer ) {
 
 
 			if ( isWebGL2 ) {
 			if ( isWebGL2 ) {
 
 
 				const width = renderTarget.width;
 				const width = renderTarget.width;
 				const height = renderTarget.height;
 				const height = renderTarget.height;
 				let mask = _gl.COLOR_BUFFER_BIT;
 				let mask = _gl.COLOR_BUFFER_BIT;
+				const invalidationArray = [ _gl.COLOR_ATTACHMENT0 ];
+				const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
+
+				if ( renderTarget.depthBuffer ) {
+
+					invalidationArray.push( depthStyle );
 
 
-				if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
-				if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
+				}
+
+				if ( ! renderTarget.ignoreDepthForMultisampleCopy ) {
+
+					if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
+					if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
+
+				}
 
 
 				const renderTargetProperties = properties.get( renderTarget );
 				const renderTargetProperties = properties.get( renderTarget );
 
 
 				state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
 				state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
 				state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
 				state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
 
 
+				if ( renderTarget.ignoreDepthForMultisampleCopy ) {
+
+					_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] );
+					_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
+
+				}
+
 				_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
 				_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
+				_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray );
 
 
 				state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
 				state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
 				state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
 				state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
@@ -1351,7 +1442,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 
 	function getRenderTargetSamples( renderTarget ) {
 	function getRenderTargetSamples( renderTarget ) {
 
 
-		return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
+		return ( isWebGL2 && ( renderTarget.useRenderbuffer || renderTarget.useRenderToTexture ) ) ?
 			Math.min( maxSamples, renderTarget.samples ) : 0;
 			Math.min( maxSamples, renderTarget.samples ) : 0;
 
 
 	}
 	}
@@ -1424,9 +1515,12 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 	this.setTexture2DArray = setTexture2DArray;
 	this.setTexture2DArray = setTexture2DArray;
 	this.setTexture3D = setTexture3D;
 	this.setTexture3D = setTexture3D;
 	this.setTextureCube = setTextureCube;
 	this.setTextureCube = setTextureCube;
+	this.rebindTextures = rebindTextures;
 	this.setupRenderTarget = setupRenderTarget;
 	this.setupRenderTarget = setupRenderTarget;
 	this.updateRenderTargetMipmap = updateRenderTargetMipmap;
 	this.updateRenderTargetMipmap = updateRenderTargetMipmap;
 	this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
 	this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
+	this.setupDepthRenderbuffer = setupDepthRenderbuffer;
+	this.setupFrameBufferTexture = setupFrameBufferTexture;
 
 
 	this.safeSetTexture2D = safeSetTexture2D;
 	this.safeSetTexture2D = safeSetTexture2D;
 	this.safeSetTextureCube = safeSetTextureCube;
 	this.safeSetTextureCube = safeSetTextureCube;

+ 68 - 107
src/renderers/webxr/WebXRManager.js

@@ -4,7 +4,19 @@ import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
 import { Vector3 } from '../../math/Vector3.js';
 import { Vector3 } from '../../math/Vector3.js';
 import { Vector4 } from '../../math/Vector4.js';
 import { Vector4 } from '../../math/Vector4.js';
 import { WebGLAnimation } from '../webgl/WebGLAnimation.js';
 import { WebGLAnimation } from '../webgl/WebGLAnimation.js';
+import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
 import { WebXRController } from './WebXRController.js';
 import { WebXRController } from './WebXRController.js';
+import { DepthTexture } from '../../textures/DepthTexture.js';
+import { WebGLMultisampleRenderTarget } from '../WebGLMultisampleRenderTarget.js';
+import {
+	DepthFormat,
+	DepthStencilFormat,
+	RGBAFormat,
+	RGBFormat,
+	UnsignedByteType,
+	UnsignedShortType,
+	UnsignedInt248Type,
+} from '../../constants.js';
 
 
 class WebXRManager extends EventDispatcher {
 class WebXRManager extends EventDispatcher {
 
 
@@ -13,26 +25,23 @@ class WebXRManager extends EventDispatcher {
 		super();
 		super();
 
 
 		const scope = this;
 		const scope = this;
-		const state = renderer.state;
 
 
 		let session = null;
 		let session = null;
 		let framebufferScaleFactor = 1.0;
 		let framebufferScaleFactor = 1.0;
 
 
 		let referenceSpace = null;
 		let referenceSpace = null;
 		let referenceSpaceType = 'local-floor';
 		let referenceSpaceType = 'local-floor';
+		const hasMultisampledRenderToTexture = renderer.extensions.has( 'WEBGL_multisampled_render_to_texture' );
 
 
 		let pose = null;
 		let pose = null;
 		let glBinding = null;
 		let glBinding = null;
-		let glFramebuffer = null;
 		let glProjLayer = null;
 		let glProjLayer = null;
 		let glBaseLayer = null;
 		let glBaseLayer = null;
 		let isMultisample = false;
 		let isMultisample = false;
-		let glMultisampledFramebuffer = null;
-		let glColorRenderbuffer = null;
-		let glDepthRenderbuffer = null;
 		let xrFrame = null;
 		let xrFrame = null;
-		let depthStyle = null;
-		let clearStyle = null;
+		const attributes = gl.getContextAttributes();
+		let initialRenderTarget = null;
+		let newRenderTarget = null;
 
 
 		const controllers = [];
 		const controllers = [];
 		const inputSourcesMap = new Map();
 		const inputSourcesMap = new Map();
@@ -137,21 +146,13 @@ class WebXRManager extends EventDispatcher {
 
 
 			// restore framebuffer/rendering state
 			// restore framebuffer/rendering state
 
 
-			state.bindXRFramebuffer( null );
-			renderer.setRenderTarget( renderer.getRenderTarget() );
-
-			if ( glFramebuffer ) gl.deleteFramebuffer( glFramebuffer );
-			if ( glMultisampledFramebuffer ) gl.deleteFramebuffer( glMultisampledFramebuffer );
-			if ( glColorRenderbuffer ) gl.deleteRenderbuffer( glColorRenderbuffer );
-			if ( glDepthRenderbuffer ) gl.deleteRenderbuffer( glDepthRenderbuffer );
-			glFramebuffer = null;
-			glMultisampledFramebuffer = null;
-			glColorRenderbuffer = null;
-			glDepthRenderbuffer = null;
+			renderer.setRenderTarget( initialRenderTarget );
+
 			glBaseLayer = null;
 			glBaseLayer = null;
 			glProjLayer = null;
 			glProjLayer = null;
 			glBinding = null;
 			glBinding = null;
 			session = null;
 			session = null;
+			newRenderTarget = null;
 
 
 			//
 			//
 
 
@@ -223,6 +224,8 @@ class WebXRManager extends EventDispatcher {
 
 
 			if ( session !== null ) {
 			if ( session !== null ) {
 
 
+				initialRenderTarget = renderer.getRenderTarget();
+
 				session.addEventListener( 'select', onSessionEvent );
 				session.addEventListener( 'select', onSessionEvent );
 				session.addEventListener( 'selectstart', onSessionEvent );
 				session.addEventListener( 'selectstart', onSessionEvent );
 				session.addEventListener( 'selectend', onSessionEvent );
 				session.addEventListener( 'selectend', onSessionEvent );
@@ -232,18 +235,16 @@ class WebXRManager extends EventDispatcher {
 				session.addEventListener( 'end', onSessionEnd );
 				session.addEventListener( 'end', onSessionEnd );
 				session.addEventListener( 'inputsourceschange', onInputSourcesChange );
 				session.addEventListener( 'inputsourceschange', onInputSourcesChange );
 
 
-				const attributes = gl.getContextAttributes();
-
 				if ( attributes.xrCompatible !== true ) {
 				if ( attributes.xrCompatible !== true ) {
 
 
 					await gl.makeXRCompatible();
 					await gl.makeXRCompatible();
 
 
 				}
 				}
 
 
-				if ( session.renderState.layers === undefined ) {
+				if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) {
 
 
 					const layerInit = {
 					const layerInit = {
-						antialias: attributes.antialias,
+						antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true,
 						alpha: attributes.alpha,
 						alpha: attributes.alpha,
 						depth: attributes.depth,
 						depth: attributes.depth,
 						stencil: attributes.stencil,
 						stencil: attributes.stencil,
@@ -254,43 +255,29 @@ class WebXRManager extends EventDispatcher {
 
 
 					session.updateRenderState( { baseLayer: glBaseLayer } );
 					session.updateRenderState( { baseLayer: glBaseLayer } );
 
 
-				} else if ( gl instanceof WebGLRenderingContext ) {
-
-					// Use old style webgl layer because we can't use MSAA
-					// WebGL2 support.
-
-					const layerInit = {
-						antialias: true,
-						alpha: attributes.alpha,
-						depth: attributes.depth,
-						stencil: attributes.stencil,
-						framebufferScaleFactor: framebufferScaleFactor
-					};
-
-					glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
-
-					session.updateRenderState( { layers: [ glBaseLayer ] } );
+					newRenderTarget = new WebGLRenderTarget(
+						glBaseLayer.framebufferWidth,
+						glBaseLayer.framebufferHeight
+					);
 
 
 				} else {
 				} else {
 
 
 					isMultisample = attributes.antialias;
 					isMultisample = attributes.antialias;
 					let depthFormat = null;
 					let depthFormat = null;
-
+					let depthType = null;
+					let glDepthFormat = null;
 
 
 					if ( attributes.depth ) {
 					if ( attributes.depth ) {
 
 
-						clearStyle = gl.DEPTH_BUFFER_BIT;
-
-						if ( attributes.stencil ) clearStyle |= gl.STENCIL_BUFFER_BIT;
-
-						depthStyle = attributes.stencil ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
-						depthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
+						glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT16;
+						depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;
+						depthType = attributes.stencil ? UnsignedInt248Type : UnsignedShortType;
 
 
 					}
 					}
 
 
 					const projectionlayerInit = {
 					const projectionlayerInit = {
-						colorFormat: attributes.alpha ? gl.RGBA8 : gl.RGB8,
-						depthFormat: depthFormat,
+						colorFormat: ( attributes.alpha || isMultisample ) ? gl.RGBA8 : gl.RGB8,
+						depthFormat: glDepthFormat,
 						scaleFactor: framebufferScaleFactor
 						scaleFactor: framebufferScaleFactor
 					};
 					};
 
 
@@ -298,41 +285,42 @@ class WebXRManager extends EventDispatcher {
 
 
 					glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
 					glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
 
 
-					glFramebuffer = gl.createFramebuffer();
-
 					session.updateRenderState( { layers: [ glProjLayer ] } );
 					session.updateRenderState( { layers: [ glProjLayer ] } );
 
 
 					if ( isMultisample ) {
 					if ( isMultisample ) {
 
 
-						glMultisampledFramebuffer = gl.createFramebuffer();
-						glColorRenderbuffer = gl.createRenderbuffer();
-						gl.bindRenderbuffer( gl.RENDERBUFFER, glColorRenderbuffer );
-						gl.renderbufferStorageMultisample(
-							gl.RENDERBUFFER,
-							4,
-							gl.RGBA8,
+						newRenderTarget = new WebGLMultisampleRenderTarget(
 							glProjLayer.textureWidth,
 							glProjLayer.textureWidth,
-							glProjLayer.textureHeight );
-						state.bindFramebuffer( gl.FRAMEBUFFER, glMultisampledFramebuffer );
-						gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, glColorRenderbuffer );
-						gl.bindRenderbuffer( gl.RENDERBUFFER, null );
-
-						if ( depthFormat !== null ) {
-
-							glDepthRenderbuffer = gl.createRenderbuffer();
-							gl.bindRenderbuffer( gl.RENDERBUFFER, glDepthRenderbuffer );
-							gl.renderbufferStorageMultisample( gl.RENDERBUFFER, 4, depthFormat, glProjLayer.textureWidth, glProjLayer.textureHeight );
-							gl.framebufferRenderbuffer( gl.FRAMEBUFFER, depthStyle, gl.RENDERBUFFER, glDepthRenderbuffer );
-							gl.bindRenderbuffer( gl.RENDERBUFFER, null );
+							glProjLayer.textureHeight,
+							{
+								format: RGBAFormat,
+								type: UnsignedByteType,
+								depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
+								stencilBuffer: attributes.stencil,
+								ignoreDepth: glProjLayer.ignoreDepthValues,
+								useRenderToTexture: hasMultisampledRenderToTexture,
+							} );
 
 
-						}
+					} else {
 
 
-						state.bindFramebuffer( gl.FRAMEBUFFER, null );
+						newRenderTarget = new WebGLRenderTarget(
+							glProjLayer.textureWidth,
+							glProjLayer.textureHeight,
+							{
+								format: attributes.alpha ? RGBAFormat : RGBFormat,
+								type: UnsignedByteType,
+								depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
+								stencilBuffer: attributes.stencil,
+								ignoreDepth: glProjLayer.ignoreDepthValues,
+							} );
 
 
 					}
 					}
 
 
 				}
 				}
 
 
+				// Set foveation to maximum.
+				this.setFoveation( 0 );
+
 				referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
 				referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
 
 
 				animation.setContext( session );
 				animation.setContext( session );
@@ -591,7 +579,8 @@ class WebXRManager extends EventDispatcher {
 
 
 				if ( glBaseLayer !== null ) {
 				if ( glBaseLayer !== null ) {
 
 
-					state.bindXRFramebuffer( glBaseLayer.framebuffer );
+					renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
+					renderer.setRenderTarget( newRenderTarget );
 
 
 				}
 				}
 
 
@@ -602,7 +591,6 @@ class WebXRManager extends EventDispatcher {
 				if ( views.length !== cameraVR.cameras.length ) {
 				if ( views.length !== cameraVR.cameras.length ) {
 
 
 					cameraVR.cameras.length = 0;
 					cameraVR.cameras.length = 0;
-
 					cameraVRNeedsUpdate = true;
 					cameraVRNeedsUpdate = true;
 
 
 				}
 				}
@@ -620,19 +608,20 @@ class WebXRManager extends EventDispatcher {
 					} else {
 					} else {
 
 
 						const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
 						const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
+						viewport = glSubImage.viewport;
 
 
-						state.bindXRFramebuffer( glFramebuffer );
+						// For side-by-side projection, we only produce a single texture for both eyes.
+						if ( i === 0 ) {
 
 
-						if ( glSubImage.depthStencilTexture !== undefined ) {
+							renderer.setRenderTargetTextures(
+								newRenderTarget,
+								glSubImage.colorTexture,
+								glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );
 
 
-							gl.framebufferTexture2D( gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, glSubImage.depthStencilTexture, 0 );
+							renderer.setRenderTarget( newRenderTarget );
 
 
 						}
 						}
 
 
-						gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glSubImage.colorTexture, 0 );
-
-						viewport = glSubImage.viewport;
-
 					}
 					}
 
 
 					const camera = cameras[ i ];
 					const camera = cameras[ i ];
@@ -655,14 +644,6 @@ class WebXRManager extends EventDispatcher {
 
 
 				}
 				}
 
 
-				if ( isMultisample ) {
-
-					state.bindXRFramebuffer( glMultisampledFramebuffer );
-
-					if ( clearStyle !== null ) gl.clear( clearStyle );
-
-				}
-
 			}
 			}
 
 
 			//
 			//
@@ -680,26 +661,6 @@ class WebXRManager extends EventDispatcher {
 
 
 			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
 			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
 
 
-			if ( isMultisample ) {
-
-				const width = glProjLayer.textureWidth;
-				const height = glProjLayer.textureHeight;
-
-				state.bindFramebuffer( gl.READ_FRAMEBUFFER, glMultisampledFramebuffer );
-				state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, glFramebuffer );
-				// Invalidate the depth here to avoid flush of the depth data to main memory.
-				gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, [ depthStyle ] );
-				gl.invalidateFramebuffer( gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
-				gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
-				// Invalidate the MSAA buffer because it's not needed anymore.
-				gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, [ gl.COLOR_ATTACHMENT0 ] );
-				state.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
-				state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
-
-				state.bindFramebuffer( gl.FRAMEBUFFER, glMultisampledFramebuffer );
-
-			}
-
 			xrFrame = null;
 			xrFrame = null;
 
 
 		}
 		}