Skip to content

WebGL context must be marked as XR compatible in order to use with an immersive XRSession #20715

@ranbuch

Description

@ranbuch

When calling WebXRManager.setSession( value ) you sometimes might get this message:

Uncaught (in promise) DOMException: Failed to construct 'XRWebGLLayer': WebGL context must be marked as XR compatible in order to use with an immersive XRSession

To Reproduce

I am able to reproduce the issue only on my localhost environment. When serving my viewer from the server it's working fine.

The reason for this issue is a racing condition.

when creating an instance of XRWebGLLayer the WebGL context (gl) should already be XR compatible enabled.

The gl.makeXRCompatible() function returns a Promise.

Current setSession Code

	this.setSession = function ( value ) {

		session = value;

		if ( session !== null ) {

			session.addEventListener( 'select', onSessionEvent );
			session.addEventListener( 'selectstart', onSessionEvent );
			session.addEventListener( 'selectend', onSessionEvent );
			session.addEventListener( 'squeeze', onSessionEvent );
			session.addEventListener( 'squeezestart', onSessionEvent );
			session.addEventListener( 'squeezeend', onSessionEvent );
			session.addEventListener( 'end', onSessionEnd );

			const attributes = gl.getContextAttributes();

			if ( attributes.xrCompatible !== true ) {

				gl.makeXRCompatible();

			}

			const layerInit = {
				antialias: attributes.antialias,
				alpha: attributes.alpha,
				depth: attributes.depth,
				stencil: attributes.stencil,
				framebufferScaleFactor: framebufferScaleFactor
			};

			// eslint-disable-next-line no-undef
			const baseLayer = new XRWebGLLayer( session, gl, layerInit );

			session.updateRenderState( { baseLayer: baseLayer } );

			session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace );

			//

			session.addEventListener( 'inputsourceschange', updateInputSources );

		}

	};

Suggested setSession Code

	this.setSession = function ( value ) {

		session = value;

		if ( session !== null ) {

			session.addEventListener( 'select', onSessionEvent );
			session.addEventListener( 'selectstart', onSessionEvent );
			session.addEventListener( 'selectend', onSessionEvent );
			session.addEventListener( 'squeeze', onSessionEvent );
			session.addEventListener( 'squeezestart', onSessionEvent );
			session.addEventListener( 'squeezeend', onSessionEvent );
			session.addEventListener( 'end', onSessionEnd );

			const attributes = gl.getContextAttributes();

			const setSession = function() {
				const layerInit = {
					antialias: attributes.antialias,
					alpha: attributes.alpha,
					depth: attributes.depth,
					stencil: attributes.stencil,
					framebufferScaleFactor: framebufferScaleFactor
				};
	
				// eslint-disable-next-line no-undef
				const baseLayer = new XRWebGLLayer( session, gl, layerInit );
	
				session.updateRenderState( { baseLayer: baseLayer } );
	
				session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace );
	
				//
	
				session.addEventListener( 'inputsourceschange', updateInputSources );
			};

			if ( attributes.xrCompatible !== true ) {

				gl.makeXRCompatible( setSession );

			} else {

				setSession();

			}

		}

	};

Screenshots
image

Platform:

  • Device: Mobile (Samsung Galaxy S20 Ultra - Exynos variant)
  • OS: Android 11
  • Browser: Chrome Canary 89.0.4329.2
  • Three.js version: dev, r122

I can create a pull request myself, I just remember that the way to do is on this repo isn't so straghtfarward.

Fork dev?

Build and then push?

If someone wants to do it be my guest. If not, please provide a link or explains how to do it right.

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions