WebGPU

Editor’s Draft,

This version:
https://gpuweb.github.io/gpuweb
Editor:
The GPU for the Web Community Group (W3C)
Not Ready For Implementation

This spec is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement this spec, please contact the editors.


Abstract

WebGPU exposes an API for performing operations, such as rendering and computation, on a Graphics Processing Unit.

Status of this document

This specification was published by the GPU for the Web Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. Introduction

This specification rocks.

2. Type Definitions

typedef long i32;
typedef unsigned long u32;
typedef unsigned long long u64;

dictionary GPUColorDict {
    required float r;
    required float g;
    required float b;
    required float a;
};
typedef (sequence<float> or GPUColorDict) GPUColor;

dictionary GPUOrigin2DDict {
    u32 x = 0;
    u32 y = 0;
};
typedef (sequence<u32> or GPUOrigin2DDict) GPUOrigin2D;

dictionary GPUOrigin3DDict {
    u32 x = 0;
    u32 y = 0;
    u32 z = 0;
};
typedef (sequence<u32> or GPUOrigin3DDict) GPUOrigin3D;

dictionary GPUExtent3DDict {
    required u32 width;
    required u32 height;
    required u32 depth;
};
typedef (sequence<u32> or GPUExtent3DDict) GPUExtent3D;

typedef sequence<any> GPUMappedBuffer;  // [GPUBuffer, ArrayBuffer]

interface mixin GPUObjectBase {
    attribute DOMString? label;
};

dictionary GPUObjectDescriptorBase {
    DOMString? label;
};

3. Buffers

typedef u32 GPUBufferUsageFlags;

interface GPUBufferUsage {
    const u32 NONE         = 0x0000;
    const u32 MAP_READ     = 0x0001;
    const u32 MAP_WRITE    = 0x0002;
    const u32 TRANSFER_SRC = 0x0004;
    const u32 TRANSFER_DST = 0x0008;
    const u32 INDEX        = 0x0010;
    const u32 VERTEX       = 0x0020;
    const u32 UNIFORM      = 0x0040;
    const u32 STORAGE      = 0x0080;
};

dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
    required u64 size;
    required GPUBufferUsageFlags usage;
};

interface GPUBuffer : GPUObjectBase {
    Promise<ArrayBuffer> mapReadAsync();
    Promise<ArrayBuffer> mapWriteAsync();
    void unmap();

    void destroy();
};

4. Textures

enum GPUTextureDimension {
    "1d",
    "2d",
    "3d"
};

// Texture formats
// The name of the format specifies the order of components, bits per component, and data type for
// the component.
//     r, g, b, a = red, green, blue, alpha
//     unorm = unsigned normalized
//     snorm = signed normalized
//     uint = unsigned int
//     sint = signed int
//     float = floating point
// If the format has the "-srgb" suffix, then sRGB gamma compression and decompression are
// applied during the reading and writing of color values in the pixel.
// Compressed texture formats are provided by extensions. Their naming should follow the
// convention here, with the texture name as a prefix. e.g. "etc2-rgba8unorm".

enum GPUTextureFormat {
    /* Normal 8 bit formats */
    "r8unorm",
    "r8unorm-srgb",
    "r8snorm",
    "r8uint",
    "r8sint",
    /* Normal 16 bit formats */
    "r16unorm",
    "r16snorm",
    "r16uint",
    "r16sint",
    "r16float",
    "rg8unorm",
    "rg8unorm-srgb",
    "rg8snorm",
    "rg8uint",
    "rg8sint",
    /* Packed 16 bit formats */
    "b5g6r5unorm",
    /* Normal 32 bit formats */
    "r32uint",
    "r32sint",
    "r32float",
    "rg16unorm",
    "rg16snorm",
    "rg16uint",
    "rg16sint",
    "rg16float",
    "rgba8unorm",
    "rgba8unorm-srgb",
    "rgba8snorm",
    "rgba8uint",
    "rgba8sint",
    "bgra8unorm",
    "bgra8unorm-srgb",
    /* Packed 32 bit formats */
    "rgb10a2unorm",
    "rg11b10float",
    /* Normal 64 bit formats */
    "rg32uint",
    "rg32sint",
    "rg32float",
    "rgba16unorm",
    "rgba16snorm",
    "rgba16uint",
    "rgba16sint",
    "rgba16float",
    /* Normal 128 bit formats */
    "rgba32uint",
    "rgba32sint",
    "rgba32float",
    /* Depth and Stencil formats */
    "depth32float",
    // depth24plus has a precision of 1 ULP <= 1/(2**24).
    // (This is unlike the 24-bit unsigned normalized format family typically
    // found in native APIs, which has a precision of 1 ULP = 1/(2**24-1).)
    "depth24plus",
    "depth24plus-stencil8"
};

typedef u32 GPUTextureUsageFlags;

interface GPUTextureUsage {
    const u32 NONE              = 0x00;
    const u32 TRANSFER_SRC      = 0x01;
    const u32 TRANSFER_DST      = 0x02;
    const u32 SAMPLED           = 0x04;
    const u32 STORAGE           = 0x08;
    const u32 OUTPUT_ATTACHMENT = 0x10;
};

dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
    required GPUExtent3D size;
    u32 arrayLayerCount = 1;
    u32 mipLevelCount = 1;
    u32 sampleCount = 1;
    GPUTextureDimension dimension = "2d";
    required GPUTextureFormat format;
    required GPUTextureUsageFlags usage;
};

