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, Default)]
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 #[error("Unable to create implicit pipeline layout from passthrough shader stage: {0:?}")]
206 Passthrough(wgt::ShaderStages),
207}
208
209impl WebGpuError for ImplicitLayoutError {
210 fn webgpu_error_type(&self) -> ErrorType {
211 let e: &dyn WebGpuError = match self {
212 Self::ReflectionError(_) => return ErrorType::Validation,
213 Self::BindGroup(e) => e,
214 Self::Pipeline(e) => e,
215 Self::Passthrough(_) => return ErrorType::Validation,
216 };
217 e.webgpu_error_type()
218 }
219}
220
221#[derive(Clone, Debug)]
223#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
224pub struct ComputePipelineDescriptor<
225 'a,
226 PLL = PipelineLayoutId,
227 SM = ShaderModuleId,
228 PLC = PipelineCacheId,
229> {
230 pub label: Label<'a>,
231 pub layout: Option<PLL>,
233 pub stage: ProgrammableStageDescriptor<'a, SM>,
235 pub cache: Option<PLC>,
237}
238
239pub type ResolvedComputePipelineDescriptor<'a> =
241 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
242
243#[derive(Clone, Debug, Error)]
244#[non_exhaustive]
245pub enum CreateComputePipelineError {
246 #[error(transparent)]
247 Device(#[from] DeviceError),
248 #[error("Unable to derive an implicit layout")]
249 Implicit(#[from] ImplicitLayoutError),
250 #[error("Error matching shader requirements against the pipeline")]
251 Stage(#[from] validation::StageError),
252 #[error("Internal error: {0}")]
253 Internal(String),
254 #[error("Pipeline constant error: {0}")]
255 PipelineConstants(String),
256 #[error(transparent)]
257 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
258 #[error(transparent)]
259 InvalidResource(#[from] InvalidResourceError),
260}
261
262impl WebGpuError for CreateComputePipelineError {
263 fn webgpu_error_type(&self) -> ErrorType {
264 let e: &dyn WebGpuError = match self {
265 Self::Device(e) => e,
266 Self::InvalidResource(e) => e,
267 Self::MissingDownlevelFlags(e) => e,
268 Self::Implicit(e) => e,
269 Self::Stage(e) => e,
270 Self::Internal(_) => return ErrorType::Internal,
271 Self::PipelineConstants(_) => return ErrorType::Validation,
272 };
273 e.webgpu_error_type()
274 }
275}
276
277#[derive(Debug)]
278pub struct ComputePipeline {
279 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
280 pub(crate) layout: Arc<PipelineLayout>,
281 pub(crate) device: Arc<Device>,
282 pub(crate) _shader_module: Arc<ShaderModule>,
283 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
284 pub(crate) label: String,
286 pub(crate) tracking_data: TrackingData,
287}
288
289impl Drop for ComputePipeline {
290 fn drop(&mut self) {
291 resource_log!("Destroy raw {}", self.error_ident());
292 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
294 unsafe {
295 self.device.raw().destroy_compute_pipeline(raw);
296 }
297 }
298}
299
300crate::impl_resource_type!(ComputePipeline);
301crate::impl_labeled!(ComputePipeline);
302crate::impl_parent_device!(ComputePipeline);
303crate::impl_storage_item!(ComputePipeline);
304crate::impl_trackable!(ComputePipeline);
305
306impl ComputePipeline {
307 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
308 self.raw.as_ref()
309 }
310
311 pub fn get_bind_group_layout(
312 self: &Arc<Self>,
313 index: u32,
314 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
315 self.layout.get_bind_group_layout(index)
316 }
317}
318
319#[derive(Clone, Debug, Error)]
320#[non_exhaustive]
321pub enum CreatePipelineCacheError {
322 #[error(transparent)]
323 Device(#[from] DeviceError),
324 #[error("Pipeline cache validation failed")]
325 Validation(#[from] PipelineCacheValidationError),
326 #[error(transparent)]
327 MissingFeatures(#[from] MissingFeatures),
328}
329
330impl WebGpuError for CreatePipelineCacheError {
331 fn webgpu_error_type(&self) -> ErrorType {
332 let e: &dyn WebGpuError = match self {
333 Self::Device(e) => e,
334 Self::Validation(e) => e,
335 Self::MissingFeatures(e) => e,
336 };
337 e.webgpu_error_type()
338 }
339}
340
341#[derive(Debug)]
342pub struct PipelineCache {
343 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
344 pub(crate) device: Arc<Device>,
345 pub(crate) label: String,
347}
348
349impl Drop for PipelineCache {
350 fn drop(&mut self) {
351 resource_log!("Destroy raw {}", self.error_ident());
352 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
354 unsafe {
355 self.device.raw().destroy_pipeline_cache(raw);
356 }
357 }
358}
359
360crate::impl_resource_type!(PipelineCache);
361crate::impl_labeled!(PipelineCache);
362crate::impl_parent_device!(PipelineCache);
363crate::impl_storage_item!(PipelineCache);
364
365impl PipelineCache {
366 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
367 self.raw.as_ref()
368 }
369}
370
371#[derive(Clone, Debug)]
373#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
374#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
375pub struct VertexBufferLayout<'a> {
376 pub array_stride: wgt::BufferAddress,
378 pub step_mode: wgt::VertexStepMode,
380 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
382}
383
384impl Default for VertexBufferLayout<'_> {
386 fn default() -> Self {
387 Self {
388 array_stride: Default::default(),
389 step_mode: Default::default(),
390 attributes: Cow::Borrowed(&[]),
391 }
392 }
393}
394
395#[derive(Clone, Debug)]
397#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
398pub struct VertexState<'a, SM = ShaderModuleId> {
399 pub stage: ProgrammableStageDescriptor<'a, SM>,
401 pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
403}
404
405pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
407
408#[derive(Clone, Debug)]
410#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
411pub struct FragmentState<'a, SM = ShaderModuleId> {
412 pub stage: ProgrammableStageDescriptor<'a, SM>,
414 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
416}
417
418pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
420
421#[derive(Clone, Debug)]
423#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
424pub struct TaskState<'a, SM = ShaderModuleId> {
425 pub stage: ProgrammableStageDescriptor<'a, SM>,
427}
428
429pub type ResolvedTaskState<'a> = TaskState<'a, Arc<ShaderModule>>;
430
431#[derive(Clone, Debug)]
433#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
434pub struct MeshState<'a, SM = ShaderModuleId> {
435 pub stage: ProgrammableStageDescriptor<'a, SM>,
437}
438
439pub type ResolvedMeshState<'a> = MeshState<'a, Arc<ShaderModule>>;
440
441#[doc(hidden)]
449#[derive(Clone, Debug)]
450#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
451pub enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> {
452 Vertex(VertexState<'a, SM>),
453 Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>),
454}
455
456#[derive(Clone, Debug)]
458#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
459pub struct RenderPipelineDescriptor<
460 'a,
461 PLL = PipelineLayoutId,
462 SM = ShaderModuleId,
463 PLC = PipelineCacheId,
464> {
465 pub label: Label<'a>,
466 pub layout: Option<PLL>,
468 pub vertex: VertexState<'a, SM>,
470 #[cfg_attr(feature = "serde", serde(default))]
472 pub primitive: wgt::PrimitiveState,
473 #[cfg_attr(feature = "serde", serde(default))]
475 pub depth_stencil: Option<wgt::DepthStencilState>,
476 #[cfg_attr(feature = "serde", serde(default))]
478 pub multisample: wgt::MultisampleState,
479 pub fragment: Option<FragmentState<'a, SM>>,
481 pub multiview_mask: Option<NonZeroU32>,
484 pub cache: Option<PLC>,
486}
487#[derive(Clone, Debug)]
489#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
490pub struct MeshPipelineDescriptor<
491 'a,
492 PLL = PipelineLayoutId,
493 SM = ShaderModuleId,
494 PLC = PipelineCacheId,
495> {
496 pub label: Label<'a>,
497 pub layout: Option<PLL>,
499 pub task: Option<TaskState<'a, SM>>,
501 pub mesh: MeshState<'a, SM>,
503 #[cfg_attr(feature = "serde", serde(default))]
505 pub primitive: wgt::PrimitiveState,
506 #[cfg_attr(feature = "serde", serde(default))]
508 pub depth_stencil: Option<wgt::DepthStencilState>,
509 #[cfg_attr(feature = "serde", serde(default))]
511 pub multisample: wgt::MultisampleState,
512 pub fragment: Option<FragmentState<'a, SM>>,
514 pub multiview: Option<NonZeroU32>,
517 pub cache: Option<PLC>,
519}
520
521#[doc(hidden)]
529#[derive(Clone, Debug)]
530#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
531pub struct GeneralRenderPipelineDescriptor<
532 'a,
533 PLL = PipelineLayoutId,
534 SM = ShaderModuleId,
535 PLC = PipelineCacheId,
536> {
537 pub label: Label<'a>,
538 pub layout: Option<PLL>,
540 pub vertex: RenderPipelineVertexProcessor<'a, SM>,
542 #[cfg_attr(feature = "serde", serde(default))]
544 pub primitive: wgt::PrimitiveState,
545 #[cfg_attr(feature = "serde", serde(default))]
547 pub depth_stencil: Option<wgt::DepthStencilState>,
548 #[cfg_attr(feature = "serde", serde(default))]
550 pub multisample: wgt::MultisampleState,
551 pub fragment: Option<FragmentState<'a, SM>>,
553 pub multiview_mask: Option<NonZeroU32>,
556 pub cache: Option<PLC>,
558}
559impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
560 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
561{
562 fn from(value: RenderPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
563 Self {
564 label: value.label,
565 layout: value.layout,
566 vertex: RenderPipelineVertexProcessor::Vertex(value.vertex),
567 primitive: value.primitive,
568 depth_stencil: value.depth_stencil,
569 multisample: value.multisample,
570 fragment: value.fragment,
571 multiview_mask: value.multiview_mask,
572 cache: value.cache,
573 }
574 }
575}
576impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
577 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
578{
579 fn from(value: MeshPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
580 Self {
581 label: value.label,
582 layout: value.layout,
583 vertex: RenderPipelineVertexProcessor::Mesh(value.task, value.mesh),
584 primitive: value.primitive,
585 depth_stencil: value.depth_stencil,
586 multisample: value.multisample,
587 fragment: value.fragment,
588 multiview_mask: value.multiview,
589 cache: value.cache,
590 }
591 }
592}
593
594pub type ResolvedGeneralRenderPipelineDescriptor<'a> =
598 GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
599
600#[derive(Clone, Debug)]
601#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
602pub struct PipelineCacheDescriptor<'a> {
603 pub label: Label<'a>,
604 pub data: Option<Cow<'a, [u8]>>,
605 pub fallback: bool,
606}
607
608#[derive(Clone, Debug, Error)]
609#[non_exhaustive]
610pub enum ColorStateError {
611 #[error("Format {0:?} is not renderable")]
612 FormatNotRenderable(wgt::TextureFormat),
613 #[error("Format {0:?} is not blendable")]
614 FormatNotBlendable(wgt::TextureFormat),
615 #[error("Format {0:?} does not have a color aspect")]
616 FormatNotColor(wgt::TextureFormat),
617 #[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:?}.")]
618 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
619 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
620 IncompatibleFormat {
621 pipeline: validation::NumericType,
622 shader: validation::NumericType,
623 },
624 #[error("Invalid write mask {0:?}")]
625 InvalidWriteMask(wgt::ColorWrites),
626 #[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.")]
627 BlendFactorOnUnsupportedTarget {
628 factor: wgt::BlendFactor,
629 target: u32,
630 },
631 #[error(
632 "Blend factor {factor:?} for render target {target} is not valid. Blend factor must be `one` when using min/max blend operations."
633 )]
634 InvalidMinMaxBlendFactor {
635 factor: wgt::BlendFactor,
636 target: u32,
637 },
638}
639
640#[derive(Clone, Debug, Error)]
641#[non_exhaustive]
642pub enum DepthStencilStateError {
643 #[error("Format {0:?} is not renderable")]
644 FormatNotRenderable(wgt::TextureFormat),
645 #[error("Format {0:?} is not a depth/stencil format")]
646 FormatNotDepthOrStencil(wgt::TextureFormat),
647 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
648 FormatNotDepth(wgt::TextureFormat),
649 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
650 FormatNotStencil(wgt::TextureFormat),
651 #[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:?}.")]
652 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
653 #[error("Depth bias is not compatible with non-triangle topology {0:?}")]
654 DepthBiasWithIncompatibleTopology(wgt::PrimitiveTopology),
655 #[error("Depth compare function must be specified for depth format {0:?}")]
656 MissingDepthCompare(wgt::TextureFormat),
657 #[error("Depth write enabled must be specified for depth format {0:?}")]
658 MissingDepthWriteEnabled(wgt::TextureFormat),
659}
660
661#[derive(Clone, Debug, Error)]
662#[non_exhaustive]
663pub enum CreateRenderPipelineError {
664 #[error(transparent)]
665 ColorAttachment(#[from] ColorAttachmentError),
666 #[error(transparent)]
667 Device(#[from] DeviceError),
668 #[error("Unable to derive an implicit layout")]
669 Implicit(#[from] ImplicitLayoutError),
670 #[error("Color state [{0}] is invalid")]
671 ColorState(u8, #[source] ColorStateError),
672 #[error("Depth/stencil state is invalid")]
673 DepthStencilState(#[from] DepthStencilStateError),
674 #[error("Invalid sample count {0}")]
675 InvalidSampleCount(u32),
676 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
677 TooManyVertexBuffers { given: u32, limit: u32 },
678 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
679 TooManyVertexAttributes { given: u32, limit: u32 },
680 #[error("Vertex attribute location {given} must be less than limit {limit}")]
681 VertexAttributeLocationTooLarge { given: u32, limit: u32 },
682 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
683 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
684 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
685 VertexAttributeStrideTooLarge {
686 location: wgt::ShaderLocation,
687 given: u32,
688 limit: u32,
689 },
690 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
691 UnalignedVertexStride {
692 index: u32,
693 stride: wgt::BufferAddress,
694 },
695 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
696 InvalidVertexAttributeOffset {
697 location: wgt::ShaderLocation,
698 offset: wgt::BufferAddress,
699 },
700 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
701 ShaderLocationClash(u32),
702 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
703 StripIndexFormatForNonStripTopology {
704 strip_index_format: Option<wgt::IndexFormat>,
705 topology: wgt::PrimitiveTopology,
706 },
707 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
708 ConservativeRasterizationNonFillPolygonMode,
709 #[error(transparent)]
710 MissingFeatures(#[from] MissingFeatures),
711 #[error(transparent)]
712 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
713 #[error("Error matching {stage:?} shader requirements against the pipeline")]
714 Stage {
715 stage: wgt::ShaderStages,
716 #[source]
717 error: validation::StageError,
718 },
719 #[error("Internal error in {stage:?} shader: {error}")]
720 Internal {
721 stage: wgt::ShaderStages,
722 error: String,
723 },
724 #[error("Pipeline constant error in {stage:?} shader: {error}")]
725 PipelineConstants {
726 stage: wgt::ShaderStages,
727 error: String,
728 },
729 #[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.")]
730 UnalignedShader { group: u32, binding: u32, size: u64 },
731 #[error("{}", concat!(
732 "At least one color attachment or depth-stencil attachment was expected, ",
733 "but no render target for the pipeline was specified."
734 ))]
735 NoTargetSpecified,
736 #[error(transparent)]
737 InvalidResource(#[from] InvalidResourceError),
738}
739
740impl WebGpuError for CreateRenderPipelineError {
741 fn webgpu_error_type(&self) -> ErrorType {
742 let e: &dyn WebGpuError = match self {
743 Self::Device(e) => e,
744 Self::InvalidResource(e) => e,
745 Self::MissingFeatures(e) => e,
746 Self::MissingDownlevelFlags(e) => e,
747
748 Self::Internal { .. } => return ErrorType::Internal,
749
750 Self::ColorAttachment(_)
751 | Self::Implicit(_)
752 | Self::ColorState(_, _)
753 | Self::DepthStencilState(_)
754 | Self::InvalidSampleCount(_)
755 | Self::TooManyVertexBuffers { .. }
756 | Self::TooManyVertexAttributes { .. }
757 | Self::VertexAttributeLocationTooLarge { .. }
758 | Self::VertexStrideTooLarge { .. }
759 | Self::UnalignedVertexStride { .. }
760 | Self::InvalidVertexAttributeOffset { .. }
761 | Self::ShaderLocationClash(_)
762 | Self::StripIndexFormatForNonStripTopology { .. }
763 | Self::ConservativeRasterizationNonFillPolygonMode
764 | Self::Stage { .. }
765 | Self::UnalignedShader { .. }
766 | Self::NoTargetSpecified
767 | Self::PipelineConstants { .. }
768 | Self::VertexAttributeStrideTooLarge { .. } => return ErrorType::Validation,
769 };
770 e.webgpu_error_type()
771 }
772}
773
774bitflags::bitflags! {
775 #[repr(transparent)]
776 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
777 pub struct PipelineFlags: u32 {
778 const BLEND_CONSTANT = 1 << 0;
779 const STENCIL_REFERENCE = 1 << 1;
780 const WRITES_DEPTH = 1 << 2;
781 const WRITES_STENCIL = 1 << 3;
782 }
783}
784
785#[derive(Clone, Copy, Debug)]
787pub struct VertexStep {
788 pub stride: wgt::BufferAddress,
790
791 pub last_stride: wgt::BufferAddress,
793
794 pub mode: wgt::VertexStepMode,
796}
797
798impl Default for VertexStep {
799 fn default() -> Self {
800 Self {
801 stride: 0,
802 last_stride: 0,
803 mode: wgt::VertexStepMode::Vertex,
804 }
805 }
806}
807
808#[derive(Debug)]
809pub struct RenderPipeline {
810 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
811 pub(crate) device: Arc<Device>,
812 pub(crate) layout: Arc<PipelineLayout>,
813 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
814 pub(crate) pass_context: RenderPassContext,
815 pub(crate) flags: PipelineFlags,
816 pub(crate) topology: wgt::PrimitiveTopology,
817 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
818 pub(crate) vertex_steps: Vec<VertexStep>,
819 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
820 pub(crate) label: String,
822 pub(crate) tracking_data: TrackingData,
823 pub(crate) is_mesh: bool,
825}
826
827impl Drop for RenderPipeline {
828 fn drop(&mut self) {
829 resource_log!("Destroy raw {}", self.error_ident());
830 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
832 unsafe {
833 self.device.raw().destroy_render_pipeline(raw);
834 }
835 }
836}
837
838crate::impl_resource_type!(RenderPipeline);
839crate::impl_labeled!(RenderPipeline);
840crate::impl_parent_device!(RenderPipeline);
841crate::impl_storage_item!(RenderPipeline);
842crate::impl_trackable!(RenderPipeline);
843
844impl RenderPipeline {
845 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
846 self.raw.as_ref()
847 }
848
849 pub fn get_bind_group_layout(
850 self: &Arc<Self>,
851 index: u32,
852 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
853 self.layout.get_bind_group_layout(index)
854 }
855}