Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9aefc38
Specify immediate data API in the WebGPU spec
shaoboyan091 Oct 29, 2025
5f99456
Update spec/index.bs
shaoboyan091 Oct 29, 2025
bffe39d
Update spec/index.bs
shaoboyan091 Oct 29, 2025
ad13b13
Specify <immediate> address space
shaoboyan091 Oct 29, 2025
895beb8
Update wgsl/index.bs
shaoboyan091 Oct 31, 2025
21ba7fa
Update wgsl/index.bs
shaoboyan091 Oct 31, 2025
b045b81
Address comments
shaoboyan091 Nov 10, 2025
f2653d8
Address comments
shaoboyan091 Dec 1, 2025
d33528e
Address comments
shaoboyan091 Dec 1, 2025
b8243f4
Apply suggestions from code review
shaoboyan091 Dec 1, 2025
5ab1e43
Update wgsl/index.bs
shaoboyan091 Dec 1, 2025
08c755a
WGSL: don't describe immediate data as part of the resource interface
dneto0 Dec 10, 2025
e68f1c1
Simplify description of max immediate variable size
dneto0 Dec 10, 2025
3fa0d5c
Address comments
shaoboyan091 Mar 20, 2026
b16cc9e
Address comments in spec/index.bs.
shaoboyan091 Mar 23, 2026
8c2b204
Update spec/index.bs
shaoboyan091 Mar 25, 2026
5cce2cd
Merge branch 'main' into gpu-spec
shaoboyan091 Mar 31, 2026
589c87b
Apply suggestions from code review
shaoboyan091 Apr 8, 2026
87585b1
Address comments
shaoboyan091 Apr 8, 2026
fbde276
Move maxImmediateSize alignment requirement to adapter-capability-gu…
shaoboyan091 Apr 8, 2026
e77030a
Merge branch 'main' into gpu-spec
shaoboyan091 May 7, 2026
7cc2469
Address review comments on immediate data validation
shaoboyan091 May 7, 2026
f2fc3f3
editorial: Validate immediate data
kainino0x May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 155 additions & 6 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ spec: WGSL; urlPrefix: https://gpuweb.github.io/gpuweb/wgsl/#
text: subgroup size; url: subgroup-size
type: abstract-op
text: SizeOf; url: sizeof
text: AccessibleSlots; url: accessible-slots
spec: Internationalization Glossary; urlPrefix: https://www.w3.org/TR/i18n-glossary/#
type: dfn
text: localizable text; url: dfn-localizable-text
Expand Down Expand Up @@ -1625,6 +1626,13 @@ A <dfn dfn>supported limits</dfn> object has a value for every limit defined by
counting any empty slots below the highest index.
Validated in {{GPUDevice/createRenderPipeline()}} and [$valid to draw|in draw calls$].

<tr><td><dfn>maxImmediateSize</dfn>
<td>{{GPUSize32}} <td>[=limit class/maximum=] <td colspan=2>64
<tr class=row-continuation><td colspan=5>
The maximum size, in bytes, of immediate data range used in a pipeline.

Note: 64 bytes is the size of a 4×4 matrix of f32 values.

