From 9338e7a0b89b311db137caaa504963511c79168c Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 8 Dec 2021 17:14:22 -0500 Subject: [PATCH 1/7] Store type for buffer does not have to be structure * Modify an example showing a runtime-sized array as the store type for a storage buffer. Fixes: #2188 --- wgsl/index.bs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/wgsl/index.bs b/wgsl/index.bs index ed0c57e6c8..d643572194 100644 --- a/wgsl/index.bs +++ b/wgsl/index.bs @@ -1267,15 +1267,17 @@ Note: Each member type must be a [=plain type=]. Some consequences of the restrictions structure member and array element types are: * A pointer, texture, or sampler must not appear in any level of nesting within an array or structure. -* A [=runtime-sized=] array must only appear as the last element of a structure, which itself - cannot be part of an enclosing array or structure. +* When a [=runtime-sized=] array is part of a larger type, it may only appear + as the last element of a structure, which itself cannot be part of an enclosing array or structure.
- // A structure with two members. + // A structure with four members. struct Data { a: i32; b: vec2<f32>; + c: array<i32,10>; + d: array<f32>; }
@@ -3311,11 +3313,11 @@ Variables at [=module scope=] are restricted as follows: have a storage class decoration. The storage class will always be [=storage classes/handle=]. A variable in the [=storage classes/uniform=] storage class is a uniform buffer variable. -Its [=store type=] must be a [=host-shareable=] [=constructible=] structure type, +Its [=store type=] must be a [=host-shareable=] [=constructible=] type, and must satisfy [storage class layout constraints](#storage-class-layout-constraints). A variable in the [=storage classes/storage=] storage class is a storage buffer variable. -Its [=store type=] must be a [=host-shareable=] structure type +Its [=store type=] must be a [=host-shareable=] type and must satisfy [storage class layout constraints](#storage-class-layout-constraints). The variable may be declared with a [=access/read=] or [=access/read_write=] access mode; the default is [=access/read=]. @@ -3341,13 +3343,9 @@ Such variables are declared with [=attribute/group=] and [=attribute/binding=] d @group(0) @binding(2) var param: Params; // A uniform buffer - struct PositionsBuffer { - // TODO: runtime-sized array syntax may have changed - pos: array>; - } // A storage buffer, for reading and writing @group(0) @binding(0) - var pbuf: PositionsBuffer; + var pbuf: array>; // Textures and samplers are always in "handle" storage. @group(0) @binding(1) From 04c3bdd573689800f75c49d168137aecf98e5ee3 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 11 Jan 2022 17:47:57 -0500 Subject: [PATCH 2/7] Update the API-side rules about minBindingSize The store type of the corresponding variable is not always going to be a structure type. Qualify the rule accordingly. --- spec/index.bs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index bce65a76bf..d3ef0bdb97 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -4936,12 +4936,14 @@ typedef double GPUPipelineConstantValue; // May represent WGSL's bool, f32, i32, :: If |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} is not `0`: - - If the last field of the corresponding structure defined in the shader has an unbounded array type, + - If the store type of the corresponding buffer variable in the shader is a structure type, and the + last member of that structure is an runtime-sized array, then the value of |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} - must be greater than or equal to the byte offset of that field plus the stride of the unbounded array. - - If the corresponding shader structure doesn't end with an unbounded array type, - then the value of |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} - must be greater than or equal to the size of the structure. + must be greater than or equal to the byte offset of that field plus the element stride of that array. + That is, the binding size must be large enough to cover the whole structure including at least one + element of that array. + - Otherwise, the value of |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} + must be greater than or equal to the size of the store type of the corresponding buffer variable. : {{GPUBindGroupLayoutEntry/sampler}} :: From 1e32a70c48352222264bc809c98b9afdb7b51e2e Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 12 Jan 2022 17:25:04 -0500 Subject: [PATCH 3/7] Rework minimum binding size in both WebGPU and WGSL spec Define 'minimum binding size' in WGSL spec, and link to it from WebGPU. Repeat the rule in both places (to be helpful). The minimum binding size for a var with store type |T| is max(AlignOf(T),SizeOf(T)), and explain why the AlignOf part is needed: it's because sometimes we have to wrap |T| in a struct. This also replaces the old rule in WGSL which confusingly dependend on the storage class. The storage class aspect is already embedded in the alignment and size constraints for the variable. --- spec/index.bs | 18 +++++++++--------- wgsl/index.bs | 31 +++++++++++++------------------ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index d3ef0bdb97..06871bbb05 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -77,6 +77,7 @@ spec: WGSL; urlPrefix: https://gpuweb.github.io/gpuweb/wgsl/# type: dfn text: location; url: input-output-locations text: interpolation; url: interpolation + text: minimum binding size; url: minimum-binding-size text: pipeline-overridable; url: pipeline-overridable text: pipeline-overridable constant identifier string; url: pipeline-overridable-constant-identifier-string text: pipeline-overridable constant has a default value; url: pipeline-overridable-constant-has-a-default-value @@ -4934,16 +4935,15 @@ typedef double GPUPipelineConstantValue; // May represent WGSL's bool, f32, i32, : {{GPUBufferBindingType/"read-only-storage"}} :: |variable| is declared with the storage class `storage` and access mode `read`. + :: - If |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} is not `0`: - - If the store type of the corresponding buffer variable in the shader is a structure type, and the - last member of that structure is an runtime-sized array, - then the value of |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} - must be greater than or equal to the byte offset of that field plus the element stride of that array. - That is, the binding size must be large enough to cover the whole structure including at least one - element of that array. - - Otherwise, the value of |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} - must be greater than or equal to the size of the store type of the corresponding buffer variable. + If |entry|.{{GPUBindGroupLayoutEntry/buffer}}.{{GPUBufferBindingLayout/minBindingSize}} is not `0`, + then it must be at least the [=minimum binding size=] for the associated buffer variable in the shader. + If the variable has store type |T|, the minimum binding size is max(SizeOf(|T|),AlignOf(|T|)). + In this calculation, if |T| is a runtime-sized array or contains a runtime-sized array, + that array is assumed to have one element. + Enforcing this lower bound ensures any memory location accessible via the buffer variable will lie + within the mapped buffer region. : {{GPUBindGroupLayoutEntry/sampler}} :: diff --git a/wgsl/index.bs b/wgsl/index.bs index d643572194..cecddf7cd9 100644 --- a/wgsl/index.bs +++ b/wgsl/index.bs @@ -7094,24 +7094,19 @@ TODO: Describe when filtering or non-filtering samplers are valid. TODO: Describe when float vs. unfilterable float sampled textures are valid. -If |B| is a [=uniform buffer=] variable in a resource interface, -and |WB| is the [[WebGPU#buffer-interface|WebGPU GPUBuffer]] bound to |B|, then: -* The size of |WB| must be at least as large as the size of the [=store type=] - of |B| in the [=storage classes/storage=] storage class. - -If |B| is a [=storage buffer=] variable in a resource interface, -and |WB| is the [[WebGPU#buffer-interface|WebGPU GPUBuffer]] bound to |B|, then: -* If the [=store type=] |S| of |B| does not contain a [=runtime-sized=] array, then - the size of |WB| must be at least as large as the size - of |S| in the [=storage classes/storage=] storage class. -* If the [=store type=] |S| of |B| contains a [=runtime-sized=] array as its last member, - then: - * The runtime-determined array length of that member must be at least 1. - * The size of |WB| must be at least as large as the size in - storage class [=storage classes/storage=] of the value stored in |B|. - -Note: Recall that a [=runtime-sized=] array may only appear as the last element in the structure -type that is the store type of a storage buffer variable. + +The region of a [[WebGPU#buffer-interface|WebGPU GPUBuffer]] bound to a buffer variable +must be large enough to cover all the memory locations accessible via the variable. +The minimium binding size of a buffer variable with store type |T| is max([=SizeOf=](|T|),[=AlignOf=](|T|)). +In this calculation, if |T| is a runtime-sized array or contains a runtime-sized array, that array is assumed +to have one element. + +Note: Naively, a minimum binding size of [=SizeOf=](|T|) should be sufficient. +However, some underlying implementations require the store type of a buffer variable to be a structure type. +Requiring the minimum binding size to be at least as large as [=AlignOf=](T) allows an implementation to +map a non-structure store type |T| in WGSL to a structure type |WrapT| in the underlying shader language, where |WrapT| +consists of a single member of type |T|. +The minimum binding sizes of |T| and |WrapT| are equal. TODO: Describe other interface matching requirements, e.g. for images? From 03e2cc843352e8d5cf7840ea8807802d1ebd4efd Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 14 Jan 2022 15:06:08 -0500 Subject: [PATCH 4/7] Simplify minimum binding size to Sizeof(store-type) Underlying APIs don't need the extra padding at the end of any structure which might wrap the store type for the buffer variable. --- wgsl/index.bs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/wgsl/index.bs b/wgsl/index.bs index cecddf7cd9..81997b7922 100644 --- a/wgsl/index.bs +++ b/wgsl/index.bs @@ -7097,17 +7097,10 @@ TODO: Describe when float vs. unfilterable float sampled textures are valid. The region of a [[WebGPU#buffer-interface|WebGPU GPUBuffer]] bound to a buffer variable must be large enough to cover all the memory locations accessible via the variable. -The minimium binding size of a buffer variable with store type |T| is max([=SizeOf=](|T|),[=AlignOf=](|T|)). -In this calculation, if |T| is a runtime-sized array or contains a runtime-sized array, that array is assumed +The minimium binding size of a buffer variable with store type |T| is [=SizeOf=](|T|). +In this calculation, if |T| is a [=runtime-sized=] array or contains a runtime-sized array, that array is assumed to have one element. -Note: Naively, a minimum binding size of [=SizeOf=](|T|) should be sufficient. -However, some underlying implementations require the store type of a buffer variable to be a structure type. -Requiring the minimum binding size to be at least as large as [=AlignOf=](T) allows an implementation to -map a non-structure store type |T| in WGSL to a structure type |WrapT| in the underlying shader language, where |WrapT| -consists of a single member of type |T|. -The minimum binding sizes of |T| and |WrapT| are equal. - TODO: Describe other interface matching requirements, e.g. for images? # Language extensions # {#language-extensions} From bf408aeb1b35a1e1c06640b5ad6994be503f926c Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 14 Jan 2022 15:11:07 -0500 Subject: [PATCH 5/7] Update API-side to SizeOf(store-type) --- spec/index.bs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 06871bbb05..0ea4af48e1 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -91,6 +91,8 @@ spec: WGSL; urlPrefix: https://gpuweb.github.io/gpuweb/wgsl/# text: invalid memory reference; url: invalid-memory-reference text: shader-creation error; url: shader-creation-error text: pipeline-creation error; url: pipeline-creation-error + text: store type; url: store-type + text: runtime-sized; url: runtime-sized