// Texture view
enum GPUTextureViewDimension {
    "1d",
    "2d",
    "2d-array",
    "cube",
    "cube-array",
    "3d"
};

enum GPUTextureAspect {
    "all",
    "stencil-only",
    "depth-only"
};

dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase {
    required GPUTextureFormat format;
    required GPUTextureViewDimension dimension;
    required GPUTextureAspect aspect;
    u32 baseMipLevel = 0;
    u32 mipLevelCount = 1;
    u32 baseArrayLayer = 0;
    u32 arrayLayerCount = 1;
};

interface GPUTextureView : GPUObjectBase {
};

interface GPUTexture : GPUObjectBase {
    GPUTextureView createView(GPUTextureViewDescriptor desc);
    GPUTextureView createDefaultView();

    void destroy();
};

5. Samplers

enum GPUAddressMode {
    "clamp-to-edge",
    "repeat",
    "mirror-repeat"
};

enum GPUFilterMode {
    "nearest",
    "linear"
};

enum GPUCompareFunction {
    "never",
    "less",
    "equal",
    "less-equal",
    "greater",
    "not-equal",
    "greater-equal",
    "always"
};

dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
    GPUAddressMode addressModeU = "clamp-to-edge";
    GPUAddressMode addressModeV = "clamp-to-edge";
    GPUAddressMode addressModeW = "clamp-to-edge";
    GPUFilterMode magFilter = "nearest";
    GPUFilterMode minFilter = "nearest";
    GPUFilterMode mipmapFilter = "nearest";
    float lodMinClamp = 0;
    float lodMaxClamp = 0xffffffff; // TODO: What should this be? Was Number.MAX_VALUE.
    GPUCompareFunction compare = "never";
};

interface GPUSampler : GPUObjectBase {
};

6. Binding and Layout

typedef u32 GPUShaderStageFlags;

interface GPUShaderStageBit {
    const u32 NONE     = 0x0;
    const u32 VERTEX   = 0x1;
    const u32 FRAGMENT = 0x2;
    const u32 COMPUTE  = 0x4;
};

enum GPUBindingType {
    "uniform-buffer",
    "storage-buffer",
    "readonly-storage-buffer",
    "sampler",
    "sampled-texture",
    "storage-texture"
    // TODO other binding types
};

dictionary GPUBindGroupLayoutBinding {
    required u32 binding;
    required GPUShaderStageFlags visibility;
    required GPUBindingType type;
    // For uniform, storage and readonly storage buffer, means that the binding
    // has a dynamic offset. One offset must be passed to setBindGroup for each
    // dynamic binding in increasing order of `binding` number.
    boolean dynamic = false;
};

dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayoutBinding> bindings;
};

interface GPUBindGroupLayout : GPUObjectBase {
};

dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayout> bindGroupLayouts;
};

interface GPUPipelineLayout : GPUObjectBase {
};

dictionary GPUBufferBinding {
    required GPUBuffer buffer;
    u64 offset = 0;
    // If size is undefined, use the whole size of the buffer.
    u64 size;
};

typedef (GPUSampler or GPUTextureView or GPUBufferBinding) GPUBindingResource;

dictionary GPUBindGroupBinding {
    required u32 binding;
    required GPUBindingResource resource;
};

dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
    required GPUBindGroupLayout layout;
    required sequence<GPUBindGroupBinding> bindings;
};

interface GPUBindGroup : GPUObjectBase {
};

7. Shader Module

// Note: While the choice of shader language is undecided,
// GPUShaderModuleDescriptor will temporarily accept both
// text and binary input.
typedef (Uint32Array or DOMString) GPUShaderCode;

dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
    required GPUShaderCode code;
};

interface GPUShaderModule : GPUObjectBase {
};

8. Pipeline Creation

// RasterizationState
enum GPUFrontFace {
    "ccw",
    "cw"
};

enum GPUCullMode {
    "none",
    "front",
    "back"
};

dictionary GPURasterizationStateDescriptor {
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";

    i32 depthBias = 0;
    float depthBiasSlopeScale = 0;
    float depthBiasClamp = 0;
};

// BlendState
enum GPUBlendFactor {
    "zero",
    "one",
    "src-color",
    "one-minus-src-color",
    "src-alpha",
    "one-minus-src-alpha",
    "dst-color",
    "one-minus-dst-color",
    "dst-alpha",
    "one-minus-dst-alpha",
    "src-alpha-saturated",
    "blend-color",
    "one-minus-blend-color"
};

enum GPUBlendOperation {
    "add",
    "subtract",
    "reverse-subtract",
    "min",
    "max"
};

typedef u32 GPUColorWriteFlags;
interface GPUColorWriteBits {
    const u32 NONE  = 0x0;
    const u32 RED   = 0x1;
    const u32 GREEN = 0x2;
    const u32 BLUE  = 0x4;
    const u32 ALPHA = 0x8;
    const u32 ALL   = 0xF;
};

dictionary GPUBlendDescriptor {
    GPUBlendFactor srcFactor = "one";
    GPUBlendFactor dstFactor = "zero";
    GPUBlendOperation operation = "add";
};

dictionary GPUColorStateDescriptor {
    required GPUTextureFormat format;

    required GPUBlendDescriptor alphaBlend;
    required GPUBlendDescriptor colorBlend;
    GPUColorWriteFlags writeMask = 0xF;  // GPUColorWriteBits.ALL
};

enum GPUStencilOperation {
    "keep",
    "zero",
    "replace",
    "invert",
    "increment-clamp",
    "decrement-clamp",
    "increment-wrap",
    "decrement-wrap"
};

dictionary GPUStencilStateFaceDescriptor {
    GPUCompareFunction compare = "always";
    GPUStencilOperation failOp = "keep";
    GPUStencilOperation depthFailOp = "keep";
    GPUStencilOperation passOp = "keep";
};

dictionary GPUDepthStencilStateDescriptor {
    required GPUTextureFormat format;

    boolean depthWriteEnabled = false;
    GPUCompareFunction depthCompare = "always";

    required GPUStencilStateFaceDescriptor stencilFront;
    required GPUStencilStateFaceDescriptor stencilBack;

    u32 stencilReadMask = 0xFFFFFFFF;
    u32 stencilWriteMask = 0xFFFFFFFF;
};

// Vertex Input

enum GPUIndexFormat {
    "uint16",
    "uint32"
};

// Vertex formats
// The name of the format specifies the data type of the component, the number of
// values, and whether the data is normalized.
//     uchar = unsigned 8-bit value
//     char = signed 8-bit value
//     ushort = unsigned 16-bit value
//     short = signed 16-bit value
//     half = half-precision 16-bit floating point value
//     float = 32-bit floating point value
//     uint = unsigned 32-bit integer value
//     int = signed 32-bit integer value
// If no number of values is given in the name, a single value is provided.
// If the format has the "-bgra" suffix, it means the values are arranged as
// blue, green, red and alpha values.

enum GPUVertexFormat {
    "uchar2",
    "uchar4",
    "char2",
    "char4",
    "uchar2norm",
    "uchar4norm",
    "char2norm",
    "char4norm",
    "ushort2",
    "ushort4",
    "short2",
    "short4",
    "ushort2norm",
    "ushort4norm",
    "short2norm",
    "short4norm",
    "half2",
    "half4",
    "float",
    "float2",
    "float3",
    "float4",
    "uint",
    "uint2",
    "uint3",
    "uint4",
    "int",
    "int2",
    "int3",
    "int4"
};

enum GPUInputStepMode {
    "vertex",
    "instance"
};

dictionary GPUVertexAttributeDescriptor {
    u64 offset = 0;
    required GPUVertexFormat format;
    required u32 shaderLocation;
};

dictionary GPUVertexBufferDescriptor {
    required u64 stride;
    GPUInputStepMode stepMode = "vertex";
    required sequence<GPUVertexAttributeDescriptor> attributeSet;
};

dictionary GPUVertexInputDescriptor {
    GPUIndexFormat indexFormat = "uint32";
    required sequence<GPUVertexBufferDescriptor?> vertexBuffers;
};

9. Pipeline Descriptors

dictionary GPUPipelineStageDescriptor {
    required GPUShaderModule module;
    required DOMString entryPoint;
    // TODO other stuff like specialization constants?
};

dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
    required GPUPipelineLayout layout;
};

10. Compute Pipeline

dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUPipelineStageDescriptor computeStage;
};

interface GPUComputePipeline : GPUObjectBase {
};

11. Render Pipeline

enum GPUPrimitiveTopology {
    "point-list",
    "line-list",
    "line-strip",
    "triangle-list",
    "triangle-strip"
};

dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUPipelineStageDescriptor vertexStage;
    GPUPipelineStageDescriptor? fragmentStage = null;

    required GPUPrimitiveTopology primitiveTopology;
    required GPURasterizationStateDescriptor rasterizationState;
    required sequence<GPUColorStateDescriptor> colorStates;
    GPUDepthStencilStateDescriptor? depthStencilState = null;
    required GPUVertexInputDescriptor vertexInput;

    // Number of MSAA samples
    u32 sampleCount = 1;
    u32 sampleMask = 0xFFFFFFFF;
    boolean alphaToCoverageEnabled = false;
    // TODO other properties
};

interface GPURenderPipeline : GPUObjectBase {
};

12. Command Recording

interface GPUProgrammablePassEncoder : GPUObjectBase {
    void endPass();

    // Allowed in both compute and render passes
    void setBindGroup(u32 index, GPUBindGroup bindGroup, optional sequence<u64> dynamicOffsets);

    // Debugging assistance
    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);
};

interface GPURenderPassEncoder : GPUProgrammablePassEncoder {
    void setPipeline(GPURenderPipeline pipeline);
    void setBlendColor(GPUColor color);
    void setStencilReference(u32 reference);

    // The default viewport is (0.0, 0.0, w, h, 0.0, 1.0), where w and h are the dimensions of back buffer
    void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);

    // The default scissor rectangle is (0, 0, w, h), where w and h are the dimensions of back buffer.
    // Width and height must be greater than 0. Otherwise, an error will be generated.
    void setScissorRect(u32 x, u32 y, u32 width, u32 height);

    void setIndexBuffer(GPUBuffer buffer, u64 offset);
    void setVertexBuffers(u32 startSlot, sequence<GPUBuffer> buffers, sequence<u64> offsets);

    void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
    void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);

    // TODO add missing commands
};

interface GPUComputePassEncoder : GPUProgrammablePassEncoder {
    void setPipeline(GPUComputePipeline pipeline);
    void dispatch(u32 x, optional u32 y = 1, optional u32 z = 1);

    // TODO add missing commands
};


enum GPULoadOp {
    "clear",
    "load"
};

enum GPUStoreOp {
    "store"
};

dictionary GPURenderPassColorAttachmentDescriptor {
    required GPUTextureView attachment;
    GPUTextureView? resolveTarget = null;

    required GPULoadOp loadOp;
    required GPUStoreOp storeOp;
    GPUColor clearColor;  // defaults to {r: 0.0, g: 0.0, b: 0.0, a: 1.0}
};

dictionary GPURenderPassDepthStencilAttachmentDescriptor {
    required GPUTextureView attachment;

    required GPULoadOp depthLoadOp;
    required GPUStoreOp depthStoreOp;
    required float clearDepth;

    required GPULoadOp stencilLoadOp;
    required GPUStoreOp stencilStoreOp;
    u32 clearStencil = 0;
};

dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
    required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
    GPURenderPassDepthStencilAttachmentDescriptor? depthStencilAttachment = null;
};

dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
};

dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
};

dictionary GPUBufferCopyView {
    required GPUBuffer buffer;
    u64 offset = 0;
    required u32 rowPitch;
    required u32 imageHeight;
};

dictionary GPUTextureCopyView {
    required GPUTexture texture;
    u32 mipLevel = 0;
    u32 arrayLayer = 0;
    GPUOrigin3D origin;  // defaults to {x: 0, y: 0, z: 0}
};

dictionary ImageBitmapCopyView {
    ImageBitmap imageBitmap;
    GPUOrigin2D origin;
};

interface GPUCommandBuffer : GPUObjectBase {
};

interface GPUCommandEncoder : GPUObjectBase {
    GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
    GPUComputePassEncoder beginComputePass(GPUComputePassEncoder? descriptor);

    // Commands allowed outside of "passes"
    void copyBufferToBuffer(
        GPUBuffer src,
        u64 srcOffset,
        GPUBuffer dst,
        u64 dstOffset,
        u64 size);

    void copyBufferToTexture(
        GPUBufferCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToBuffer(
        GPUTextureCopyView source,
        GPUBufferCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToTexture(
        GPUTextureCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyImageBitmapToTexture(
        ImageBitmapCopyView source,
        GPUTextureCopyView destination,
        // For now, copySize.z must be 1.
        GPUExtent3D copySize);

    // Debugging assistance
    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);

    GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor);
};

dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
    //TODO: reusability flag?
};

13. Fences

dictionary GPUFenceDescriptor : GPUObjectDescriptorBase {
    u64 initialValue = 0;
};

interface GPUFence : GPUObjectBase {
    u64 getCompletedValue();
    Promise<void> onCompletion(u64 completionValue);
};

14. Queues

interface GPUQueue : GPUObjectBase {
    void submit(sequence<GPUCommandBuffer> buffers);

    GPUFence createFence(optional GPUFenceDescriptor descriptor);
    void signal(GPUFence fence, u64 signalValue);
};

15. Canvas Rendering and Swap Chain

interface GPUCanvasContext {
    // Calling configureSwapChain a second time invalidates the previous one,
    // and all of the textures it’s produced.
    GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);

    Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
};

dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
    required GPUDevice device;
    required GPUTextureFormat format;
    GPUTextureUsageFlags usage = 0x10;  // GPUTextureUsage.OUTPUT_ATTACHMENT
};

interface GPUSwapChain : GPUObjectBase {
    GPUTexture getCurrentTexture();
};

16. Device

dictionary GPUExtensions {
    boolean anisotropicFiltering = false;
};

dictionary GPULimits {
    u32 maxBindGroups = 4;
};

// Device
[Exposed=(Window, Worker)]
interface GPUDevice : EventTarget {
    readonly attribute GPUExtensions extensions;
    readonly attribute GPULimits limits;
    readonly attribute GPUAdapter adapter;

    GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
    GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
    Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
    GPUTexture createTexture(GPUTextureDescriptor descriptor);
    GPUSampler createSampler(optional GPUSamplerDescriptor descriptor);

    GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
    GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
    GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);

    GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
    GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
    GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);

    GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor);

    GPUQueue getQueue();
};

GPUDevice includes GPUObjectBase;

dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
    GPUExtensions extensions;
    GPULimits limits;

    // TODO are other things configurable like queues?
};

interface GPUAdapter : GPUObjectBase {
    readonly attribute DOMString name;
    readonly attribute GPUExtensions extensions;
    //readonly attribute GPULimits limits; Don’t expose higher limits for now.

    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor);
};

enum GPUPowerPreference {
    "low-power",
    "high-performance"
};

dictionary GPURequestAdapterOptions {
    GPUPowerPreference? powerPreference;
};

[Exposed=Window]
interface GPU {
    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options);
};

[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute GPU gpu;
};

[Exposed=DedicatedWorker]
partial interface WorkerNavigator {
    [SameObject] readonly attribute GPU gpu;
};

17. Fatal Errors

interface GPUDeviceLostInfo {
    readonly attribute DOMString message;
};

partial interface GPUDevice {
    readonly attribute Promise<GPUDeviceLostInfo> lost;
};

18. Error Scopes

enum GPUErrorFilter {
    "none",
    "out-of-memory",
    "validation"
};

[
    Constructor()
]
interface GPUOutOfMemoryError {};

[
    Constructor(DOMString message)
]
interface GPUValidationError {
    readonly attribute DOMString message;
};

typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;

partial interface GPUDevice {
    void pushErrorScope(GPUErrorFilter filter);
    Promise<GPUError?> popErrorScope();
};

19. Telemetry

[
    Constructor(DOMString type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict),
    Exposed=Window
]
interface GPUUncapturedErrorEvent : Event {
    readonly attribute GPUError error;
};

dictionary GPUUncapturedErrorEventInit : EventInit {
    required GPUError error;
};

partial interface GPUDevice {
    [Exposed=Window]
    attribute EventHandler onuncapturederror;
};

Conformance

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.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

IDL Index

typedef long i32;
typedef unsigned long u32;
typedef unsigned long long u64;

dictionary GPUColorDict {
    required float r;
    required float g;
    required float b;
    required float a;
};
typedef (sequence<float> or GPUColorDict) GPUColor;

dictionary GPUOrigin2DDict {
    u32 x = 0;
    u32 y = 0;
};
typedef (sequence<u32> or GPUOrigin2DDict) GPUOrigin2D;

dictionary GPUOrigin3DDict {
    u32 x = 0;
    u32 y = 0;
    u32 z = 0;
};
typedef (sequence<u32> or GPUOrigin3DDict) GPUOrigin3D;

dictionary GPUExtent3DDict {
    required u32 width;
    required u32 height;
    required u32 depth;
};
typedef (sequence<u32> or GPUExtent3DDict) GPUExtent3D;

typedef sequence<any> GPUMappedBuffer;  // [GPUBuffer, ArrayBuffer]

interface mixin GPUObjectBase {
    attribute DOMString? label;
};

dictionary GPUObjectDescriptorBase {
    DOMString? label;
};

typedef u32 GPUBufferUsageFlags;

interface GPUBufferUsage {
    const u32 NONE         = 0x0000;
    const u32 MAP_READ     = 0x0001;
    const u32 MAP_WRITE    = 0x0002;
    const u32 TRANSFER_SRC = 0x0004;
    const u32 TRANSFER_DST = 0x0008;
    const u32 INDEX        = 0x0010;
    const u32 VERTEX       = 0x0020;
    const u32 UNIFORM      = 0x0040;
    const u32 STORAGE      = 0x0080;
};

dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
    required u64 size;
    required GPUBufferUsageFlags usage;
};

interface GPUBuffer : GPUObjectBase {
    Promise<ArrayBuffer> mapReadAsync();
    Promise<ArrayBuffer> mapWriteAsync();
    void unmap();

    void destroy();
};

enum GPUTextureDimension {
    "1d",
    "2d",
    "3d"
};

// Texture formats
// The name of the format specifies the order of components, bits per component, and data type for
// the component.
//     r, g, b, a = red, green, blue, alpha
//     unorm = unsigned normalized
//     snorm = signed normalized
//     uint = unsigned int
//     sint = signed int
//     float = floating point
// If the format has the "-srgb" suffix, then sRGB gamma compression and decompression are
// applied during the reading and writing of color values in the pixel.
// Compressed texture formats are provided by extensions. Their naming should follow the
// convention here, with the texture name as a prefix. e.g. "etc2-rgba8unorm".

enum GPUTextureFormat {
    /* Normal 8 bit formats */
    "r8unorm",
    "r8unorm-srgb",
    "r8snorm",
    "r8uint",
    "r8sint",
    /* Normal 16 bit formats */
    "r16unorm",
    "r16snorm",
    "r16uint",
    "r16sint",
    "r16float",
    "rg8unorm",
    "rg8unorm-srgb",
    "rg8snorm",
    "rg8uint",
    "rg8sint",
    /* Packed 16 bit formats */
    "b5g6r5unorm",
    /* Normal 32 bit formats */
    "r32uint",
    "r32sint",
    "r32float",
    "rg16unorm",
    "rg16snorm",
    "rg16uint",
    "rg16sint",
    "rg16float",
    "rgba8unorm",
    "rgba8unorm-srgb",
    "rgba8snorm",
    "rgba8uint",
    "rgba8sint",
    "bgra8unorm",
    "bgra8unorm-srgb",
    /* Packed 32 bit formats */
    "rgb10a2unorm",
    "rg11b10float",
    /* Normal 64 bit formats */
    "rg32uint",
    "rg32sint",
    "rg32float",
    "rgba16unorm",
    "rgba16snorm",
    "rgba16uint",
    "rgba16sint",
    "rgba16float",
    /* Normal 128 bit formats */
    "rgba32uint",
    "rgba32sint",
    "rgba32float",
    /* Depth and Stencil formats */
    "depth32float",
    // depth24plus has a precision of 1 ULP <= 1/(2**24).
    // (This is unlike the 24-bit unsigned normalized format family typically
    // found in native APIs, which has a precision of 1 ULP = 1/(2**24-1).)
    "depth24plus",
    "depth24plus-stencil8"
};

typedef u32 GPUTextureUsageFlags;

interface GPUTextureUsage {
    const u32 NONE              = 0x00;
    const u32 TRANSFER_SRC      = 0x01;
    const u32 TRANSFER_DST      = 0x02;
    const u32 SAMPLED           = 0x04;
    const u32 STORAGE           = 0x08;
    const u32 OUTPUT_ATTACHMENT = 0x10;
};

dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
    required GPUExtent3D size;
    u32 arrayLayerCount = 1;
    u32 mipLevelCount = 1;
    u32 sampleCount = 1;
    GPUTextureDimension dimension = "2d";
    required GPUTextureFormat format;
    required GPUTextureUsageFlags usage;
};

