async setSession( session ) {

		const renderer = this._renderer;
		const backend = renderer.backend;

		this._gl = renderer.getContext();
		const gl = this._gl;
		const attributes = gl.getContextAttributes();

		this._session = session;

		if ( session !== null ) {

			if ( backend.isWebGPUBackend === true ) throw new Error( 'THREE.XRManager: XR is currently not supported with a WebGPU backend. Use WebGL by passing "{ forceWebGL: true }" to the constructor of the renderer.' );

			session.addEventListener( 'select', this._onSessionEvent );
			session.addEventListener( 'selectstart', this._onSessionEvent );
			session.addEventListener( 'selectend', this._onSessionEvent );
			session.addEventListener( 'squeeze', this._onSessionEvent );
			session.addEventListener( 'squeezestart', this._onSessionEvent );
			session.addEventListener( 'squeezeend', this._onSessionEvent );
			session.addEventListener( 'end', this._onSessionEnd );
			session.addEventListener( 'inputsourceschange', this._onInputSourcesChange );

			await backend.makeXRCompatible();

			this._currentPixelRatio = renderer.getPixelRatio();
			renderer.getSize( this._currentSize );

			this._currentAnimationContext = renderer._animation.getContext();
			this._currentAnimationLoop = renderer._animation.getAnimationLoop();
			renderer._animation.stop();

			//

			if ( this._useLayers === true ) {

				// default path using XRWebGLBinding/XRProjectionLayer

				let depthFormat = null;
				let depthType = null;
				let glDepthFormat = null;

				if ( renderer.depth ) {

					glDepthFormat = renderer.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
					depthFormat = renderer.stencil ? DepthStencilFormat : DepthFormat;
					depthType = renderer.stencil ? UnsignedInt248Type : UnsignedIntType;

				}

				const projectionlayerInit = {
					colorFormat: gl.RGBA8,
					depthFormat: glDepthFormat,
					scaleFactor: this._framebufferScaleFactor,
					clearOnAccess: false
				};

				if ( this._useMultiviewIfPossible && renderer.hasFeature( 'OVR_multiview2' ) ) {

					projectionlayerInit.textureType = 'texture-array';
					this._useMultiview = true;

				}

				const glBinding = new XRWebGLBinding( session, gl );
				const glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
				const layersArray = [ glProjLayer ];

				this._glBinding = glBinding;
				this._glProjLayer = glProjLayer;

				renderer.setPixelRatio( 1 );
				renderer._setXRLayerSize( glProjLayer.textureWidth, glProjLayer.textureHeight );

				const depth = this._useMultiview ? 2 : 1;
				const depthTexture = new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat, depth );

				this._xrRenderTarget = new XRRenderTarget(
					glProjLayer.textureWidth,
					glProjLayer.textureHeight,
					{
						format: RGBAFormat,
						type: UnsignedByteType,
						colorSpace: renderer.outputColorSpace,
						depthTexture: depthTexture,
						stencilBuffer: renderer.stencil,
						samples: attributes.antialias ? 4 : 0,
						resolveDepthBuffer: ( glProjLayer.ignoreDepthValues === false ),
						resolveStencilBuffer: ( glProjLayer.ignoreDepthValues === false ),
						depth: this._useMultiview ? 2 : 1,
						multiview: this._useMultiview
					} );

				this._xrRenderTarget._hasExternalTextures = true;
				this._xrRenderTarget.depth = this._useMultiview ? 2 : 1;

				this._supportsLayers = session.enabledFeatures.includes( 'layers' );

				this._referenceSpace = await session.requestReferenceSpace( this.getReferenceSpaceType() );

				if ( this._supportsLayers ) {

					// switch layers to native
					for ( const layer of this._layers ) {

						// change material so it "punches" out a hole to show the XR Layer.
						layer.plane.material = new MeshBasicMaterial( { color: 0xffffff, side: layer.type === 'cylinder' ? BackSide : FrontSide } );
						layer.plane.material.blending = CustomBlending;
						layer.plane.material.blendEquation = AddEquation;
						layer.plane.material.blendSrc = ZeroFactor;
						layer.plane.material.blendDst = ZeroFactor;

						layer.xrlayer = this._createXRLayer( layer );

						layersArray.unshift( layer.xrlayer );

					}

				}

				session.updateRenderState( { layers: layersArray } );

			} else {

				// fallback to XRWebGLLayer

				const layerInit = {
					antialias: renderer.samples > 0,
					alpha: true,
					depth: renderer.depth,
					stencil: renderer.stencil,
					framebufferScaleFactor: this.getFramebufferScaleFactor()
				};

				const glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
				this._glBaseLayer = glBaseLayer;

				session.updateRenderState( { baseLayer: glBaseLayer } );

				renderer.setPixelRatio( 1 );
				renderer._setXRLayerSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight );

				this._xrRenderTarget = new XRRenderTarget(
					glBaseLayer.framebufferWidth,
					glBaseLayer.framebufferHeight,
					{
						format: RGBAFormat,
						type: UnsignedByteType,
						colorSpace: renderer.outputColorSpace,
						stencilBuffer: renderer.stencil,
						resolveDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ),
						resolveStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ),
					}
				);

				this._xrRenderTarget._isOpaqueFramebuffer = true;
				this._referenceSpace = await session.requestReferenceSpace( this.getReferenceSpaceType() );

			}

			//

			this.setFoveation( this.getFoveation() );

			renderer._animation.setAnimationLoop( this._onAnimationFrame );
			renderer._animation.setContext( session );
			renderer._animation.start();

			this.isPresenting = true;

			this.dispatchEvent( { type: 'sessionstart' } );

		}

	}
After a XR session has been requested usually with one of the `*Button` modules, it
is injected into the renderer with this method. This method triggers the start of
the actual XR rendering.

@async
@param {XRSession} session - The XR session to set.
@return {Promise} A Promise that resolves when the session has been set.