WebXR/WebGPU Binding Module - Level 1

Editor’s Draft,

More details about this document
This version:
https://immersive-web.github.io/webxr-webgpu-binding/
Latest published version:
https://www.w3.org/TR/webxr-webgpu-binding-1/
Previous Versions:
Feedback:
GitHub
Editor:
(Google)
Unstable API

The API represented in this document is under development and may change at any time.

For additional context on the use of this API please reference the WebXR/WebGPU Binding Module Explainer.


Abstract

This specification describes support for rendering content for a WebXR session with WebGPU.

Status of this document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This document was published by the Immersive Web Working Group as an Editors' Draft. This document is intended to become a W3C Recommendation. Feedback and comments on this specification are welcome. Please use Github issues. Discussions may also be found in the public-immersive-web-wg@w3.org archives.

Publication as an Editors' Draft does not imply endorsement by W3C and its Members. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 03 November 2023 W3C Process Document.

1. Introduction

This spec adds support for creation of XRCompositionLayers, as described in the WebXR Layers API, which are rendered using the WebGPU API.

WebGPU is an API for utilizing the graphics and compute capabilities of a device’s GPU more efficiently than WebGL allows, with an API that better matches both GPU hardware architecture and the modern native APIs that interface with them, such as Vulkan, Direct3D 12, and Metal.

1.1. Application flow

If an author wants to use WebGPU to render content for a WebXR Session, they must perform the following steps:

In no particular order

  1. Create a GPUDevice from an GPUAdapter which was requested with the xrCompatible option set to true.

  2. Create an XRSession with the webgpu feature.

Then

  1. Create an XRGPUBinding with both the XR-compatible GPUDevice and WebGPU-compatible session.

  2. Create one or more XRCompositionLayers with the XRGPUBinding

  3. Add the layers to XRRenderStateInit and call updateRenderState().

  4. During requestAnimationFrame() for each WebGPU layer:

    1. For each XRGPUSubImage exposed by the layer:

      1. Draw the contents of the subimage using the GPUDevice the XRGPUBinding was created with.

2. Initialization

2.1. "webgpu" feature

If an application wants to use WebGPU for rendering during a session, the session MUST be requested with an appropriate feature descriptor. The string "webgpu" is introduced by this module as a new valid feature descriptor for the WebXR/WebGPU Bindings feature. XRSessions created with the webgpu feature are considered WebGPU-compatible sessions.

A WebGPU-compatible session MUST have the following behavioral from a WebGL-compatible session:

The following code creates a WebGPU-compatible session.
navigator.xr.requestSession('immersive-vr', {
  requiredFeatures: ['webgpu']
}

Note: The webgpu feature may be passed to either requiredFeatures or optionalFeatures, but if passed to optionalFeatures the author must check enabledFeatures after the session is created and use either WebGPU or WebGL to render the session’s content depending on if webgpu is present.

2.2. GPUAdapter integration

partial dictionary GPURequestAdapterOptions {
    boolean xrCompatible = false;
};

Note: There is no WebGPU equivalent to the makeXRCompatible() method to make a GPUDevice XR-compatible after creation.

2.3. XRGPUBinding

[Exposed=(Window), SecureContext]
interface XRGPUBinding {
  constructor(XRSession session, GPUDevice device);

  readonly attribute double nativeProjectionScaleFactor;

  XRProjectionLayer createProjectionLayer(optional XRGPUProjectionLayerInit init);
  XRQuadLayer createQuadLayer(optional XRGPUQuadLayerInit init);
  XRCylinderLayer createCylinderLayer(optional XRGPUCylinderLayerInit init);
  XREquirectLayer createEquirectLayer(optional XRGPUEquirectLayerInit init);
  XRCubeLayer createCubeLayer(optional XRGPUCubeLayerInit init);

  XRGPUSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none");
  XRGPUSubImage getViewSubImage(XRProjectionLayer layer, XRView view);
  
  GPUTextureFormat getPreferredColorFormat();
};

3. Rendering

3.1. XRGPUSubImage

[Exposed=(Window), SecureContext]
interface XRGPUSubImage : XRSubImage {
  [SameObject] readonly attribute GPUTexture colorTexture;
  [SameObject] readonly attribute GPUTexture? depthStencilTexture;
  [SameObject] readonly attribute GPUTexture? motionVectorTexture;
  GPUTextureViewDescriptor getViewDescriptor();
};

4. Layer Creation

4.1. XRGPUProjectionLayerInit

[Exposed=(Window), SecureContext]
dictionary XRGPUProjectionLayerInit {
  required GPUTextureFormat colorFormat;
  GPUTextureFormat? depthStencilFormat;
  GPUTextureUsageFlags textureUsage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT 
  double scaleFactor = 1.0;
};

4.2. XRGPULayerInit

[Exposed=(Window), SecureContext]
dictionary XRGPULayerInit {
  required GPUTextureFormat colorFormat;
  GPUTextureFormat? depthStencilFormat;
  GPUTextureUsageFlags textureUsage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT
  required XRSpace space;
  unsigned long mipLevels = 1;
  required unsigned long viewPixelWidth;
  required unsigned long viewPixelHeight;
  XRLayerLayout layout = "mono";
  boolean isStatic = false;
};

4.3. XRGPUQuadLayerInit

dictionary XRGPUQuadLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float width = 1.0;
  float height = 1.0;
};

4.4. XRGPUCylinderLayerInit

dictionary XRGPUCylinderLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float aspectRatio = 2.0;
};

4.5. XRGPUEquirectLayerInit

dictionary XRGPUEquirectLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float radius = 0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

4.6. XRGPUCubeLayerInit

dictionary XRGPUCubeLayerInit : XRGPULayerInit {
  DOMPointReadOnly? orientation;
};

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[GEOMETRY-1]
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. URL: https://drafts.fxtf.org/geometry/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGPU]
Kai Ninomiya; Brandon Jones; Jim Blandy. WebGPU. URL: https://gpuweb.github.io/gpuweb/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WEBXR]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Device API. URL: https://immersive-web.github.io/webxr/
[WEBXRLAYERS-1]
Rik Cabanier. WebXR Layers API Level 1. URL: https://immersive-web.github.io/layers/

IDL Index

partial dictionary GPURequestAdapterOptions {
    boolean xrCompatible = false;
};

[Exposed=(Window), SecureContext]
interface XRGPUBinding {
  constructor(XRSession session, GPUDevice device);

  readonly attribute double nativeProjectionScaleFactor;

  XRProjectionLayer createProjectionLayer(optional XRGPUProjectionLayerInit init);
  XRQuadLayer createQuadLayer(optional XRGPUQuadLayerInit init);
  XRCylinderLayer createCylinderLayer(optional XRGPUCylinderLayerInit init);
  XREquirectLayer createEquirectLayer(optional XRGPUEquirectLayerInit init);
  XRCubeLayer createCubeLayer(optional XRGPUCubeLayerInit init);

  XRGPUSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none");
  XRGPUSubImage getViewSubImage(XRProjectionLayer layer, XRView view);
  
  GPUTextureFormat getPreferredColorFormat();
};

[Exposed=(Window), SecureContext]
interface XRGPUSubImage : XRSubImage {
  [SameObject] readonly attribute GPUTexture colorTexture;
  [SameObject] readonly attribute GPUTexture? depthStencilTexture;
  [SameObject] readonly attribute GPUTexture? motionVectorTexture;
  GPUTextureViewDescriptor getViewDescriptor();
};

[Exposed=(Window), SecureContext]
dictionary XRGPUProjectionLayerInit {
  required GPUTextureFormat colorFormat;
  GPUTextureFormat? depthStencilFormat;
  GPUTextureUsageFlags textureUsage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT 
  double scaleFactor = 1.0;
};

[Exposed=(Window), SecureContext]
dictionary XRGPULayerInit {
  required GPUTextureFormat colorFormat;
  GPUTextureFormat? depthStencilFormat;
  GPUTextureUsageFlags textureUsage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT
  required XRSpace space;
  unsigned long mipLevels = 1;
  required unsigned long viewPixelWidth;
  required unsigned long viewPixelHeight;
  XRLayerLayout layout = "mono";
  boolean isStatic = false;
};

dictionary XRGPUQuadLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float width = 1.0;
  float height = 1.0;
};

dictionary XRGPUCylinderLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float aspectRatio = 2.0;
};

dictionary XRGPUEquirectLayerInit : XRGPULayerInit {
  XRRigidTransform? transform;
  float radius = 0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

dictionary XRGPUCubeLayerInit : XRGPULayerInit {
  DOMPointReadOnly? orientation;
};