// Texture view
enum GPUTextureViewDimension {
    "1d",
    "2d",
    "2d-array",
    "cube",
    "cube-array",
    "3d"
};

enum GPUTextureAspect {
    "all",
    "stencil-only",
    "depth-only"
};

dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase {
    required GPUTextureFormat format;
    required GPUTextureViewDimension dimension;
    required GPUTextureAspect aspect;
    u32 baseMipLevel = 0;
    u32 mipLevelCount = 1;
    u32 baseArrayLayer = 0;
    u32 arrayLayerCount = 1;
};

interface GPUTextureView : GPUObjectBase {
};

interface GPUTexture : GPUObjectBase {
    GPUTextureView createView(GPUTextureViewDescriptor desc);
    GPUTextureView createDefaultView();

    void destroy();
};

enum GPUAddressMode {
    "clamp-to-edge",
    "repeat",
    "mirror-repeat"
};

enum GPUFilterMode {
    "nearest",
    "linear"
};

enum GPUCompareFunction {
    "never",
    "less",
    "equal",
    "less-equal",
    "greater",
    "not-equal",
    "greater-equal",
    "always"
};

dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
    GPUAddressMode addressModeU = "clamp-to-edge";
    GPUAddressMode addressModeV = "clamp-to-edge";
    GPUAddressMode addressModeW = "clamp-to-edge";
    GPUFilterMode magFilter = "nearest";
    GPUFilterMode minFilter = "nearest";
    GPUFilterMode mipmapFilter = "nearest";
    float lodMinClamp = 0;
    float lodMaxClamp = 0xffffffff; // TODO: What should this be? Was Number.MAX_VALUE.
    GPUCompareFunction compare = "never";
};

interface GPUSampler : GPUObjectBase {
};

typedef u32 GPUShaderStageFlags;

interface GPUShaderStageBit {
    const u32 NONE     = 0x0;
    const u32 VERTEX   = 0x1;
    const u32 FRAGMENT = 0x2;
    const u32 COMPUTE  = 0x4;
};

enum GPUBindingType {
    "uniform-buffer",
    "storage-buffer",
    "readonly-storage-buffer",
    "sampler",
    "sampled-texture",
    "storage-texture"
    // TODO other binding types
};

dictionary GPUBindGroupLayoutBinding {
    required u32 binding;
    required GPUShaderStageFlags visibility;
    required GPUBindingType type;
    // For uniform, storage and readonly storage buffer, means that the binding
    // has a dynamic offset. One offset must be passed to setBindGroup for each
    // dynamic binding in increasing order of `binding` number.
    boolean dynamic = false;
};

dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayoutBinding> bindings;
};

interface GPUBindGroupLayout : GPUObjectBase {
};

dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayout> bindGroupLayouts;
};

interface GPUPipelineLayout : GPUObjectBase {
};

dictionary GPUBufferBinding {
    required GPUBuffer buffer;
    u64 offset = 0;
    // If size is undefined, use the whole size of the buffer.
    u64 size;
};

typedef (GPUSampler or GPUTextureView or GPUBufferBinding) GPUBindingResource;

dictionary GPUBindGroupBinding {
    required u32 binding;
    required GPUBindingResource resource;
};

dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
    required GPUBindGroupLayout layout;
    required sequence<GPUBindGroupBinding> bindings;
};

interface GPUBindGroup : GPUObjectBase {
};

// Note: While the choice of shader language is undecided,
// GPUShaderModuleDescriptor will temporarily accept both
// text and binary input.
typedef (Uint32Array or DOMString) GPUShaderCode;

dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
    required GPUShaderCode code;
};

interface GPUShaderModule : GPUObjectBase {
};

// RasterizationState
enum GPUFrontFace {
    "ccw",
    "cw"
};

enum GPUCullMode {
    "none",
    "front",
    "back"
};

dictionary GPURasterizationStateDescriptor {
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";

    i32 depthBias = 0;
    float depthBiasSlopeScale = 0;
    float depthBiasClamp = 0;
};

// BlendState
enum GPUBlendFactor {
    "zero",
    "one",
    "src-color",
    "one-minus-src-color",
    "src-alpha",
    "one-minus-src-alpha",
    "dst-color",
    "one-minus-dst-color",
    "dst-alpha",
    "one-minus-dst-alpha",
    "src-alpha-saturated",
    "blend-color",
    "one-minus-blend-color"
};

enum GPUBlendOperation {
    "add",
    "subtract",
    "reverse-subtract",
    "min",
    "max"
};

typedef u32 GPUColorWriteFlags;
interface GPUColorWriteBits {
    const u32 NONE  = 0x0;
    const u32 RED   = 0x1;
    const u32 GREEN = 0x2;
    const u32 BLUE  = 0x4;
    const u32 ALPHA = 0x8;
    const u32 ALL   = 0xF;
};

dictionary GPUBlendDescriptor {
    GPUBlendFactor srcFactor = "one";
    GPUBlendFactor dstFactor = "zero";
    GPUBlendOperation operation = "add";
};

dictionary GPUColorStateDescriptor {
    required GPUTextureFormat format;

    required GPUBlendDescriptor alphaBlend;
    required GPUBlendDescriptor colorBlend;
    GPUColorWriteFlags writeMask = 0xF;  // GPUColorWriteBits.ALL
};

enum GPUStencilOperation {
    "keep",
    "zero",
    "replace",
    "invert",
    "increment-clamp",
    "decrement-clamp",
    "increment-wrap",
    "decrement-wrap"
};

