# 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>
198 lines
6.8 KiB
Rust
198 lines
6.8 KiB
Rust
use super::ShaderDefVal;
|
|
use crate::{
|
|
define_atomic_id,
|
|
render_resource::{resource_macros::render_resource_wrapper, BindGroupLayout, Shader},
|
|
};
|
|
use bevy_asset::Handle;
|
|
use std::{borrow::Cow, ops::Deref};
|
|
use wgpu::{
|
|
BufferAddress, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState,
|
|
PushConstantRange, VertexAttribute, VertexFormat, VertexStepMode,
|
|
};
|
|
|
|
define_atomic_id!(RenderPipelineId);
|
|
render_resource_wrapper!(ErasedRenderPipeline, wgpu::RenderPipeline);
|
|
|
|
/// A [`RenderPipeline`] represents a graphics pipeline and its stages (shaders), bindings and vertex buffers.
|
|
///
|
|
/// May be converted from and dereferences to a wgpu [`RenderPipeline`](wgpu::RenderPipeline).
|
|
/// Can be created via [`RenderDevice::create_render_pipeline`](crate::renderer::RenderDevice::create_render_pipeline).
|
|
#[derive(Clone, Debug)]
|
|
pub struct RenderPipeline {
|
|
id: RenderPipelineId,
|
|
value: ErasedRenderPipeline,
|
|
}
|
|
|
|
impl RenderPipeline {
|
|
#[inline]
|
|
pub fn id(&self) -> RenderPipelineId {
|
|
self.id
|
|
}
|
|
}
|
|
|
|
impl From<wgpu::RenderPipeline> for RenderPipeline {
|
|
fn from(value: wgpu::RenderPipeline) -> Self {
|
|
RenderPipeline {
|
|
id: RenderPipelineId::new(),
|
|
value: ErasedRenderPipeline::new(value),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Deref for RenderPipeline {
|
|
type Target = wgpu::RenderPipeline;
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
define_atomic_id!(ComputePipelineId);
|
|
render_resource_wrapper!(ErasedComputePipeline, wgpu::ComputePipeline);
|
|
|
|
/// A [`ComputePipeline`] represents a compute pipeline and its single shader stage.
|
|
///
|
|
/// May be converted from and dereferences to a wgpu [`ComputePipeline`](wgpu::ComputePipeline).
|
|
/// Can be created via [`RenderDevice::create_compute_pipeline`](crate::renderer::RenderDevice::create_compute_pipeline).
|
|
#[derive(Clone, Debug)]
|
|
pub struct ComputePipeline {
|
|
id: ComputePipelineId,
|
|
value: ErasedComputePipeline,
|
|
}
|
|
|
|
impl ComputePipeline {
|
|
/// Returns the [`ComputePipelineId`].
|
|
#[inline]
|
|
pub fn id(&self) -> ComputePipelineId {
|
|
self.id
|
|
}
|
|
}
|
|
|
|
impl From<wgpu::ComputePipeline> for ComputePipeline {
|
|
fn from(value: wgpu::ComputePipeline) -> Self {
|
|
ComputePipeline {
|
|
id: ComputePipelineId::new(),
|
|
value: ErasedComputePipeline::new(value),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Deref for ComputePipeline {
|
|
type Target = wgpu::ComputePipeline;
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
/// Describes a render (graphics) pipeline.
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct RenderPipelineDescriptor {
|
|
/// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
|
|
pub label: Option<Cow<'static, str>>,
|
|
/// The layout of bind groups for this pipeline.
|
|
pub layout: Vec<BindGroupLayout>,
|
|
/// The push constant ranges for this pipeline.
|
|
/// Supply an empty vector if the pipeline doesn't use push constants.
|
|
pub push_constant_ranges: Vec<PushConstantRange>,
|
|
/// The compiled vertex stage, its entry point, and the input buffers layout.
|
|
pub vertex: VertexState,
|
|
/// The properties of the pipeline at the primitive assembly and rasterization level.
|
|
pub primitive: PrimitiveState,
|
|
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
|
|
pub depth_stencil: Option<DepthStencilState>,
|
|
/// The multi-sampling properties of the pipeline.
|
|
pub multisample: MultisampleState,
|
|
/// The compiled fragment stage, its entry point, and the color targets.
|
|
pub fragment: Option<FragmentState>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct VertexState {
|
|
/// The compiled shader module for this stage.
|
|
pub shader: Handle<Shader>,
|
|
pub shader_defs: Vec<ShaderDefVal>,
|
|
/// The name of the entry point in the compiled shader. There must be a
|
|
/// function with this name in the shader.
|
|
pub entry_point: Cow<'static, str>,
|
|
/// The format of any vertex buffers used with this pipeline.
|
|
pub buffers: Vec<VertexBufferLayout>,
|
|
}
|
|
|
|
/// Describes how the vertex buffer is interpreted.
|
|
#[derive(Default, Clone, Debug, Hash, Eq, PartialEq)]
|
|
pub struct VertexBufferLayout {
|
|
/// The stride, in bytes, between elements of this buffer.
|
|
pub array_stride: BufferAddress,
|
|
/// How often this vertex buffer is "stepped" forward.
|
|
pub step_mode: VertexStepMode,
|
|
/// The list of attributes which comprise a single vertex.
|
|
pub attributes: Vec<VertexAttribute>,
|
|
}
|
|
|
|
impl VertexBufferLayout {
|
|
/// Creates a new densely packed [`VertexBufferLayout`] from an iterator of vertex formats.
|
|
/// Iteration order determines the `shader_location` and `offset` of the [`VertexAttributes`](VertexAttribute).
|
|
/// The first iterated item will have a `shader_location` and `offset` of zero.
|
|
/// The `array_stride` is the sum of the size of the iterated [`VertexFormats`](VertexFormat) (in bytes).
|
|
pub fn from_vertex_formats<T: IntoIterator<Item = VertexFormat>>(
|
|
step_mode: VertexStepMode,
|
|
vertex_formats: T,
|
|
) -> Self {
|
|
let mut offset = 0;
|
|
let mut attributes = Vec::new();
|
|
for (shader_location, format) in vertex_formats.into_iter().enumerate() {
|
|
attributes.push(VertexAttribute {
|
|
format,
|
|
offset,
|
|
shader_location: shader_location as u32,
|
|
});
|
|
offset += format.size();
|
|
}
|
|
|
|
VertexBufferLayout {
|
|
array_stride: offset,
|
|
step_mode,
|
|
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.
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct FragmentState {
|
|
/// The compiled shader module for this stage.
|
|
pub shader: Handle<Shader>,
|
|
pub shader_defs: Vec<ShaderDefVal>,
|
|
/// The name of the entry point in the compiled shader. There must be a
|
|
/// function with this name in the shader.
|
|
pub entry_point: Cow<'static, str>,
|
|
/// The color state of the render targets.
|
|
pub targets: Vec<Option<ColorTargetState>>,
|
|
}
|
|
|
|
/// Describes a compute pipeline.
|
|
#[derive(Clone, Debug)]
|
|
pub struct ComputePipelineDescriptor {
|
|
pub label: Option<Cow<'static, str>>,
|
|
pub layout: Vec<BindGroupLayout>,
|
|
pub push_constant_ranges: Vec<PushConstantRange>,
|
|
/// The compiled shader module for this stage.
|
|
pub shader: Handle<Shader>,
|
|
pub shader_defs: Vec<ShaderDefVal>,
|
|
/// The name of the entry point in the compiled shader. There must be a
|
|
/// function with this name in the shader.
|
|
pub entry_point: Cow<'static, str>,
|
|
}
|