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