<tr><td><dfn>maxBindingsPerBindGroup</dfn>
<td>{{GPUSize32}} <td>[=limit class/maximum=] <td colspan=2>1000
<tr class=row-continuation><td colspan=5>
Expand Down Expand Up @@ -1859,6 +1867,7 @@ interface GPUSupportedLimits {
readonly attribute unsigned long maxTextureArrayLayers;
readonly attribute unsigned long maxBindGroups;
readonly attribute unsigned long maxBindGroupsPlusVertexBuffers;
readonly attribute unsigned long maxImmediateSize;
Comment thread
kainino0x marked this conversation as resolved.
readonly attribute unsigned long maxBindingsPerBindGroup;
readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout;
readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout;
Expand Down Expand Up @@ -2596,6 +2605,7 @@ Any {{GPUAdapter}} returned by {{GPU/requestAdapter()}} must provide the followi
- {{supported limits/maxComputeWorkgroupSizeZ}} must be &le; {{supported limits/maxComputeInvocationsPerWorkgroup}}.
- {{supported limits/maxComputeInvocationsPerWorkgroup}} must be &le; {{supported limits/maxComputeWorkgroupSizeX}}
&times; {{supported limits/maxComputeWorkgroupSizeY}} &times; {{supported limits/maxComputeWorkgroupSizeZ}}.
- {{supported limits/maxImmediateSize}} must be a multiple of 4 bytes.

### Adapter Selection ### {#adapter-selection}

Expand Down Expand Up @@ -6950,6 +6960,11 @@ GPUPipelineLayout includes GPUObjectBase;
: <dfn>\[[bindGroupLayouts]]</dfn>, of type [=list=]&lt;{{GPUBindGroupLayout}}&gt;, readonly
::
The {{GPUBindGroupLayout}} objects provided at creation in {{GPUPipelineLayoutDescriptor/bindGroupLayouts|GPUPipelineLayoutDescriptor.bindGroupLayouts}}.

: <dfn>\[[immediateSize]]</dfn>, of type {{GPUSize32}}, readonly
::
The size in bytes of the immediate data range, provided at creation in {{GPUPipelineLayoutDescriptor/immediateSize|GPUPipelineLayoutDescriptor.immediateSize}}
(or by the [$default pipeline layout$]).
</dl>

Note: using the same {{GPUPipelineLayout}} for many {{GPURenderPipeline}} or {{GPUComputePipeline}} pipelines guarantees that the user agent doesn't need to rebind any resources internally when there is a switch between these pipelines.
Expand Down Expand Up @@ -6979,6 +6994,7 @@ A {{GPUPipelineLayout}} is created via {{GPUDevice/createPipelineLayout()|GPUDev
dictionary GPUPipelineLayoutDescriptor
: GPUObjectDescriptorBase {
required sequence<GPUBindGroupLayout?> bindGroupLayouts;
GPUSize32 immediateSize = 0;
};
</script>

Expand All @@ -6991,6 +7007,10 @@ pipeline, and have the following members:
A list of optional {{GPUBindGroupLayout}}s the pipeline will use. Each element corresponds
to a [=@group=] attribute in the {{GPUShaderModule}}, with the `N`th element corresponding
with `@group(N)`.

: <dfn>immediateSize</dfn>
::
The size, in bytes, of the immediate data range used by the pipeline.
</dl>

<dl dfn-type=method dfn-for=GPUDevice>
Expand Down Expand Up @@ -7040,16 +7060,21 @@ pipeline, and have the following members:
- The [=list/size=] of |descriptor|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
must be &le; |limits|.{{supported limits/maxBindGroups}}.
- |allEntries| must not [=exceeds the binding slot limits|exceed the binding slot limits=] of |limits|.
- |descriptor|.{{GPUPipelineLayoutDescriptor/immediateSize}} must be &le;
|limits|.{{supported limits/maxImmediateSize}}.
- |descriptor|.{{GPUPipelineLayoutDescriptor/immediateSize}} must be a multiple of 4.
</div>

1. Set the |pl|.{{GPUPipelineLayout/[[bindGroupLayouts]]}} to |bindGroupLayouts|.
1. Set the |pl|.{{GPUPipelineLayout/[[immediateSize]]}} to |descriptor|.{{GPUPipelineLayoutDescriptor/immediateSize}}.
</div>
</div>
</dl>

Note: two {{GPUPipelineLayout}} objects are considered equivalent for any usage
if their internal {{GPUPipelineLayout/[[bindGroupLayouts]]}} sequences contain
{{GPUBindGroupLayout}} objects that are [=group-equivalent=].
{{GPUBindGroupLayout}} objects that are [=group-equivalent=] and their
{{GPUPipelineLayout/[[immediateSize]]}} values are equal.

## Example ## {#bindgroup-examples}

Expand Down Expand Up @@ -7692,6 +7717,7 @@ To create a <dfn abstract-op>default pipeline layout</dfn> for {{GPUPipelineBase
run the following [=device timeline=] steps:

1. Let |groupCount| be 0.
1. Let |immediateSize| be 0.
1. Let |groupDescs| be a sequence of |device|.{{device/[[limits]]}}.{{supported limits/maxBindGroups}}
new {{GPUBindGroupLayoutDescriptor}} objects.
1. For each |groupDesc| in |groupDescs|:
Expand Down Expand Up @@ -7824,6 +7850,11 @@ run the following [=device timeline=] steps:

1. Append |entry| to |groupDescs|[|group|].

1. If there is an immediate data variable that is [=statically used=] by |entryPoint|
([=assert=] there is at most one):
1. Let |T| be the [=store type=] of the immediate data variable.
1. Set |immediateSize| to max(|immediateSize|, [=roundUp=](4, [$SizeOf$](|T|))).

1. Let |groupLayouts| be a new [=list=].
1. For each |i| from 0 to |groupCount| - 1, inclusive:
1. Let |groupDesc| be |groupDescs|[|i|].
Expand All @@ -7833,6 +7864,7 @@ run the following [=device timeline=] steps:

1. Let |desc| be a new {{GPUPipelineLayoutDescriptor}}.
1. Set |desc|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}} to |groupLayouts|.
1. Set |desc|.{{GPUPipelineLayoutDescriptor/immediateSize}} to |immediateSize|.
1. Return |device|.{{GPUDevice/createPipelineLayout()}}(|desc|).
</div>

Expand Down Expand Up @@ -8014,6 +8046,11 @@ typedef double GPUPipelineConstantValue; // May represent WGSL's bool, f32, i32,
- If the pipeline-overridable constant identified by |key|
[=pipeline-overridable constant default value|does not have a default value=],
|descriptor|.{{GPUProgrammableStage/constants}} |must| [=map/contain=] |key|.
1. If there is an immediate data variable that is [=statically used=] by |entryPoint|
([=assert=] there is at most one):
- Let |T| be the [=store type=] of the immediate data variable.
- Let |requiredSize| be [$SizeOf$](|T|).
- |layout|.{{GPUPipelineLayout/[[immediateSize]]}} must be &ge; |requiredSize|.
1. [=pipeline-creation error|Pipeline-creation=] [=program errors=] |must| not
result from the rules of the [[WGSL]] specification.
1.
Expand Down Expand Up @@ -11263,6 +11300,9 @@ interface mixin GPUBindingCommandsMixin {
[AllowShared] Uint32Array dynamicOffsetsData,
GPUSize64 dynamicOffsetsDataStart,
GPUSize32 dynamicOffsetsDataLength);

undefined setImmediates(GPUSize32 rangeOffset, AllowSharedBufferSource data,
optional GPUSize64 dataOffset = 0, optional GPUSize64 dataSize);
};
</script>

Expand All @@ -11277,9 +11317,21 @@ It must only be included by interfaces which also include those mixins.
::
The current {{GPUBindGroup}} for each index.

: <dfn>\[[dynamic_offsets]]</dfn>, of type [=ordered map=]&lt;{{GPUIndex32}}, [=list=]&lt;{{GPUBufferDynamicOffset}}&gt;&gt;, initally empty
: <dfn>\[[dynamic_offsets]]</dfn>, of type [=ordered map=]&lt;{{GPUIndex32}}, [=list=]&lt;{{GPUBufferDynamicOffset}}&gt;&gt;, initially empty
::
The current dynamic offsets for each {{GPUBindingCommandsMixin/[[bind_groups]]}} entry.

: <dfn>\[[immediate_data]]</dfn>, of type [=byte sequence=]
::
The current immediate data bytes.
Initially a [=byte sequence=] of length equal to the device's {{supported limits/maxImmediateSize}}, with all bytes set to zero.
Values are set by {{GPUBindingCommandsMixin/setImmediates()}}.

: <dfn>\[[immediate_slots_set]]</dfn>, of type [=list=]&lt;{{boolean}}&gt;
::
Tracks which 32-bit word slots of immediate data have been set.
Initially a [=list=] of length equal to the device's {{supported limits/maxImmediateSize}} divided by 4, with all entries set to `false`.
Each entry corresponds to a 4-byte slot.
</dl>

## Bind Groups ## {#programmable-passes-bind-groups}
Expand Down Expand Up @@ -11484,7 +11536,6 @@ It must only be included by interfaces which also include those mixins.
</div>
</div>


<div algorithm data-timeline=device>
To <dfn abstract-op>Iterate over each dynamic binding offset</dfn> in a given {{GPUBindGroup}} |bindGroup|
with a given list of |steps| to be executed for each dynamic offset, run the following [=device timeline=] steps:
Expand Down Expand Up @@ -11573,6 +11624,32 @@ It must only be included by interfaces which also include those mixins.
Otherwise return `true`.
</div>

<div algorithm data-timeline=device>
<dfn abstract-op>Validate immediate data</dfn>(encoder, pipeline)
Comment thread
kainino0x marked this conversation as resolved.

**Arguments:**

: {{GPUBindingCommandsMixin}} |encoder|
:: Encoder whose immediate data is being validated.
: {{GPUPipelineBase}} |pipeline|
:: Pipeline to validate |encoder|'s immediate data is compatible with.

[=Device timeline=] steps:

1. If any of the following conditions are unsatisfied, return `false`:

<div class=validusage>
- |pipeline| must not be `null`.
- For each immediate data variable that is [=statically used=] by any entry point in |pipeline|:
- Let |T| be the [=store type=] of the immediate data variable.
- Let |accessibleSlots| be [$AccessibleSlots$](|T|) as defined in [[WGSL]].
- For each |slotIndex| in |accessibleSlots|:
- |encoder|.{{GPUBindingCommandsMixin/[[immediate_slots_set]]}}[|slotIndex|] must be `true`.
</div>

Otherwise return `true`.
</div>

<div algorithm data-timeline=device>
<dfn abstract-op>Encoder bind groups alias a writable resource</dfn>(|encoder|, |pipeline|)
if any writable buffer binding range overlaps with any other binding range of the same buffer,
Expand Down Expand Up @@ -11630,6 +11707,71 @@ It must only be included by interfaces which also include those mixins.
Implementations are strongly encouraged to optimize this algorithm.
</div>

## Immediate Data ## {#programmable-passes-immediate-data}

<dl dfn-type=method dfn-for=GPUBindingCommandsMixin>
: <dfn>setImmediates(rangeOffset, data, dataOffset, dataSize)</dfn>
::
Sets immediate data for subsequent render or compute commands.

<div algorithm=GPUBindingCommandsMixin.setImmediates>
<div data-timeline=content>
**Called on:** {{GPUBindingCommandsMixin}} |this|.

**Arguments:**

<pre class=argumentdef for="GPUBindingCommandsMixin/setImmediates(rangeOffset, data, dataOffset, dataSize)">
|rangeOffset|: Offset in bytes into the immediate data range to begin writing at.
|data|: Data to write into the immediate data range.
|dataOffset|: Offset into |data| to begin writing from. Given in elements if
|data| is a {{TypedArray}} and bytes otherwise.
|dataSize|: Size of content to write from |data|. Given in elements if
|data| is a {{TypedArray}} and bytes otherwise.
</pre>

**Returns:** {{undefined}}

[=Content timeline=] steps:

1. If |data| is an {{ArrayBuffer}} or {{DataView}}, let the element type be "byte".
Otherwise, |data| is a TypedArray; let the element type be the type of the TypedArray.
1. Let |dataElementCount| be the size of |data|, in elements.
1. If |dataSize| is missing,
let |contentsSize| be |dataElementCount| &minus; |dataOffset|.
Otherwise, let |contentsSize| be |dataSize|.
1. If any of the following conditions are unsatisfied,
throw an {{OperationError}} and return.

<div class=validusage>
- |contentsSize| &ge; 0.
- |dataOffset| + |contentsSize| &le; |dataElementCount|.
- |contentsSize|, converted to bytes, is a multiple of 4.
</div>
1. Let |dataContents| be [=get a copy of the buffer source|a copy of the bytes held by the buffer source=] |data|.
1. Let |contents| be the |contentsSize| elements of |dataContents| starting at
an offset of |dataOffset| elements.
1. Let |contentsBytes| be |contentsSize| converted to bytes.
1. Issue the subsequent steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}.
</div>
<div data-timeline=device>
[=Device timeline=] steps:

1. [$Validate the encoder state$] of |this|. If it returns false, return.
1. If any of the following conditions are unsatisfied, [$invalidate$] |this| and return.

<div class=validusage>
- |rangeOffset| is a multiple of 4.
- |rangeOffset| + |contentsBytes| &le; |this|.{{GPUObjectBase/[[device]]}}.{{device/[[limits]]}}.{{supported limits/maxImmediateSize}}.
</div>
1. For each byte |b| at index |i| in |contents|:
1. Let |byteIndex| be |rangeOffset| + |i|.
1. Let |slotIndex| be floor(|byteIndex| &div; 4).
1. Set |this|.{{GPUBindingCommandsMixin/[[immediate_data]]}}[|byteIndex|] to |b|.
1. Set |this|.{{GPUBindingCommandsMixin/[[immediate_slots_set]]}}[|slotIndex|] to true.
</div>
</div>
</dl>

# Debug Markers # {#debug-markers}

<dfn interface>GPUDebugCommandsMixin</dfn> provides methods to apply debug labels to groups
Expand Down Expand Up @@ -11918,10 +12060,12 @@ dictionary GPUComputePassDescriptor
- |usageScope| must satisfy [=usage scope validation=].
- [$Validate encoder bind groups$](|this|, |this|.{{GPUComputePassEncoder/[[pipeline]]}})
is `true`.
- [$Validate immediate data$](|this|, |this|.{{GPUComputePassEncoder/[[pipeline]]}})
is `true`.
- all of |workgroupCountX|, |workgroupCountY| and |workgroupCountZ| are &le;
|this|.device.limits.{{supported limits/maxComputeWorkgroupsPerDimension}}.
- let |workgroupSize| be the computed workgroup size for
|bindingState|.{{GPUComputePassEncoder/[[pipeline]]}}.
|bindingState|.{{GPUComputePassEncoder/[[pipeline]]}}.
- the entry point uses the [=builtin/workgroup_index=]
built-in value and |workgroupCountX| &times; |workgroupCountY|
&times; |workgroupCountZ|
Expand Down Expand Up @@ -11997,6 +12141,8 @@ dictionary GPUComputePassDescriptor
- |usageScope| must satisfy [=usage scope validation=].
- [$Validate encoder bind groups$](|this|, |this|.{{GPUComputePassEncoder/[[pipeline]]}})
is `true`.
- [$Validate immediate data$](|this|, |this|.{{GPUComputePassEncoder/[[pipeline]]}})
is `true`.
- |indirectBuffer| is [$valid to use with$] |this|.
- |indirectBuffer|.{{GPUBuffer/usage}} contains {{GPUBufferUsage/INDIRECT}}.
- |indirectOffset| + sizeof([=indirect dispatch parameters=]) &le;
Expand Down Expand Up @@ -13413,6 +13559,8 @@ It must only be included by interfaces which also include those mixins.
<div class=validusage>
- [$Validate encoder bind groups$](|encoder|, |encoder|.{{GPURenderCommandsMixin/[[pipeline]]}})
must be `true`.
- [$Validate immediate data$](|encoder|, |encoder|.{{GPURenderCommandsMixin/[[pipeline]]}})
must be `true`.
- Let |pipelineDescriptor| be |encoder|.{{GPURenderCommandsMixin/[[pipeline]]}}.{{GPURenderPipeline/[[descriptor]]}}.
- For each {{GPUIndex32}} |slot| `0` to
|pipelineDescriptor|.{{GPURenderPipelineDescriptor/vertex}}.{{GPUVertexState/buffers}}.[=list/size=]:
Expand Down Expand Up @@ -13731,8 +13879,8 @@ attachments used by this encoder.
this render pass.

When a {{GPURenderBundle}} is executed, it does not inherit the render pass's pipeline, bind
groups, or vertex and index buffers. After a {{GPURenderBundle}} has executed, the render
pass's pipeline, bind group, and vertex/index buffer state is cleared
groups, immediate data, or vertex and index buffers. After a {{GPURenderBundle}} has executed, the render
pass's pipeline, bind group, immediate data, and vertex/index buffer state is cleared
(to the initial, empty values).

Note: The state is cleared, not restored to the previous state.
Expand Down Expand Up @@ -13797,6 +13945,7 @@ attachments used by this encoder.
the following [=device timeline=] steps:

1. [=map/Clear=] |encoder|.{{GPUBindingCommandsMixin/[[bind_groups]]}}.
1. Set each entry of |encoder|.{{GPUBindingCommandsMixin/[[immediate_slots_set]]}} to `false`.
1. Set |encoder|.{{GPURenderCommandsMixin/[[pipeline]]}} to `null`.
1. Set |encoder|.{{GPURenderCommandsMixin/[[index_buffer]]}} to `null`.
1. [=map/Clear=] |encoder|.{{GPURenderCommandsMixin/[[vertex_buffers]]}}.
Expand Down
Loading
Loading