Add VertexBufferLayout::offset_locations (#9805)

# Objective

When using instancing, 2 `VertexBufferLayout`s are needed, one for
per-vertex and one for per-instance data. Shader locations of all
attributes must not overlap, so one of the layouts needs to start its
locations at an offset. However,
`VertexBufferLayout::from_vertex_formats` will always start locations at
0, requiring manual adjustment, which is currently pretty verbose.

## Solution

Add `VertexBufferLayout::offset_locations`, which adds an offset to all
attribute locations.

Code using this method looks like this:

```rust
VertexState {
    shader: BACKBUFFER_SHADER_HANDLE.typed(),
    shader_defs: Vec::new(),
    entry_point: "vertex".into(),
    buffers: vec![
        VertexBufferLayout::from_vertex_formats(
            VertexStepMode::Vertex,
            [VertexFormat::Float32x2],
        ),
        VertexBufferLayout::from_vertex_formats(
            VertexStepMode::Instance,
            [VertexFormat::Float32x2, VertexFormat::Float32x3],
        )
        .offset_locations(1),
    ],
}
```

Alternative solutions include:

- Pass the starting location to `from_vertex_formats` – this is a bit
simpler than my solution here, but most calls don't need an offset, so
they'd always pass 0 there.
- Do nothing and make the user hand-write this.

---

## Changelog

- Add `VertexBufferLayout::offset_locations` to simplify buffer layout
construction when using instancing.

---------

Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Sludge 2024-08-26 19:54:33 +02:00 committed by GitHub
parent 1caa64d948
commit 7bb76ab74b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -158,6 +158,15 @@ impl VertexBufferLayout {
attributes, attributes,
} }
} }
/// Returns a [`VertexBufferLayout`] with the shader location of every attribute offset by
/// `location`.
pub fn offset_locations_by(mut self, location: u32) -> Self {
self.attributes.iter_mut().for_each(|attr| {
attr.shader_location += location;
});
self
}
} }
/// Describes the fragment process in a render pipeline. /// Describes the fragment process in a render pipeline.