wgpu_core/
pipeline.rs

1pub use crate::pipeline_cache::PipelineCacheValidationError;
2use crate::{
3    binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError, PipelineLayout},
4    command::ColorAttachmentError,
5    device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext},
6    id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId},
7    resource::{InvalidResourceError, Labeled, TrackingData},
8    resource_log, validation, Label,
9};
10use arrayvec::ArrayVec;
11use naga::error::ShaderError;
12use std::{borrow::Cow, marker::PhantomData, mem::ManuallyDrop, num::NonZeroU32, sync::Arc};
13use thiserror::Error;
14
15/// Information about buffer bindings, which
16/// is validated against the shader (and pipeline)
17/// at draw time as opposed to initialization time.
18#[derive(Debug)]
19pub(crate) struct LateSizedBufferGroup {
20    // The order has to match `BindGroup::late_buffer_binding_sizes`.
21    pub(crate) shader_sizes: Vec<wgt::BufferAddress>,
22}
23
24#[allow(clippy::large_enum_variant)]
25pub enum ShaderModuleSource<'a> {
26    #[cfg(feature = "wgsl")]
27    Wgsl(Cow<'a, str>),
28    #[cfg(feature = "glsl")]
29    Glsl(Cow<'a, str>, naga::front::glsl::Options),
30    #[cfg(feature = "spirv")]
31    SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
32    Naga(Cow<'static, naga::Module>),
33    /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it
34    /// could be the last one active.
35    #[doc(hidden)]
36    Dummy(PhantomData<&'a ()>),
37}
38
39#[derive(Clone, Debug)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct ShaderModuleDescriptor<'a> {
42    pub label: Label<'a>,
43    #[cfg_attr(feature = "serde", serde(default))]
44    pub runtime_checks: wgt::ShaderRuntimeChecks,
45}
46
47#[derive(Debug)]
48pub struct ShaderModule {
49    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynShaderModule>>,
50    pub(crate) device: Arc<Device>,
51    pub(crate) interface: Option<validation::Interface>,
52    /// The `label` from the descriptor used to create the resource.
53    pub(crate) label: String,
54}
55
56impl Drop for ShaderModule {
57    fn drop(&mut self) {
58        resource_log!("Destroy raw {}", self.error_ident());
59        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
60        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
61        unsafe {
62            self.device.raw().destroy_shader_module(raw);
63        }
64    }
65}
66
67crate::impl_resource_type!(ShaderModule);
68crate::impl_labeled!(ShaderModule);
69crate::impl_parent_device!(ShaderModule);
70crate::impl_storage_item!(ShaderModule);
71
72impl ShaderModule {
73    pub(crate) fn raw(&self) -> &dyn hal::DynShaderModule {
74        self.raw.as_ref()
75    }
76
77    pub(crate) fn finalize_entry_point_name(
78        &self,
79        stage_bit: wgt::ShaderStages,
80        entry_point: Option<&str>,
81    ) -> Result<String, validation::StageError> {
82        match &self.interface {
83            Some(interface) => interface.finalize_entry_point_name(stage_bit, entry_point),
84            None => entry_point
85                .map(|ep| ep.to_string())
86                .ok_or(validation::StageError::NoEntryPointFound),
87        }
88    }
89}
90
91//Note: `Clone` would require `WithSpan: Clone`.
92#[derive(Clone, Debug, Error)]
93#[non_exhaustive]
94pub enum CreateShaderModuleError {
95    #[cfg(any(feature = "wgsl", feature = "indirect-validation"))]
96    #[error(transparent)]
97    Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
98    #[cfg(feature = "glsl")]
99    #[error(transparent)]
100    ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
101    #[cfg(feature = "spirv")]
102    #[error(transparent)]
103    ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
104    #[error("Failed to generate the backend-specific code")]
105    Generation,
106    #[error(transparent)]
107    Device(#[from] DeviceError),
108    #[error(transparent)]
109    Validation(#[from] ShaderError<naga::WithSpan<naga::valid::ValidationError>>),
110    #[error(transparent)]
111    MissingFeatures(#[from] MissingFeatures),
112    #[error(
113        "Shader global {bind:?} uses a group index {group} that exceeds the max_bind_groups limit of {limit}."
114    )]
115    InvalidGroupIndex {
116        bind: naga::ResourceBinding,
117        group: u32,
118        limit: u32,
119    },
120}
121
122/// Describes a programmable pipeline stage.
123#[derive(Clone, Debug)]
124#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
125pub struct ProgrammableStageDescriptor<'a> {
126    /// The compiled shader module for this stage.
127    pub module: ShaderModuleId,
128    /// The name of the entry point in the compiled shader. The name is selected using the
129    /// following logic:
130    ///
131    /// * If `Some(name)` is specified, there must be a function with this name in the shader.
132    /// * If a single entry point associated with this stage must be in the shader, then proceed as
133    ///   if `Some(…)` was specified with that entry point's name.
134    pub entry_point: Option<Cow<'a, str>>,
135    /// Specifies the values of pipeline-overridable constants in the shader module.
136    ///
137    /// If an `@id` attribute was specified on the declaration,
138    /// the key must be the pipeline constant ID as a decimal ASCII number; if not,
139    /// the key must be the constant's identifier name.
140    ///
141    /// The value may represent any of WGSL's concrete scalar types.
142    pub constants: Cow<'a, naga::back::PipelineConstants>,
143    /// Whether workgroup scoped memory will be initialized with zero values for this stage.
144    ///
145    /// This is required by the WebGPU spec, but may have overhead which can be avoided
146    /// for cross-platform applications
147    pub zero_initialize_workgroup_memory: bool,
148}
149
150/// Describes a programmable pipeline stage.
151#[derive(Clone, Debug)]
152pub struct ResolvedProgrammableStageDescriptor<'a> {
153    /// The compiled shader module for this stage.
154    pub module: Arc<ShaderModule>,
155    /// The name of the entry point in the compiled shader. The name is selected using the
156    /// following logic:
157    ///
158    /// * If `Some(name)` is specified, there must be a function with this name in the shader.
159    /// * If a single entry point associated with this stage must be in the shader, then proceed as
160    ///   if `Some(…)` was specified with that entry point's name.
161    pub entry_point: Option<Cow<'a, str>>,
162    /// Specifies the values of pipeline-overridable constants in the shader module.
163    ///
164    /// If an `@id` attribute was specified on the declaration,
165    /// the key must be the pipeline constant ID as a decimal ASCII number; if not,
166    /// the key must be the constant's identifier name.
167    ///
168    /// The value may represent any of WGSL's concrete scalar types.
169    pub constants: Cow<'a, naga::back::PipelineConstants>,
170    /// Whether workgroup scoped memory will be initialized with zero values for this stage.
171    ///
172    /// This is required by the WebGPU spec, but may have overhead which can be avoided
173    /// for cross-platform applications
174    pub zero_initialize_workgroup_memory: bool,
175}
176
177/// Number of implicit bind groups derived at pipeline creation.
178pub type ImplicitBindGroupCount = u8;
179
180#[derive(Clone, Debug, Error)]
181#[non_exhaustive]
182pub enum ImplicitLayoutError {
183    #[error("The implicit_pipeline_ids arg is required")]
184    MissingImplicitPipelineIds,
185    #[error("Missing IDs for deriving {0} bind groups")]
186    MissingIds(ImplicitBindGroupCount),
187    #[error("Unable to reflect the shader {0:?} interface")]
188    ReflectionError(wgt::ShaderStages),
189    #[error(transparent)]
190    BindGroup(#[from] CreateBindGroupLayoutError),
191    #[error(transparent)]
192    Pipeline(#[from] CreatePipelineLayoutError),
193}
194
195/// Describes a compute pipeline.
196#[derive(Clone, Debug)]
197#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
198pub struct ComputePipelineDescriptor<'a> {
199    pub label: Label<'a>,
200    /// The layout of bind groups for this pipeline.
201    pub layout: Option<PipelineLayoutId>,
202    /// The compiled compute stage and its entry point.
203    pub stage: ProgrammableStageDescriptor<'a>,
204    /// The pipeline cache to use when creating this pipeline.
205    pub cache: Option<PipelineCacheId>,
206}
207
208/// Describes a compute pipeline.
209#[derive(Clone, Debug)]
210pub struct ResolvedComputePipelineDescriptor<'a> {
211    pub label: Label<'a>,
212    /// The layout of bind groups for this pipeline.
213    pub layout: Option<Arc<PipelineLayout>>,
214    /// The compiled compute stage and its entry point.
215    pub stage: ResolvedProgrammableStageDescriptor<'a>,
216    /// The pipeline cache to use when creating this pipeline.
217    pub cache: Option<Arc<PipelineCache>>,
218}
219
220#[derive(Clone, Debug, Error)]
221#[non_exhaustive]
222pub enum CreateComputePipelineError {
223    #[error(transparent)]
224    Device(#[from] DeviceError),
225    #[error("Unable to derive an implicit layout")]
226    Implicit(#[from] ImplicitLayoutError),
227    #[error("Error matching shader requirements against the pipeline")]
228    Stage(#[from] validation::StageError),
229    #[error("Internal error: {0}")]
230    Internal(String),
231    #[error("Pipeline constant error: {0}")]
232    PipelineConstants(String),
233    #[error(transparent)]
234    MissingDownlevelFlags(#[from] MissingDownlevelFlags),
235    #[error(transparent)]
236    InvalidResource(#[from] InvalidResourceError),
237}
238
239#[derive(Debug)]
240pub struct ComputePipeline {
241    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
242    pub(crate) layout: Arc<PipelineLayout>,
243    pub(crate) device: Arc<Device>,
244    pub(crate) _shader_module: Arc<ShaderModule>,
245    pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
246    /// The `label` from the descriptor used to create the resource.
247    pub(crate) label: String,
248    pub(crate) tracking_data: TrackingData,
249}
250
251impl Drop for ComputePipeline {
252    fn drop(&mut self) {
253        resource_log!("Destroy raw {}", self.error_ident());
254        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
255        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
256        unsafe {
257            self.device.raw().destroy_compute_pipeline(raw);
258        }
259    }
260}
261
262crate::impl_resource_type!(ComputePipeline);
263crate::impl_labeled!(ComputePipeline);
264crate::impl_parent_device!(ComputePipeline);
265crate::impl_storage_item!(ComputePipeline);
266crate::impl_trackable!(ComputePipeline);
267
268impl ComputePipeline {
269    pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
270        self.raw.as_ref()
271    }
272}
273
274#[derive(Clone, Debug, Error)]
275#[non_exhaustive]
276pub enum CreatePipelineCacheError {
277    #[error(transparent)]
278    Device(#[from] DeviceError),
279    #[error("Pipeline cache validation failed")]
280    Validation(#[from] PipelineCacheValidationError),
281    #[error(transparent)]
282    MissingFeatures(#[from] MissingFeatures),
283}
284
285#[derive(Debug)]
286pub struct PipelineCache {
287    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
288    pub(crate) device: Arc<Device>,
289    /// The `label` from the descriptor used to create the resource.
290    pub(crate) label: String,
291}
292
293impl Drop for PipelineCache {
294    fn drop(&mut self) {
295        resource_log!("Destroy raw {}", self.error_ident());
296        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
297        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
298        unsafe {
299            self.device.raw().destroy_pipeline_cache(raw);
300        }
301    }
302}
303
304crate::impl_resource_type!(PipelineCache);
305crate::impl_labeled!(PipelineCache);
306crate::impl_parent_device!(PipelineCache);
307crate::impl_storage_item!(PipelineCache);
308
309impl PipelineCache {
310    pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
311        self.raw.as_ref()
312    }
313}
314
315/// Describes how the vertex buffer is interpreted.
316#[derive(Clone, Debug)]
317#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
318#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
319pub struct VertexBufferLayout<'a> {
320    /// The stride, in bytes, between elements of this buffer.
321    pub array_stride: wgt::BufferAddress,
322    /// How often this vertex buffer is "stepped" forward.
323    pub step_mode: wgt::VertexStepMode,
324    /// The list of attributes which comprise a single vertex.
325    pub attributes: Cow<'a, [wgt::VertexAttribute]>,
326}
327
328/// Describes the vertex process in a render pipeline.
329#[derive(Clone, Debug)]
330#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
331pub struct VertexState<'a> {
332    /// The compiled vertex stage and its entry point.
333    pub stage: ProgrammableStageDescriptor<'a>,
334    /// The format of any vertex buffers used with this pipeline.
335    pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
336}
337
338/// Describes the vertex process in a render pipeline.
339#[derive(Clone, Debug)]
340pub struct ResolvedVertexState<'a> {
341    /// The compiled vertex stage and its entry point.
342    pub stage: ResolvedProgrammableStageDescriptor<'a>,
343    /// The format of any vertex buffers used with this pipeline.
344    pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
345}
346
347/// Describes fragment processing in a render pipeline.
348#[derive(Clone, Debug)]
349#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
350pub struct FragmentState<'a> {
351    /// The compiled fragment stage and its entry point.
352    pub stage: ProgrammableStageDescriptor<'a>,
353    /// The effect of draw calls on the color aspect of the output target.
354    pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
355}
356
357/// Describes fragment processing in a render pipeline.
358#[derive(Clone, Debug)]
359pub struct ResolvedFragmentState<'a> {
360    /// The compiled fragment stage and its entry point.
361    pub stage: ResolvedProgrammableStageDescriptor<'a>,
362    /// The effect of draw calls on the color aspect of the output target.
363    pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
364}
365
366/// Describes a render (graphics) pipeline.
367#[derive(Clone, Debug)]
368#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
369pub struct RenderPipelineDescriptor<'a> {
370    pub label: Label<'a>,
371    /// The layout of bind groups for this pipeline.
372    pub layout: Option<PipelineLayoutId>,
373    /// The vertex processing state for this pipeline.
374    pub vertex: VertexState<'a>,
375    /// The properties of the pipeline at the primitive assembly and rasterization level.
376    #[cfg_attr(feature = "serde", serde(default))]
377    pub primitive: wgt::PrimitiveState,
378    /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
379    #[cfg_attr(feature = "serde", serde(default))]
380    pub depth_stencil: Option<wgt::DepthStencilState>,
381    /// The multi-sampling properties of the pipeline.
382    #[cfg_attr(feature = "serde", serde(default))]
383    pub multisample: wgt::MultisampleState,
384    /// The fragment processing state for this pipeline.
385    pub fragment: Option<FragmentState<'a>>,
386    /// If the pipeline will be used with a multiview render pass, this indicates how many array
387    /// layers the attachments will have.
388    pub multiview: Option<NonZeroU32>,
389    /// The pipeline cache to use when creating this pipeline.
390    pub cache: Option<PipelineCacheId>,
391}
392
393/// Describes a render (graphics) pipeline.
394#[derive(Clone, Debug)]
395pub struct ResolvedRenderPipelineDescriptor<'a> {
396    pub label: Label<'a>,
397    /// The layout of bind groups for this pipeline.
398    pub layout: Option<Arc<PipelineLayout>>,
399    /// The vertex processing state for this pipeline.
400    pub vertex: ResolvedVertexState<'a>,
401    /// The properties of the pipeline at the primitive assembly and rasterization level.
402    pub primitive: wgt::PrimitiveState,
403    /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
404    pub depth_stencil: Option<wgt::DepthStencilState>,
405    /// The multi-sampling properties of the pipeline.
406    pub multisample: wgt::MultisampleState,
407    /// The fragment processing state for this pipeline.
408    pub fragment: Option<ResolvedFragmentState<'a>>,
409    /// If the pipeline will be used with a multiview render pass, this indicates how many array
410    /// layers the attachments will have.
411    pub multiview: Option<NonZeroU32>,
412    /// The pipeline cache to use when creating this pipeline.
413    pub cache: Option<Arc<PipelineCache>>,
414}
415
416#[derive(Clone, Debug)]
417#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
418pub struct PipelineCacheDescriptor<'a> {
419    pub label: Label<'a>,
420    pub data: Option<Cow<'a, [u8]>>,
421    pub fallback: bool,
422}
423
424#[derive(Clone, Debug, Error)]
425#[non_exhaustive]
426pub enum ColorStateError {
427    #[error("Format {0:?} is not renderable")]
428    FormatNotRenderable(wgt::TextureFormat),
429    #[error("Format {0:?} is not blendable")]
430    FormatNotBlendable(wgt::TextureFormat),
431    #[error("Format {0:?} does not have a color aspect")]
432    FormatNotColor(wgt::TextureFormat),
433    #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
434    InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
435    #[error("Output format {pipeline} is incompatible with the shader {shader}")]
436    IncompatibleFormat {
437        pipeline: validation::NumericType,
438        shader: validation::NumericType,
439    },
440    #[error("Invalid write mask {0:?}")]
441    InvalidWriteMask(wgt::ColorWrites),
442}
443
444#[derive(Clone, Debug, Error)]
445#[non_exhaustive]
446pub enum DepthStencilStateError {
447    #[error("Format {0:?} is not renderable")]
448    FormatNotRenderable(wgt::TextureFormat),
449    #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
450    FormatNotDepth(wgt::TextureFormat),
451    #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
452    FormatNotStencil(wgt::TextureFormat),
453    #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
454    InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
455}
456
457#[derive(Clone, Debug, Error)]
458#[non_exhaustive]
459pub enum CreateRenderPipelineError {
460    #[error(transparent)]
461    ColorAttachment(#[from] ColorAttachmentError),
462    #[error(transparent)]
463    Device(#[from] DeviceError),
464    #[error("Unable to derive an implicit layout")]
465    Implicit(#[from] ImplicitLayoutError),
466    #[error("Color state [{0}] is invalid")]
467    ColorState(u8, #[source] ColorStateError),
468    #[error("Depth/stencil state is invalid")]
469    DepthStencilState(#[from] DepthStencilStateError),
470    #[error("Invalid sample count {0}")]
471    InvalidSampleCount(u32),
472    #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
473    TooManyVertexBuffers { given: u32, limit: u32 },
474    #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
475    TooManyVertexAttributes { given: u32, limit: u32 },
476    #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
477    VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
478    #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
479    VertexAttributeStrideTooLarge {
480        location: wgt::ShaderLocation,
481        given: u32,
482        limit: u32,
483    },
484    #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
485    UnalignedVertexStride {
486        index: u32,
487        stride: wgt::BufferAddress,
488    },
489    #[error("Vertex attribute at location {location} has invalid offset {offset}")]
490    InvalidVertexAttributeOffset {
491        location: wgt::ShaderLocation,
492        offset: wgt::BufferAddress,
493    },
494    #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
495    ShaderLocationClash(u32),
496    #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
497    StripIndexFormatForNonStripTopology {
498        strip_index_format: Option<wgt::IndexFormat>,
499        topology: wgt::PrimitiveTopology,
500    },
501    #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
502    ConservativeRasterizationNonFillPolygonMode,
503    #[error(transparent)]
504    MissingFeatures(#[from] MissingFeatures),
505    #[error(transparent)]
506    MissingDownlevelFlags(#[from] MissingDownlevelFlags),
507    #[error("Error matching {stage:?} shader requirements against the pipeline")]
508    Stage {
509        stage: wgt::ShaderStages,
510        #[source]
511        error: validation::StageError,
512    },
513    #[error("Internal error in {stage:?} shader: {error}")]
514    Internal {
515        stage: wgt::ShaderStages,
516        error: String,
517    },
518    #[error("Pipeline constant error in {stage:?} shader: {error}")]
519    PipelineConstants {
520        stage: wgt::ShaderStages,
521        error: String,
522    },
523    #[error("In the provided shader, the type given for group {group} binding {binding} has a size of {size}. As the device does not support `DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED`, the type must have a size that is a multiple of 16 bytes.")]
524    UnalignedShader { group: u32, binding: u32, size: u64 },
525    #[error("Using the blend factor {factor:?} for render target {target} is not possible. Only the first render target may be used when dual-source blending.")]
526    BlendFactorOnUnsupportedTarget {
527        factor: wgt::BlendFactor,
528        target: u32,
529    },
530    #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
531    PipelineExpectsShaderToUseDualSourceBlending,
532    #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
533    ShaderExpectsPipelineToUseDualSourceBlending,
534    #[error("{}", concat!(
535        "At least one color attachment or depth-stencil attachment was expected, ",
536        "but no render target for the pipeline was specified."
537    ))]
538    NoTargetSpecified,
539    #[error(transparent)]
540    InvalidResource(#[from] InvalidResourceError),
541}
542
543bitflags::bitflags! {
544    #[repr(transparent)]
545    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
546    pub struct PipelineFlags: u32 {
547        const BLEND_CONSTANT = 1 << 0;
548        const STENCIL_REFERENCE = 1 << 1;
549        const WRITES_DEPTH = 1 << 2;
550        const WRITES_STENCIL = 1 << 3;
551    }
552}
553
554/// How a render pipeline will retrieve attributes from a particular vertex buffer.
555#[derive(Clone, Copy, Debug)]
556pub struct VertexStep {
557    /// The byte stride in the buffer between one attribute value and the next.
558    pub stride: wgt::BufferAddress,
559
560    /// The byte size required to fit the last vertex in the stream.
561    pub last_stride: wgt::BufferAddress,
562
563    /// Whether the buffer is indexed by vertex number or instance number.
564    pub mode: wgt::VertexStepMode,
565}
566
567impl Default for VertexStep {
568    fn default() -> Self {
569        Self {
570            stride: 0,
571            last_stride: 0,
572            mode: wgt::VertexStepMode::Vertex,
573        }
574    }
575}
576
577#[derive(Debug)]
578pub struct RenderPipeline {
579    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
580    pub(crate) device: Arc<Device>,
581    pub(crate) layout: Arc<PipelineLayout>,
582    pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
583    pub(crate) pass_context: RenderPassContext,
584    pub(crate) flags: PipelineFlags,
585    pub(crate) strip_index_format: Option<wgt::IndexFormat>,
586    pub(crate) vertex_steps: Vec<VertexStep>,
587    pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
588    /// The `label` from the descriptor used to create the resource.
589    pub(crate) label: String,
590    pub(crate) tracking_data: TrackingData,
591}
592
593impl Drop for RenderPipeline {
594    fn drop(&mut self) {
595        resource_log!("Destroy raw {}", self.error_ident());
596        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
597        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
598        unsafe {
599            self.device.raw().destroy_render_pipeline(raw);
600        }
601    }
602}
603
604crate::impl_resource_type!(RenderPipeline);
605crate::impl_labeled!(RenderPipeline);
606crate::impl_parent_device!(RenderPipeline);
607crate::impl_storage_item!(RenderPipeline);
608crate::impl_trackable!(RenderPipeline);
609
610impl RenderPipeline {
611    pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
612        self.raw.as_ref()
613    }
614}