dictionary GPUStencilStateFaceDescriptor {
    GPUCompareFunction compare = "always";
    GPUStencilOperation failOp = "keep";
    GPUStencilOperation depthFailOp = "keep";
    GPUStencilOperation passOp = "keep";
};

dictionary GPUDepthStencilStateDescriptor {
    required GPUTextureFormat format;

    boolean depthWriteEnabled = false;
    GPUCompareFunction depthCompare = "always";

    required GPUStencilStateFaceDescriptor stencilFront;
    required GPUStencilStateFaceDescriptor stencilBack;

    u32 stencilReadMask = 0xFFFFFFFF;
    u32 stencilWriteMask = 0xFFFFFFFF;
};

// Vertex Input

enum GPUIndexFormat {
    "uint16",
    "uint32"
};

// Vertex formats
// The name of the format specifies the data type of the component, the number of
// values, and whether the data is normalized.
//     uchar = unsigned 8-bit value
//     char = signed 8-bit value
//     ushort = unsigned 16-bit value
//     short = signed 16-bit value
//     half = half-precision 16-bit floating point value
//     float = 32-bit floating point value
//     uint = unsigned 32-bit integer value
//     int = signed 32-bit integer value
// If no number of values is given in the name, a single value is provided.
// If the format has the "-bgra" suffix, it means the values are arranged as
// blue, green, red and alpha values.

enum GPUVertexFormat {
    "uchar2",
    "uchar4",
    "char2",
    "char4",
    "uchar2norm",
    "uchar4norm",
    "char2norm",
    "char4norm",
    "ushort2",
    "ushort4",
    "short2",
    "short4",
    "ushort2norm",
    "ushort4norm",
    "short2norm",
    "short4norm",
    "half2",
    "half4",
    "float",
    "float2",
    "float3",
    "float4",
    "uint",
    "uint2",
    "uint3",
    "uint4",
    "int",
    "int2",
    "int3",
    "int4"
};

enum GPUInputStepMode {
    "vertex",
    "instance"
};

dictionary GPUVertexAttributeDescriptor {
    u64 offset = 0;
    required GPUVertexFormat format;
    required u32 shaderLocation;
};

dictionary GPUVertexBufferDescriptor {
    required u64 stride;
    GPUInputStepMode stepMode = "vertex";
    required sequence<GPUVertexAttributeDescriptor> attributeSet;
};

dictionary GPUVertexInputDescriptor {
    GPUIndexFormat indexFormat = "uint32";
    required sequence<GPUVertexBufferDescriptor?> vertexBuffers;
};

dictionary GPUPipelineStageDescriptor {
    required GPUShaderModule module;
    required DOMString entryPoint;
    // TODO other stuff like specialization constants?
};

dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
    required GPUPipelineLayout layout;
};

dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUPipelineStageDescriptor computeStage;
};

interface GPUComputePipeline : GPUObjectBase {
};

enum GPUPrimitiveTopology {
    "point-list",
    "line-list",
    "line-strip",
    "triangle-list",
    "triangle-strip"
};

dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUPipelineStageDescriptor vertexStage;
    GPUPipelineStageDescriptor? fragmentStage = null;

    required GPUPrimitiveTopology primitiveTopology;
    required GPURasterizationStateDescriptor rasterizationState;
    required sequence<GPUColorStateDescriptor> colorStates;
    GPUDepthStencilStateDescriptor? depthStencilState = null;
    required GPUVertexInputDescriptor vertexInput;

    // Number of MSAA samples
    u32 sampleCount = 1;
    u32 sampleMask = 0xFFFFFFFF;
    boolean alphaToCoverageEnabled = false;
    // TODO other properties
};

interface GPURenderPipeline : GPUObjectBase {
};

interface GPUProgrammablePassEncoder : GPUObjectBase {
    void endPass();

    // Allowed in both compute and render passes
    void setBindGroup(u32 index, GPUBindGroup bindGroup, optional sequence<u64> dynamicOffsets);

    // Debugging assistance
    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);
};

interface GPURenderPassEncoder : GPUProgrammablePassEncoder {
    void setPipeline(GPURenderPipeline pipeline);
    void setBlendColor(GPUColor color);
    void setStencilReference(u32 reference);

    // The default viewport is (0.0, 0.0, w, h, 0.0, 1.0), where w and h are the dimensions of back buffer
    void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);

    // The default scissor rectangle is (0, 0, w, h), where w and h are the dimensions of back buffer.
    // Width and height must be greater than 0. Otherwise, an error will be generated.
    void setScissorRect(u32 x, u32 y, u32 width, u32 height);

    void setIndexBuffer(GPUBuffer buffer, u64 offset);
    void setVertexBuffers(u32 startSlot, sequence<GPUBuffer> buffers, sequence<u64> offsets);

    void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
    void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);

    // TODO add missing commands
};

interface GPUComputePassEncoder : GPUProgrammablePassEncoder {
    void setPipeline(GPUComputePipeline pipeline);
    void dispatch(u32 x, optional u32 y = 1, optional u32 z = 1);

    // TODO add missing commands
};


enum GPULoadOp {
    "clear",
    "load"
};

enum GPUStoreOp {
    "store"
};

dictionary GPURenderPassColorAttachmentDescriptor {
    required GPUTextureView attachment;
    GPUTextureView? resolveTarget = null;

    required GPULoadOp loadOp;
    required GPUStoreOp storeOp;
    GPUColor clearColor;  // defaults to {r: 0.0, g: 0.0, b: 0.0, a: 1.0}
};

