1use alloc::{
2 borrow::Cow,
3 boxed::Box,
4 string::{String, ToString as _},
5 sync::Arc,
6 vec::Vec,
7};
8use core::{marker::PhantomData, mem::ManuallyDrop, num::NonZeroU32};
9
10use arrayvec::ArrayVec;
11use naga::error::ShaderError;
12use thiserror::Error;
13use wgt::error::{ErrorType, WebGpuError};
14
15pub use crate::pipeline_cache::PipelineCacheValidationError;
16use crate::{
17 binding_model::{
18 BindGroupLayout, CreateBindGroupLayoutError, CreatePipelineLayoutError,
19 GetBindGroupLayoutError, PipelineLayout,
20 },
21 command::ColorAttachmentError,
22 device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext},
23 id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId},
24 resource::{InvalidResourceError, Labeled, TrackingData},
25 resource_log, validation, Label,
26};
27
28#[derive(Debug)]
32pub(crate) struct LateSizedBufferGroup {
33 pub(crate) shader_sizes: Vec<wgt::BufferAddress>,
35}
36
37#[allow(clippy::large_enum_variant)]
38pub enum ShaderModuleSource<'a> {
39 #[cfg(feature = "wgsl")]
40 Wgsl(Cow<'a, str>),
41 #[cfg(feature = "glsl")]
42 Glsl(Cow<'a, str>, naga::front::glsl::Options),
43 #[cfg(feature = "spirv")]
44 SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
45 Naga(Cow<'static, naga::Module>),
46 #[doc(hidden)]
49 Dummy(PhantomData<&'a ()>),
50}
51
52#[derive(Clone, Debug)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
54pub struct ShaderModuleDescriptor<'a> {
55 pub label: Label<'a>,
56 #[cfg_attr(feature = "serde", serde(default))]
57 pub runtime_checks: wgt::ShaderRuntimeChecks,
58}
59
60pub type ShaderModuleDescriptorPassthrough<'a> =
61 wgt::CreateShaderModuleDescriptorPassthrough<'a, Label<'a>>;
62
63#[derive(Debug)]
64pub struct ShaderModule {
65 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynShaderModule>>,
66 pub(crate) device: Arc<Device>,
67 pub(crate) interface: Option<validation::Interface>,
68 pub(crate) label: String,
70}
71
72impl Drop for ShaderModule {
73 fn drop(&mut self) {
74 resource_log!("Destroy raw {}", self.error_ident());
75 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
77 unsafe {
78 self.device.raw().destroy_shader_module(raw);
79 }
80 }
81}
82
83crate::impl_resource_type!(ShaderModule);
84crate::impl_labeled!(ShaderModule);
85crate::impl_parent_device!(ShaderModule);
86crate::impl_storage_item!(ShaderModule);
87
88impl ShaderModule {
89 pub(crate) fn raw(&self) -> &dyn hal::DynShaderModule {
90 self.raw.as_ref()
91 }
92
93 pub(crate) fn finalize_entry_point_name(
94 &self,
95 stage: naga::ShaderStage,
96 entry_point: Option<&str>,
97 ) -> Result<String, validation::StageError> {
98 match &self.interface {
99 Some(interface) => interface.finalize_entry_point_name(stage, entry_point),
100 None => entry_point
101 .map(|ep| ep.to_string())
102 .ok_or(validation::StageError::NoEntryPointFound),
103 }
104 }
105}
106
107#[derive(Clone, Debug, Error)]
109#[non_exhaustive]
110pub enum CreateShaderModuleError {
111 #[cfg(feature = "wgsl")]
112 #[error(transparent)]
113 Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
114 #[cfg(feature = "glsl")]
115 #[error(transparent)]
116 ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
117 #[cfg(feature = "spirv")]
118 #[error(transparent)]
119 ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
120 #[error("Failed to generate the backend-specific code")]
121 Generation,
122 #[error(transparent)]
123 Device(#[from] DeviceError),
124 #[error(transparent)]
125 Validation(#[from] ShaderError<naga::WithSpan<naga::valid::ValidationError>>),
126 #[error(transparent)]
127 MissingFeatures(#[from] MissingFeatures),
128 #[error(
129 "Shader global {bind:?} uses a group index {group} that exceeds the max_bind_groups limit of {limit}."
130 )]
131 InvalidGroupIndex {
132 bind: naga::ResourceBinding,
133 group: u32,
134 limit: u32,
135 },
136 #[error("Generic shader passthrough does not contain any code compatible with this backend.")]
137 NotCompiledForBackend,
138}
139
140impl WebGpuError for CreateShaderModuleError {
141 fn webgpu_error_type(&self) -> ErrorType {
142 let e: &dyn WebGpuError = match self {
143 Self::Device(e) => e,
144 Self::MissingFeatures(e) => e,
145
146 Self::Generation => return ErrorType::Internal,
147
148 Self::Validation(..) | Self::InvalidGroupIndex { .. } => return ErrorType::Validation,
149 #[cfg(feature = "wgsl")]
150 Self::Parsing(..) => return ErrorType::Validation,
151 #[cfg(feature = "glsl")]
152 Self::ParsingGlsl(..) => return ErrorType::Validation,
153 #[cfg(feature = "spirv")]
154 Self::ParsingSpirV(..) => return ErrorType::Validation,
155 Self::NotCompiledForBackend => return ErrorType::Validation,
156 };
157 e.webgpu_error_type()
158 }
159}
160
161#[derive(Clone, Debug)]
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
165 pub module: SM,
167 pub entry_point: Option<Cow<'a, str>>,
174 pub constants: naga::back::PipelineConstants,
182 pub zero_initialize_workgroup_memory: bool,
187}
188
189pub type ResolvedProgrammableStageDescriptor<'a> =
191 ProgrammableStageDescriptor<'a, Arc<ShaderModule>>;
192
193pub type ImplicitBindGroupCount = u8;
195
196#[derive(Clone, Debug, Error)]
197#[non_exhaustive]
198pub enum ImplicitLayoutError {
199 #[error("Unable to reflect the shader {0:?} interface")]
200 ReflectionError(wgt::ShaderStages),
201 #[error(transparent)]
202 BindGroup(#[from] CreateBindGroupLayoutError),
203 #[error(transparent)]
204 Pipeline(#[from] CreatePipelineLayoutError),
205}
206
207impl WebGpuError for ImplicitLayoutError {
208 fn webgpu_error_type(&self) -> ErrorType {
209 let e: &dyn WebGpuError = match self {
210 Self::ReflectionError(_) => return ErrorType::Validation,
211 Self::BindGroup(e) => e,
212 Self::Pipeline(e) => e,
213 };
214 e.webgpu_error_type()
215 }
216}
217
218#[derive(Clone, Debug)]
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221pub struct ComputePipelineDescriptor<
222 'a,
223 PLL = PipelineLayoutId,
224 SM = ShaderModuleId,
225 PLC = PipelineCacheId,
226> {
227 pub label: Label<'a>,
228 pub layout: Option<PLL>,
230 pub stage: ProgrammableStageDescriptor<'a, SM>,
232 pub cache: Option<PLC>,
234}
235
236pub type ResolvedComputePipelineDescriptor<'a> =
238 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
239
240#[derive(Clone, Debug, Error)]
241#[non_exhaustive]
242pub enum CreateComputePipelineError {
243 #[error(transparent)]
244 Device(#[from] DeviceError),
245 #[error("Unable to derive an implicit layout")]
246 Implicit(#[from] ImplicitLayoutError),
247 #[error("Error matching shader requirements against the pipeline")]
248 Stage(#[from] validation::StageError),
249 #[error("Internal error: {0}")]
250 Internal(String),
251 #[error("Pipeline constant error: {0}")]
252 PipelineConstants(String),
253 #[error(transparent)]
254 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
255 #[error(transparent)]
256 InvalidResource(#[from] InvalidResourceError),
257}
258
259impl WebGpuError for CreateComputePipelineError {
260 fn webgpu_error_type(&self) -> ErrorType {
261 let e: &dyn WebGpuError = match self {
262 Self::Device(e) => e,
263 Self::InvalidResource(e) => e,
264 Self::MissingDownlevelFlags(e) => e,
265 Self::Implicit(e) => e,
266 Self::Stage(e) => e,
267 Self::Internal(_) => return ErrorType::Internal,
268 Self::PipelineConstants(_) => return ErrorType::Validation,
269 };
270 e.webgpu_error_type()
271 }
272}
273
274#[derive(Debug)]
275pub struct ComputePipeline {
276 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
277 pub(crate) layout: Arc<PipelineLayout>,
278 pub(crate) device: Arc<Device>,
279 pub(crate) _shader_module: Arc<ShaderModule>,
280 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
281 pub(crate) label: String,
283 pub(crate) tracking_data: TrackingData,
284}
285
286impl Drop for ComputePipeline {
287 fn drop(&mut self) {
288 resource_log!("Destroy raw {}", self.error_ident());
289 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
291 unsafe {
292 self.device.raw().destroy_compute_pipeline(raw);
293 }
294 }
295}
296
297crate::impl_resource_type!(ComputePipeline);
298crate::impl_labeled!(ComputePipeline);
299crate::impl_parent_device!(ComputePipeline);
300crate::impl_storage_item!(ComputePipeline);
301crate::impl_trackable!(ComputePipeline);
302
303impl ComputePipeline {
304 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
305 self.raw.as_ref()
306 }
307
308 pub fn get_bind_group_layout(
309 self: &Arc<Self>,
310 index: u32,
311 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
312 self.layout
313 .bind_group_layouts
314 .get(index as usize)
315 .cloned()
316 .ok_or(GetBindGroupLayoutError::InvalidGroupIndex(index))
317 }
318}
319
320#[derive(Clone, Debug, Error)]
321#[non_exhaustive]
322pub enum CreatePipelineCacheError {
323 #[error(transparent)]
324 Device(#[from] DeviceError),
325 #[error("Pipeline cache validation failed")]
326 Validation(#[from] PipelineCacheValidationError),
327 #[error(transparent)]
328 MissingFeatures(#[from] MissingFeatures),
329}
330
331impl WebGpuError for CreatePipelineCacheError {
332 fn webgpu_error_type(&self) -> ErrorType {
333 let e: &dyn WebGpuError = match self {
334 Self::Device(e) => e,
335 Self::Validation(e) => e,
336 Self::MissingFeatures(e) => e,
337 };
338 e.webgpu_error_type()
339 }
340}
341
342#[derive(Debug)]
343pub struct PipelineCache {
344 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
345 pub(crate) device: Arc<Device>,
346 pub(crate) label: String,
348}
349
350impl Drop for PipelineCache {
351 fn drop(&mut self) {
352 resource_log!("Destroy raw {}", self.error_ident());
353 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
355 unsafe {
356 self.device.raw().destroy_pipeline_cache(raw);
357 }
358 }
359}
360
361crate::impl_resource_type!(PipelineCache);
362crate::impl_labeled!(PipelineCache);
363crate::impl_parent_device!(PipelineCache);
364crate::impl_storage_item!(PipelineCache);
365
366impl PipelineCache {
367 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
368 self.raw.as_ref()
369 }
370}
371
372#[derive(Clone, Debug)]
374#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
375#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
376pub struct VertexBufferLayout<'a> {
377 pub array_stride: wgt::BufferAddress,
379 pub step_mode: wgt::VertexStepMode,
381 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
383}
384
385impl Default for VertexBufferLayout<'_> {
387 fn default() -> Self {
388 Self {
389 array_stride: Default::default(),
390 step_mode: Default::default(),
391 attributes: Cow::Borrowed(&[]),
392 }
393 }
394}
395
396#[derive(Clone, Debug)]
398#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
399pub struct VertexState<'a, SM = ShaderModuleId> {
400 pub stage: ProgrammableStageDescriptor<'a, SM>,
402 pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
404}
405
406pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
408
409#[derive(Clone, Debug)]
411#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
412pub struct FragmentState<'a, SM = ShaderModuleId> {
413 pub stage: ProgrammableStageDescriptor<'a, SM>,
415 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
417}
418
419pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
421
422#[derive(Clone, Debug)]
424#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
425pub struct TaskState<'a, SM = ShaderModuleId> {
426 pub stage: ProgrammableStageDescriptor<'a, SM>,
428}
429
430pub type ResolvedTaskState<'a> = TaskState<'a, Arc<ShaderModule>>;
431
432#[derive(Clone, Debug)]
434#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
435pub struct MeshState<'a, SM = ShaderModuleId> {
436 pub stage: ProgrammableStageDescriptor<'a, SM>,
438}
439
440pub type ResolvedMeshState<'a> = MeshState<'a, Arc<ShaderModule>>;
441
442#[doc(hidden)]
450#[derive(Clone, Debug)]
451#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
452pub enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> {
453 Vertex(VertexState<'a, SM>),
454 Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>),
455}
456
457#[derive(Clone, Debug)]
459#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
460pub struct RenderPipelineDescriptor<
461 'a,
462 PLL = PipelineLayoutId,
463 SM = ShaderModuleId,
464 PLC = PipelineCacheId,
465> {
466 pub label: Label<'a>,
467 pub layout: Option<PLL>,
469 pub vertex: VertexState<'a, SM>,
471 #[cfg_attr(feature = "serde", serde(default))]
473 pub primitive: wgt::PrimitiveState,
474 #[cfg_attr(feature = "serde", serde(default))]
476 pub depth_stencil: Option<wgt::DepthStencilState>,
477 #[cfg_attr(feature = "serde", serde(default))]
479 pub multisample: wgt::MultisampleState,
480 pub fragment: Option<FragmentState<'a, SM>>,
482 pub multiview_mask: Option<NonZeroU32>,
485 pub cache: Option<PLC>,
487}
488#[derive(Clone, Debug)]
490#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
491pub struct MeshPipelineDescriptor<
492 'a,
493 PLL = PipelineLayoutId,
494 SM = ShaderModuleId,
495 PLC = PipelineCacheId,
496> {
497 pub label: Label<'a>,
498 pub layout: Option<PLL>,
500 pub task: Option<TaskState<'a, SM>>,
502 pub mesh: MeshState<'a, SM>,
504 #[cfg_attr(feature = "serde", serde(default))]
506 pub primitive: wgt::PrimitiveState,
507 #[cfg_attr(feature = "serde", serde(default))]
509 pub depth_stencil: Option<wgt::DepthStencilState>,
510 #[cfg_attr(feature = "serde", serde(default))]
512 pub multisample: wgt::MultisampleState,
513 pub fragment: Option<FragmentState<'a, SM>>,
515 pub multiview: Option<NonZeroU32>,
518 pub cache: Option<PLC>,
520}
521
522#[doc(hidden)]
530#[derive(Clone, Debug)]
531#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
532pub struct GeneralRenderPipelineDescriptor<
533 'a,
534 PLL = PipelineLayoutId,
535 SM = ShaderModuleId,
536 PLC = PipelineCacheId,
537> {
538 pub label: Label<'a>,
539 pub layout: Option<PLL>,
541 pub vertex: RenderPipelineVertexProcessor<'a, SM>,
543 #[cfg_attr(feature = "serde", serde(default))]
545 pub primitive: wgt::PrimitiveState,
546 #[cfg_attr(feature = "serde", serde(default))]
548 pub depth_stencil: Option<wgt::DepthStencilState>,
549 #[cfg_attr(feature = "serde", serde(default))]
551 pub multisample: wgt::MultisampleState,
552 pub fragment: Option<FragmentState<'a, SM>>,
554 pub multiview_mask: Option<NonZeroU32>,
557 pub cache: Option<PLC>,
559}
560impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
561 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
562{
563 fn from(value: RenderPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
564 Self {
565 label: value.label,
566 layout: value.layout,
567 vertex: RenderPipelineVertexProcessor::Vertex(value.vertex),
568 primitive: value.primitive,
569 depth_stencil: value.depth_stencil,
570 multisample: value.multisample,
571 fragment: value.fragment,
572 multiview_mask: value.multiview_mask,
573 cache: value.cache,
574 }
575 }
576}
577impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
578 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
579{
580 fn from(value: MeshPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
581 Self {
582 label: value.label,
583 layout: value.layout,
584 vertex: RenderPipelineVertexProcessor::Mesh(value.task, value.mesh),
585 primitive: value.primitive,
586 depth_stencil: value.depth_stencil,
587 multisample: value.multisample,
588 fragment: value.fragment,
589 multiview_mask: value.multiview,
590 cache: value.cache,
591 }
592 }
593}
594
595pub type ResolvedGeneralRenderPipelineDescriptor<'a> =
599 GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
600
601#[derive(Clone, Debug)]
602#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
603pub struct PipelineCacheDescriptor<'a> {
604 pub label: Label<'a>,
605 pub data: Option<Cow<'a, [u8]>>,
606 pub fallback: bool,
607}
608
609#[derive(Clone, Debug, Error)]
610#[non_exhaustive]
611pub enum ColorStateError {
612 #[error("Format {0:?} is not renderable")]
613 FormatNotRenderable(wgt::TextureFormat),
614 #[error("Format {0:?} is not blendable")]
615 FormatNotBlendable(wgt::TextureFormat),
616 #[error("Format {0:?} does not have a color aspect")]
617 FormatNotColor(wgt::TextureFormat),
618 #[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:?}.")]
619 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
620 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
621 IncompatibleFormat {
622 pipeline: validation::NumericType,
623 shader: validation::NumericType,
624 },
625 #[error("Invalid write mask {0:?}")]
626 InvalidWriteMask(wgt::ColorWrites),
627}
628
629#[derive(Clone, Debug, Error)]
630#[non_exhaustive]
631pub enum DepthStencilStateError {
632 #[error("Format {0:?} is not renderable")]
633 FormatNotRenderable(wgt::TextureFormat),
634 #[error("Format {0:?} is not a depth/stencil format")]
635 FormatNotDepthOrStencil(wgt::TextureFormat),
636 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
637 FormatNotDepth(wgt::TextureFormat),
638 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
639 FormatNotStencil(wgt::TextureFormat),
640 #[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:?}.")]
641 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
642}
643
644#[derive(Clone, Debug, Error)]
645#[non_exhaustive]
646pub enum CreateRenderPipelineError {
647 #[error(transparent)]
648 ColorAttachment(#[from] ColorAttachmentError),
649 #[error(transparent)]
650 Device(#[from] DeviceError),
651 #[error("Unable to derive an implicit layout")]
652 Implicit(#[from] ImplicitLayoutError),
653 #[error("Color state [{0}] is invalid")]
654 ColorState(u8, #[source] ColorStateError),
655 #[error("Depth/stencil state is invalid")]
656 DepthStencilState(#[from] DepthStencilStateError),
657 #[error("Invalid sample count {0}")]
658 InvalidSampleCount(u32),
659 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
660 TooManyVertexBuffers { given: u32, limit: u32 },
661 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
662 TooManyVertexAttributes { given: u32, limit: u32 },
663 #[error("Vertex attribute location {given} must be less than limit {limit}")]
664 VertexAttributeLocationTooLarge { given: u32, limit: u32 },
665 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
666 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
667 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
668 VertexAttributeStrideTooLarge {
669 location: wgt::ShaderLocation,
670 given: u32,
671 limit: u32,
672 },
673 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
674 UnalignedVertexStride {
675 index: u32,
676 stride: wgt::BufferAddress,
677 },
678 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
679 InvalidVertexAttributeOffset {
680 location: wgt::ShaderLocation,
681 offset: wgt::BufferAddress,
682 },
683 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
684 ShaderLocationClash(u32),
685 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
686 StripIndexFormatForNonStripTopology {
687 strip_index_format: Option<wgt::IndexFormat>,
688 topology: wgt::PrimitiveTopology,
689 },
690 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
691 ConservativeRasterizationNonFillPolygonMode,
692 #[error(transparent)]
693 MissingFeatures(#[from] MissingFeatures),
694 #[error(transparent)]
695 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
696 #[error("Error matching {stage:?} shader requirements against the pipeline")]
697 Stage {
698 stage: wgt::ShaderStages,
699 #[source]
700 error: validation::StageError,
701 },
702 #[error("Internal error in {stage:?} shader: {error}")]
703 Internal {
704 stage: wgt::ShaderStages,
705 error: String,
706 },
707 #[error("Pipeline constant error in {stage:?} shader: {error}")]
708 PipelineConstants {
709 stage: wgt::ShaderStages,
710 error: String,
711 },
712 #[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.")]
713 UnalignedShader { group: u32, binding: u32, size: u64 },
714 #[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.")]
715 BlendFactorOnUnsupportedTarget {
716 factor: wgt::BlendFactor,
717 target: u32,
718 },
719 #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
720 PipelineExpectsShaderToUseDualSourceBlending,
721 #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
722 ShaderExpectsPipelineToUseDualSourceBlending,
723 #[error("{}", concat!(
724 "At least one color attachment or depth-stencil attachment was expected, ",
725 "but no render target for the pipeline was specified."
726 ))]
727 NoTargetSpecified,
728 #[error(transparent)]
729 InvalidResource(#[from] InvalidResourceError),
730}
731
732impl WebGpuError for CreateRenderPipelineError {
733 fn webgpu_error_type(&self) -> ErrorType {
734 let e: &dyn WebGpuError = match self {
735 Self::Device(e) => e,
736 Self::InvalidResource(e) => e,
737 Self::MissingFeatures(e) => e,
738 Self::MissingDownlevelFlags(e) => e,
739
740 Self::Internal { .. } => return ErrorType::Internal,
741
742 Self::ColorAttachment(_)
743 | Self::Implicit(_)
744 | Self::ColorState(_, _)
745 | Self::DepthStencilState(_)
746 | Self::InvalidSampleCount(_)
747 | Self::TooManyVertexBuffers { .. }
748 | Self::TooManyVertexAttributes { .. }
749 | Self::VertexAttributeLocationTooLarge { .. }
750 | Self::VertexStrideTooLarge { .. }
751 | Self::UnalignedVertexStride { .. }
752 | Self::InvalidVertexAttributeOffset { .. }
753 | Self::ShaderLocationClash(_)
754 | Self::StripIndexFormatForNonStripTopology { .. }
755 | Self::ConservativeRasterizationNonFillPolygonMode
756 | Self::Stage { .. }
757 | Self::UnalignedShader { .. }
758 | Self::BlendFactorOnUnsupportedTarget { .. }
759 | Self::PipelineExpectsShaderToUseDualSourceBlending
760 | Self::ShaderExpectsPipelineToUseDualSourceBlending
761 | Self::NoTargetSpecified
762 | Self::PipelineConstants { .. }
763 | Self::VertexAttributeStrideTooLarge { .. } => return ErrorType::Validation,
764 };
765 e.webgpu_error_type()
766 }
767}
768
769bitflags::bitflags! {
770 #[repr(transparent)]
771 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
772 pub struct PipelineFlags: u32 {
773 const BLEND_CONSTANT = 1 << 0;
774 const STENCIL_REFERENCE = 1 << 1;
775 const WRITES_DEPTH = 1 << 2;
776 const WRITES_STENCIL = 1 << 3;
777 }
778}
779
780#[derive(Clone, Copy, Debug)]
782pub struct VertexStep {
783 pub stride: wgt::BufferAddress,
785
786 pub last_stride: wgt::BufferAddress,
788
789 pub mode: wgt::VertexStepMode,
791}
792
793impl Default for VertexStep {
794 fn default() -> Self {
795 Self {
796 stride: 0,
797 last_stride: 0,
798 mode: wgt::VertexStepMode::Vertex,
799 }
800 }
801}
802
803#[derive(Debug)]
804pub struct RenderPipeline {
805 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
806 pub(crate) device: Arc<Device>,
807 pub(crate) layout: Arc<PipelineLayout>,
808 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
809 pub(crate) pass_context: RenderPassContext,
810 pub(crate) flags: PipelineFlags,
811 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
812 pub(crate) vertex_steps: Vec<VertexStep>,
813 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
814 pub(crate) label: String,
816 pub(crate) tracking_data: TrackingData,
817 pub(crate) is_mesh: bool,
819}
820
821impl Drop for RenderPipeline {
822 fn drop(&mut self) {
823 resource_log!("Destroy raw {}", self.error_ident());
824 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
826 unsafe {
827 self.device.raw().destroy_render_pipeline(raw);
828 }
829 }
830}
831
832crate::impl_resource_type!(RenderPipeline);
833crate::impl_labeled!(RenderPipeline);
834crate::impl_parent_device!(RenderPipeline);
835crate::impl_storage_item!(RenderPipeline);
836crate::impl_trackable!(RenderPipeline);
837
838impl RenderPipeline {
839 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
840 self.raw.as_ref()
841 }
842
843 pub fn get_bind_group_layout(
844 self: &Arc<Self>,
845 index: u32,
846 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
847 self.layout
848 .bind_group_layouts
849 .get(index as usize)
850 .cloned()
851 .ok_or(GetBindGroupLayoutError::InvalidGroupIndex(index))
852 }
853}