bevy_render/render_resource/
pipeline.rs

1use crate::define_atomic_id;
2use crate::renderer::WgpuWrapper;
3use alloc::borrow::Cow;
4use bevy_asset::Handle;
5use bevy_mesh::VertexBufferLayout;
6use bevy_shader::{Shader, ShaderDefVal};
7use core::iter;
8use core::ops::Deref;
9use thiserror::Error;
10use wgpu::{
11    BindGroupLayoutEntry, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState,
12    PushConstantRange,
13};
14
15define_atomic_id!(RenderPipelineId);
16
17/// A [`RenderPipeline`] represents a graphics pipeline and its stages (shaders), bindings and vertex buffers.
18///
19/// May be converted from and dereferences to a wgpu [`RenderPipeline`](wgpu::RenderPipeline).
20/// Can be created via [`RenderDevice::create_render_pipeline`](crate::renderer::RenderDevice::create_render_pipeline).
21#[derive(Clone, Debug)]
22pub struct RenderPipeline {
23    id: RenderPipelineId,
24    value: WgpuWrapper<wgpu::RenderPipeline>,
25}
26
27impl RenderPipeline {
28    #[inline]
29    pub fn id(&self) -> RenderPipelineId {
30        self.id
31    }
32}
33
34impl From<wgpu::RenderPipeline> for RenderPipeline {
35    fn from(value: wgpu::RenderPipeline) -> Self {
36        RenderPipeline {
37            id: RenderPipelineId::new(),
38            value: WgpuWrapper::new(value),
39        }
40    }
41}
42
43impl Deref for RenderPipeline {
44    type Target = wgpu::RenderPipeline;
45
46    #[inline]
47    fn deref(&self) -> &Self::Target {
48        &self.value
49    }
50}
51
52define_atomic_id!(ComputePipelineId);
53
54/// A [`ComputePipeline`] represents a compute pipeline and its single shader stage.
55///
56/// May be converted from and dereferences to a wgpu [`ComputePipeline`](wgpu::ComputePipeline).
57/// Can be created via [`RenderDevice::create_compute_pipeline`](crate::renderer::RenderDevice::create_compute_pipeline).
58#[derive(Clone, Debug)]
59pub struct ComputePipeline {
60    id: ComputePipelineId,
61    value: WgpuWrapper<wgpu::ComputePipeline>,
62}
63
64impl ComputePipeline {
65    /// Returns the [`ComputePipelineId`].
66    #[inline]
67    pub fn id(&self) -> ComputePipelineId {
68        self.id
69    }
70}
71
72impl From<wgpu::ComputePipeline> for ComputePipeline {
73    fn from(value: wgpu::ComputePipeline) -> Self {
74        ComputePipeline {
75            id: ComputePipelineId::new(),
76            value: WgpuWrapper::new(value),
77        }
78    }
79}
80
81impl Deref for ComputePipeline {
82    type Target = wgpu::ComputePipeline;
83
84    #[inline]
85    fn deref(&self) -> &Self::Target {
86        &self.value
87    }
88}
89
90#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
91pub struct BindGroupLayoutDescriptor {
92    /// Debug label of the bind group layout descriptor. This will show up in graphics debuggers for easy identification.
93    pub label: Cow<'static, str>,
94    pub entries: Vec<BindGroupLayoutEntry>,
95}
96
97impl BindGroupLayoutDescriptor {
98    pub fn new(label: impl Into<Cow<'static, str>>, entries: &[BindGroupLayoutEntry]) -> Self {
99        Self {
100            label: label.into(),
101            entries: entries.into(),
102        }
103    }
104}
105
106/// Describes a render (graphics) pipeline.
107#[derive(Clone, Debug, PartialEq, Default)]
108pub struct RenderPipelineDescriptor {
109    /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
110    pub label: Option<Cow<'static, str>>,
111    /// The layout of bind groups for this pipeline.
112    pub layout: Vec<BindGroupLayoutDescriptor>,
113    /// The push constant ranges for this pipeline.
114    /// Supply an empty vector if the pipeline doesn't use push constants.
115    pub push_constant_ranges: Vec<PushConstantRange>,
116    /// The compiled vertex stage, its entry point, and the input buffers layout.
117    pub vertex: VertexState,
118    /// The properties of the pipeline at the primitive assembly and rasterization level.
119    pub primitive: PrimitiveState,
120    /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
121    pub depth_stencil: Option<DepthStencilState>,
122    /// The multi-sampling properties of the pipeline.
123    pub multisample: MultisampleState,
124    /// The compiled fragment stage, its entry point, and the color targets.
125    pub fragment: Option<FragmentState>,
126    /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true.
127    /// If this is false, reading from workgroup variables before writing to them will result in garbage values.
128    pub zero_initialize_workgroup_memory: bool,
129}
130
131#[derive(Copy, Clone, Debug, Error)]
132#[error("RenderPipelineDescriptor has no FragmentState configured")]
133pub struct NoFragmentStateError;
134
135impl RenderPipelineDescriptor {
136    pub fn fragment_mut(&mut self) -> Result<&mut FragmentState, NoFragmentStateError> {
137        self.fragment.as_mut().ok_or(NoFragmentStateError)
138    }
139
140    pub fn set_layout(&mut self, index: usize, layout: BindGroupLayoutDescriptor) {
141        filling_set_at(&mut self.layout, index, bevy_utils::default(), layout);
142    }
143}
144
145#[derive(Clone, Debug, Eq, PartialEq, Default)]
146pub struct VertexState {
147    /// The compiled shader module for this stage.
148    pub shader: Handle<Shader>,
149    pub shader_defs: Vec<ShaderDefVal>,
150    /// The name of the entry point in the compiled shader, or `None` if the default entry point
151    /// is used.
152    pub entry_point: Option<Cow<'static, str>>,
153    /// The format of any vertex buffers used with this pipeline.
154    pub buffers: Vec<VertexBufferLayout>,
155}
156
157/// Describes the fragment process in a render pipeline.
158#[derive(Clone, Debug, PartialEq, Eq, Default)]
159pub struct FragmentState {
160    /// The compiled shader module for this stage.
161    pub shader: Handle<Shader>,
162    pub shader_defs: Vec<ShaderDefVal>,
163    /// The name of the entry point in the compiled shader, or `None` if the default entry point
164    /// is used.
165    pub entry_point: Option<Cow<'static, str>>,
166    /// The color state of the render targets.
167    pub targets: Vec<Option<ColorTargetState>>,
168}
169
170impl FragmentState {
171    pub fn set_target(&mut self, index: usize, target: ColorTargetState) {
172        filling_set_at(&mut self.targets, index, None, Some(target));
173    }
174}
175
176/// Describes a compute pipeline.
177#[derive(Clone, Debug, PartialEq, Eq, Default)]
178pub struct ComputePipelineDescriptor {
179    pub label: Option<Cow<'static, str>>,
180    pub layout: Vec<BindGroupLayoutDescriptor>,
181    pub push_constant_ranges: Vec<PushConstantRange>,
182    /// The compiled shader module for this stage.
183    pub shader: Handle<Shader>,
184    pub shader_defs: Vec<ShaderDefVal>,
185    /// The name of the entry point in the compiled shader, or `None` if the default entry point
186    /// is used.
187    pub entry_point: Option<Cow<'static, str>>,
188    /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true.
189    /// If this is false, reading from workgroup variables before writing to them will result in garbage values.
190    pub zero_initialize_workgroup_memory: bool,
191}
192
193// utility function to set a value at the specified index, extending with
194// a filler value if the index is out of bounds.
195fn filling_set_at<T: Clone>(vec: &mut Vec<T>, index: usize, filler: T, value: T) {
196    let num_to_fill = (index + 1).saturating_sub(vec.len());
197    vec.extend(iter::repeat_n(filler, num_to_fill));
198    vec[index] = value;
199}