dictionary GPURenderPassDepthStencilAttachmentDescriptor {
    required GPUTextureView attachment;

    required GPULoadOp depthLoadOp;
    required GPUStoreOp depthStoreOp;
    required float clearDepth;

    required GPULoadOp stencilLoadOp;
    required GPUStoreOp stencilStoreOp;
    u32 clearStencil = 0;
};

dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
    required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
    GPURenderPassDepthStencilAttachmentDescriptor? depthStencilAttachment = null;
};

dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
};

dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
};

dictionary GPUBufferCopyView {
    required GPUBuffer buffer;
    u64 offset = 0;
    required u32 rowPitch;
    required u32 imageHeight;
};

dictionary GPUTextureCopyView {
    required GPUTexture texture;
    u32 mipLevel = 0;
    u32 arrayLayer = 0;
    GPUOrigin3D origin;  // defaults to {x: 0, y: 0, z: 0}
};

dictionary ImageBitmapCopyView {
    ImageBitmap imageBitmap;
    GPUOrigin2D origin;
};

interface GPUCommandBuffer : GPUObjectBase {
};

interface GPUCommandEncoder : GPUObjectBase {
    GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
    GPUComputePassEncoder beginComputePass(GPUComputePassEncoder? descriptor);

    // Commands allowed outside of "passes"
    void copyBufferToBuffer(
        GPUBuffer src,
        u64 srcOffset,
        GPUBuffer dst,
        u64 dstOffset,
        u64 size);

    void copyBufferToTexture(
        GPUBufferCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToBuffer(
        GPUTextureCopyView source,
        GPUBufferCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToTexture(
        GPUTextureCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyImageBitmapToTexture(
        ImageBitmapCopyView source,
        GPUTextureCopyView destination,
        // For now, copySize.z must be 1.
        GPUExtent3D copySize);

    // Debugging assistance
    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);

    GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor);
};

dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
    //TODO: reusability flag?
};

dictionary GPUFenceDescriptor : GPUObjectDescriptorBase {
    u64 initialValue = 0;
};

interface GPUFence : GPUObjectBase {
    u64 getCompletedValue();
    Promise<void> onCompletion(u64 completionValue);
};

interface GPUQueue : GPUObjectBase {
    void submit(sequence<GPUCommandBuffer> buffers);

    GPUFence createFence(optional GPUFenceDescriptor descriptor);
    void signal(GPUFence fence, u64 signalValue);
};

interface GPUCanvasContext {
    // Calling configureSwapChain a second time invalidates the previous one,
    // and all of the textures it’s produced.
    GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);

    Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
};

dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
    required GPUDevice device;
    required GPUTextureFormat format;
    GPUTextureUsageFlags usage = 0x10;  // GPUTextureUsage.OUTPUT_ATTACHMENT
};

interface GPUSwapChain : GPUObjectBase {
    GPUTexture getCurrentTexture();
};

dictionary GPUExtensions {
    boolean anisotropicFiltering = false;
};

dictionary GPULimits {
    u32 maxBindGroups = 4;
};

// Device
[Exposed=(Window, Worker)]
interface GPUDevice : EventTarget {
    readonly attribute GPUExtensions extensions;
    readonly attribute GPULimits limits;
    readonly attribute GPUAdapter adapter;

    GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
    GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
    Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
    GPUTexture createTexture(GPUTextureDescriptor descriptor);
    GPUSampler createSampler(optional GPUSamplerDescriptor descriptor);

    GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
    GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
    GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);

    GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
    GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
    GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);

    GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor);

    GPUQueue getQueue();
};

GPUDevice includes GPUObjectBase;

dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
    GPUExtensions extensions;
    GPULimits limits;

    // TODO are other things configurable like queues?
};

interface GPUAdapter : GPUObjectBase {
    readonly attribute DOMString name;
    readonly attribute GPUExtensions extensions;
    //readonly attribute GPULimits limits; Don’t expose higher limits for now.

    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor);
};

enum GPUPowerPreference {
    "low-power",
    "high-performance"
};

dictionary GPURequestAdapterOptions {
    GPUPowerPreference? powerPreference;
};

[Exposed=Window]
interface GPU {
    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options);
};

[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute GPU gpu;
};

[Exposed=DedicatedWorker]
partial interface WorkerNavigator {
    [SameObject] readonly attribute GPU gpu;
};

interface GPUDeviceLostInfo {
    readonly attribute DOMString message;
};

partial interface GPUDevice {
    readonly attribute Promise<GPUDeviceLostInfo> lost;
};

enum GPUErrorFilter {
    "none",
    "out-of-memory",
    "validation"
};

[
    Constructor()
]
interface GPUOutOfMemoryError {};

[
    Constructor(DOMString message)
]
interface GPUValidationError {
    readonly attribute DOMString message;
};

typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;

partial interface GPUDevice {
    void pushErrorScope(GPUErrorFilter filter);
    Promise<GPUError?> popErrorScope();
};

[
    Constructor(DOMString type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict),
    Exposed=Window
]
interface GPUUncapturedErrorEvent : Event {
    readonly attribute GPUError error;
};

dictionary GPUUncapturedErrorEventInit : EventInit {
    required GPUError error;
};

partial interface GPUDevice {
    [Exposed=Window]
    attribute EventHandler onuncapturederror;
};