diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index d6e5955c..ffd799aa 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -52,10 +52,17 @@ module.exports = { '/showcase/pong/', '/showcase/compute/', '/showcase/alignment/', - '/showcase/imgui-demo/', + // '/showcase/imgui-demo/', ] }, - '/news/' + { + title: 'News', + collapsable: true, + children: [ + '/news/0.12/', + '/news/pre-0.12/', + ] + } ] } } \ No newline at end of file diff --git a/docs/intermediate/tutorial10-lighting/README.md b/docs/intermediate/tutorial10-lighting/README.md index a1d9d7fa..00a8ebd0 100644 --- a/docs/intermediate/tutorial10-lighting/README.md +++ b/docs/intermediate/tutorial10-lighting/README.md @@ -27,11 +27,27 @@ struct LightUniform { // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here _padding: u32, color: [f32; 3], + // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here + _padding2: u32, } ``` Our `LightUniform` represents a colored point in space. We're just going to use pure white light, but it's good to allow different colors of light. + +
+ +The rule of thumb for alignment with WGSL structs is field alignments are +always powers of 2. For example a `vec3` may only have 3 float fields giving +it a size of 12, the alignment will be bumped up to the next power of 2 being +16. This means that you have to be more careful with how you layout your struct +in Rust. + +Some developers choose the use `vec4`s instead of `vec3`s to avoid alignment +issues. You can learn more about the alignment rules in the [wgsl spec](https://www.w3.org/TR/WGSL/#alignment-and-size) + +
+ We're going to create another buffer to store our light in. ```rust @@ -39,6 +55,7 @@ let light_uniform = LightUniform { position: [2.0, 2.0, 2.0], _padding: 0, color: [1.0, 1.0, 1.0], + _padding2: 0, }; // We'll want to update our lights position, so we use COPY_DST @@ -51,6 +68,7 @@ let light_buffer = device.create_buffer_init( ); ``` + Don't forget to add the `light_uniform` and `light_buffer` to `State`. After that we need to create a bind group layout and bind group for our light. ```rust diff --git a/docs/news/0.12.md b/docs/news/0.12.md deleted file mode 100644 index 8e03c1f5..00000000 --- a/docs/news/0.12.md +++ /dev/null @@ -1,33 +0,0 @@ -# Update to 0.12! - -There's not a ton of changes in this release, so the migration -wasn't too painful. - -## Multi view added - -## No more block attribute - -## More validation - -``` -thread 'main' panicked at 'wgpu error: Validation Error - -Caused by: - In a RenderPass - note: encoder = `Render Encoder` - In a draw command, indexed:true indirect:false - note: render pipeline = `Render Pipeline` - Buffer is bound with size 28 where the shader expects 32 in group[1] compact index 0 -``` - -```rust -#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct LightUniform { - position: [f32; 3], - // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here - _padding: u32, - color: [f32; 3], - // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here - _padding2: u32, -} -``` \ No newline at end of file diff --git a/docs/news/0.12/readme.md b/docs/news/0.12/readme.md new file mode 100644 index 00000000..bf936689 --- /dev/null +++ b/docs/news/0.12/readme.md @@ -0,0 +1,74 @@ +# Update to 0.12! + +There's not a ton of changes in this release, so the migration +wasn't too painful. + +## Multi view added + +## No more block attribute + +The WGSL spec has changed and the `block` attribute is no longer a thing. +This means that structs in WGSL no longer need to be anotated to be used +as uniform input. For example: + +```wgsl +[[block]] +struct Camera { + view_pos: vec4; + view_proj: mat4x4; +}; +``` + +Can be simplified to just + +```wgsl +struct Camera { + view_pos: vec4; + view_proj: mat4x4; +}; +``` + +## More validation + +Wgpu now has a validation error where if your uniform doesn't match the +alignment specified in the shader, the program will crash when you go to +draw: + +``` +thread 'main' panicked at 'wgpu error: Validation Error + +Caused by: + In a RenderPass + note: encoder = `Render Encoder` + In a draw command, indexed:true indirect:false + note: render pipeline = `Render Pipeline` + Buffer is bound with size 28 where the shader expects 32 in group[1] compact index 0 +``` + +The only struct that I needed to change was the `LightUniform` struct. All +I needed to do was add a padding field: + +```rust +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct LightUniform { + position: [f32; 3], + // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here + _padding: u32, + color: [f32; 3], + // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here + _padding2: u32, +} +``` + +I updated the [lighting tutorial](../../intermediate/tutorial10-lighting) to reflect +this change. + +## Misc + +Due to the recent deploy to [anyhow](https://docs.rs/anyhow/latest/) that +breaks glob imports (aka. `use anyhow::*`), I had to switch qualified +imports and uses (ie. `anyhow::Result`). This was mostly an issue on my +build scripts for some of showcase examples. + +The main tutorial examples weren't affected, and the changes are minor, so +if your curious feel free to look at the repo. \ No newline at end of file diff --git a/docs/news/normal_mapping_correct.png b/docs/news/pre-0.12/normal_mapping_correct.png similarity index 100% rename from docs/news/normal_mapping_correct.png rename to docs/news/pre-0.12/normal_mapping_correct.png diff --git a/docs/news/README.md b/docs/news/pre-0.12/readme.md similarity index 99% rename from docs/news/README.md rename to docs/news/pre-0.12/readme.md index eaf53250..bcc5d275 100644 --- a/docs/news/README.md +++ b/docs/news/pre-0.12/readme.md @@ -1,4 +1,4 @@ -# News +# News (Pre 0.12) ## Pong working on the web diff --git a/docs/showcase/alignment/README.md b/docs/showcase/alignment/README.md index 47b4f9c5..2d5efa3f 100644 --- a/docs/showcase/alignment/README.md +++ b/docs/showcase/alignment/README.md @@ -1,29 +1,91 @@ -# Memory Layout in GLSL - -## Alignments - -The address of the position of an instance in memory has to a multiple of its alignment. - -Normally alignment is the same as size. Exceptions are vec3, structs and arrays. - -A vec3 is padded to be a vec4 which means it behaves as if it was a vec4 just that the last entry is not used. - -`{i,u,b}vec` is shorthand for `ivec`, `uvec`, `bvec` so a vector of `int` or `uint` or `bool`. A `vec` is a vec of `float`. - -| type | Alignment in bytes | size in bytes | -| --------------------------- | ------------------ | ------------- | -| int, uint, float, bool | 4 | 4 | -| double | 8 | 8 | -| {i,u,b}vec2 | 8 | 8 | -| dvec2 | 16 | 16 | -| {i,u,b}vec3 | **16** | 12 | -| {i,u,b}vec4 | 16 | 16 | -| dvec3 | **32** | 24 | -| dvec4 | 32 | 32 | -| mat3 (like array of 3 vec3) | **16** | 3*16 | -| mat4 (like array of 4 vec4) | 16 | 4*16 | - -[Reference](https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159) section 7.6.2.2 +# Memory Layout in WGSL + +## Alignment of vertex and index buffers + +Vertex buffers require defining a `VertexBufferLayout`, so the memory alignment is whatever +you tell WebGPU it should be. This can be really convenient for keeping down memory usage +on the GPU. + +The Index Buffer use the alignment of whatever primitive type you specify via the `IndexFormat` +you pass into `RenderEncoder::set_index_buffer()`. + +## Alignment of Uniform and Storage buffers + +GPUs are designed to process thousands of pixels in parallel. In order to achieve this, +some sacrifices had to be made. Graphics hardware likes to have all the bytes you intend +on processing aligned by powers of 2. The exact specifics of why this is are beyond +my level of knowledge, but it's important to know so that you can trouble shoot why your +shaders aren't working. + + + +Let's take a look at the following table: + +--------------------------------------------------------------- +| Type | Alignment in Bytes | Size in Bytes | +|------------------------|--------------------|---------------| +| scalar (i32, u32, f32) | 4 | 4 | +| vec2<T> | 8 | 8 | +| vec3<T> | **16** | 12 | +| vec4<T> | 16 | 16 | + +You can see for `vec3` the alignment is the next power of 2 from the size, 16. This can +catche beginners (and even veterans) as it's not the most intuitive. This becomes especially +important when we start laying out structs. Take the light struct from the [lighting tutorial](../../intermediate/tutorial10-lighting/#seeing-the-light): + +You can see the full table of the alignments in section [4.3.7.1 of the WGSL spec](https://www.w3.org/TR/WGSL/#alignment-and-size) + +```wgsl +struct Light { + position: vec3; + color: vec3; +}; +``` + +So what's the alignment of this scruct? Your first guess would be that it's the sum of +the alignments of the individual fields. That might make sense if we were in Rust-land, +but in shader-land, it's a little more involved. The alignment for a given struct is given +by the following equation: + +``` +// S is the struct in question +// M is a member of the struct +AlignOf(S) = max(AlignOfMember(S, M1), ... , AlignOfMember(S, Mn)) +``` + +Basically the alignment of the struct is the maximum of the alignments of the members of +the struct. This means that: + +``` +AlignOf(Light) + = max(AlignOfMember(Light, position), AlignOfMember(Light, color)) + = max(16, 16) + = 16 +``` + +This is why the `LightUniform` has those padding fields. WGPU won't accept it if the data +is not aligned correctly. + +## How to deal with alignment issues + +In general 16, is the max alignment you'll see. In that case you might think that we should +be able to do something like the following: + +```rust +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct LightUniform { + position: [f32; 3], + color: [f32; 3], +} +``` + +But this won't compile. The [bytemuck crate](https://docs.rs/bytemuck/) doesn't work with +structs with implicit padding bytes. Rust can't guarantee that the memory between the fields +has been initialized properly. The are potential security ## In WGPU