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#[derive(Clone, Debug)]
429#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
430pub(crate) enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> {
431 Vertex(VertexState<'a, SM>),
432 Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>),
433}
434
435#[derive(Clone, Debug)]
437#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
438pub struct RenderPipelineDescriptor<
439 'a,
440 PLL = PipelineLayoutId,
441 SM = ShaderModuleId,
442 PLC = PipelineCacheId,
443> {
444 pub label: Label<'a>,
445 pub layout: Option<PLL>,
447 pub vertex: VertexState<'a, SM>,
449 #[cfg_attr(feature = "serde", serde(default))]
451 pub primitive: wgt::PrimitiveState,
452 #[cfg_attr(feature = "serde", serde(default))]
454 pub depth_stencil: Option<wgt::DepthStencilState>,
455 #[cfg_attr(feature = "serde", serde(default))]
457 pub multisample: wgt::MultisampleState,
458 pub fragment: Option<FragmentState<'a, SM>>,
460 pub multiview: Option<NonZeroU32>,
463 pub cache: Option<PLC>,
465}
466#[derive(Clone, Debug)]
468#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
469pub struct MeshPipelineDescriptor<
470 'a,
471 PLL = PipelineLayoutId,
472 SM = ShaderModuleId,
473 PLC = PipelineCacheId,
474> {
475 pub label: Label<'a>,
476 pub layout: Option<PLL>,
478 pub task: Option<TaskState<'a, SM>>,
480 pub mesh: MeshState<'a, SM>,
482 #[cfg_attr(feature = "serde", serde(default))]
484 pub primitive: wgt::PrimitiveState,
485 #[cfg_attr(feature = "serde", serde(default))]
487 pub depth_stencil: Option<wgt::DepthStencilState>,
488 #[cfg_attr(feature = "serde", serde(default))]
490 pub multisample: wgt::MultisampleState,
491 pub fragment: Option<FragmentState<'a, SM>>,
493 pub multiview: Option<NonZeroU32>,
496 pub cache: Option<PLC>,
498}
499
500#[derive(Clone, Debug)]
502#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
503pub(crate) struct GeneralRenderPipelineDescriptor<
504 'a,
505 PLL = PipelineLayoutId,
506 SM = ShaderModuleId,
507 PLC = PipelineCacheId,
508> {
509 pub label: Label<'a>,
510 pub layout: Option<PLL>,
512 pub vertex: RenderPipelineVertexProcessor<'a, SM>,
514 #[cfg_attr(feature = "serde", serde(default))]
516 pub primitive: wgt::PrimitiveState,
517 #[cfg_attr(feature = "serde", serde(default))]
519 pub depth_stencil: Option<wgt::DepthStencilState>,
520 #[cfg_attr(feature = "serde", serde(default))]
522 pub multisample: wgt::MultisampleState,
523 pub fragment: Option<FragmentState<'a, SM>>,
525 pub multiview: Option<NonZeroU32>,
528 pub cache: Option<PLC>,
530}
531impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
532 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
533{
534 fn from(value: RenderPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
535 Self {
536 label: value.label,
537 layout: value.layout,
538 vertex: RenderPipelineVertexProcessor::Vertex(value.vertex),
539 primitive: value.primitive,
540 depth_stencil: value.depth_stencil,
541 multisample: value.multisample,
542 fragment: value.fragment,
543 multiview: value.multiview,
544 cache: value.cache,
545 }
546 }
547}
548impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
549 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
550{
551 fn from(value: MeshPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
552 Self {
553 label: value.label,
554 layout: value.layout,
555 vertex: RenderPipelineVertexProcessor::Mesh(value.task, value.mesh),
556 primitive: value.primitive,
557 depth_stencil: value.depth_stencil,
558 multisample: value.multisample,
559 fragment: value.fragment,
560 multiview: value.multiview,
561 cache: value.cache,
562 }
563 }
564}
565
566pub(crate) type ResolvedGeneralRenderPipelineDescriptor<'a> =
568 GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
569
570#[derive(Clone, Debug)]
571#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
572pub struct PipelineCacheDescriptor<'a> {
573 pub label: Label<'a>,
574 pub data: Option<Cow<'a, [u8]>>,
575 pub fallback: bool,
576}
577
578#[derive(Clone, Debug, Error)]
579#[non_exhaustive]
580pub enum ColorStateError {
581 #[error("Format {0:?} is not renderable")]
582 FormatNotRenderable(wgt::TextureFormat),
583 #[error("Format {0:?} is not blendable")]
584 FormatNotBlendable(wgt::TextureFormat),
585 #[error("Format {0:?} does not have a color aspect")]
586 FormatNotColor(wgt::TextureFormat),
587 #[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:?}.")]
588 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
589 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
590 IncompatibleFormat {
591 pipeline: validation::NumericType,
592 shader: validation::NumericType,
593 },
594 #[error("Invalid write mask {0:?}")]
595 InvalidWriteMask(wgt::ColorWrites),
596}
597
598#[derive(Clone, Debug, Error)]
599#[non_exhaustive]
600pub enum DepthStencilStateError {
601 #[error("Format {0:?} is not renderable")]
602 FormatNotRenderable(wgt::TextureFormat),
603 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
604 FormatNotDepth(wgt::TextureFormat),
605 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
606 FormatNotStencil(wgt::TextureFormat),
607 #[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:?}.")]
608 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
609}
610
611#[derive(Clone, Debug, Error)]
612#[non_exhaustive]
613pub enum CreateRenderPipelineError {
614 #[error(transparent)]
615 ColorAttachment(#[from] ColorAttachmentError),
616 #[error(transparent)]
617 Device(#[from] DeviceError),
618 #[error("Unable to derive an implicit layout")]
619 Implicit(#[from] ImplicitLayoutError),
620 #[error("Color state [{0}] is invalid")]
621 ColorState(u8, #[source] ColorStateError),
622 #[error("Depth/stencil state is invalid")]
623 DepthStencilState(#[from] DepthStencilStateError),
624 #[error("Invalid sample count {0}")]
625 InvalidSampleCount(u32),
626 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
627 TooManyVertexBuffers { given: u32, limit: u32 },
628 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
629 TooManyVertexAttributes { given: u32, limit: u32 },
630 #[error("Vertex attribute location {given} must be less than limit {limit}")]
631 VertexAttributeLocationTooLarge { given: u32, limit: u32 },
632 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
633 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
634 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
635 VertexAttributeStrideTooLarge {
636 location: wgt::ShaderLocation,
637 given: u32,
638 limit: u32,
639 },
640 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
641 UnalignedVertexStride {
642 index: u32,
643 stride: wgt::BufferAddress,
644 },
645 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
646 InvalidVertexAttributeOffset {
647 location: wgt::ShaderLocation,
648 offset: wgt::BufferAddress,
649 },
650 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
651 ShaderLocationClash(u32),
652 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
653 StripIndexFormatForNonStripTopology {
654 strip_index_format: Option<wgt::IndexFormat>,
655 topology: wgt::PrimitiveTopology,
656 },
657 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
658 ConservativeRasterizationNonFillPolygonMode,
659 #[error(transparent)]
660 MissingFeatures(#[from] MissingFeatures),
661 #[error(transparent)]
662 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
663 #[error("Error matching {stage:?} shader requirements against the pipeline")]
664 Stage {
665 stage: wgt::ShaderStages,
666 #[source]
667 error: validation::StageError,
668 },
669 #[error("Internal error in {stage:?} shader: {error}")]
670 Internal {
671 stage: wgt::ShaderStages,
672 error: String,
673 },
674 #[error("Pipeline constant error in {stage:?} shader: {error}")]
675 PipelineConstants {
676 stage: wgt::ShaderStages,
677 error: String,
678 },
679 #[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.")]
680 UnalignedShader { group: u32, binding: u32, size: u64 },
681 #[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.")]
682 BlendFactorOnUnsupportedTarget {
683 factor: wgt::BlendFactor,
684 target: u32,
685 },
686 #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
687 PipelineExpectsShaderToUseDualSourceBlending,
688 #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
689 ShaderExpectsPipelineToUseDualSourceBlending,
690 #[error("{}", concat!(
691 "At least one color attachment or depth-stencil attachment was expected, ",
692 "but no render target for the pipeline was specified."
693 ))]
694 NoTargetSpecified,
695 #[error(transparent)]
696 InvalidResource(#[from] InvalidResourceError),
697}
698
699impl WebGpuError for CreateRenderPipelineError {
700 fn webgpu_error_type(&self) -> ErrorType {
701 let e: &dyn WebGpuError = match self {
702 Self::Device(e) => e,
703 Self::InvalidResource(e) => e,
704 Self::MissingFeatures(e) => e,
705 Self::MissingDownlevelFlags(e) => e,
706
707 Self::Internal { .. } => return ErrorType::Internal,
708
709 Self::ColorAttachment(_)
710 | Self::Implicit(_)
711 | Self::ColorState(_, _)
712 | Self::DepthStencilState(_)
713 | Self::InvalidSampleCount(_)
714 | Self::TooManyVertexBuffers { .. }
715 | Self::TooManyVertexAttributes { .. }
716 | Self::VertexAttributeLocationTooLarge { .. }
717 | Self::VertexStrideTooLarge { .. }
718 | Self::UnalignedVertexStride { .. }
719 | Self::InvalidVertexAttributeOffset { .. }
720 | Self::ShaderLocationClash(_)
721 | Self::StripIndexFormatForNonStripTopology { .. }
722 | Self::ConservativeRasterizationNonFillPolygonMode
723 | Self::Stage { .. }
724 | Self::UnalignedShader { .. }
725 | Self::BlendFactorOnUnsupportedTarget { .. }
726 | Self::PipelineExpectsShaderToUseDualSourceBlending
727 | Self::ShaderExpectsPipelineToUseDualSourceBlending
728 | Self::NoTargetSpecified
729 | Self::PipelineConstants { .. }
730 | Self::VertexAttributeStrideTooLarge { .. } => return ErrorType::Validation,
731 };
732 e.webgpu_error_type()
733 }
734}
735
736bitflags::bitflags! {
737 #[repr(transparent)]
738 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
739 pub struct PipelineFlags: u32 {
740 const BLEND_CONSTANT = 1 << 0;
741 const STENCIL_REFERENCE = 1 << 1;
742 const WRITES_DEPTH = 1 << 2;
743 const WRITES_STENCIL = 1 << 3;
744 }
745}
746
747#[derive(Clone, Copy, Debug)]
749pub struct VertexStep {
750 pub stride: wgt::BufferAddress,
752
753 pub last_stride: wgt::BufferAddress,
755
756 pub mode: wgt::VertexStepMode,
758}
759
760impl Default for VertexStep {
761 fn default() -> Self {
762 Self {
763 stride: 0,
764 last_stride: 0,
765 mode: wgt::VertexStepMode::Vertex,
766 }
767 }
768}
769
770#[derive(Debug)]
771pub struct RenderPipeline {
772 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
773 pub(crate) device: Arc<Device>,
774 pub(crate) layout: Arc<PipelineLayout>,
775 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
776 pub(crate) pass_context: RenderPassContext,
777 pub(crate) flags: PipelineFlags,
778 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
779 pub(crate) vertex_steps: Vec<VertexStep>,
780 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
781 pub(crate) label: String,
783 pub(crate) tracking_data: TrackingData,
784 pub(crate) is_mesh: bool,
786}
787
788impl Drop for RenderPipeline {
789 fn drop(&mut self) {
790 resource_log!("Destroy raw {}", self.error_ident());
791 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
793 unsafe {
794 self.device.raw().destroy_render_pipeline(raw);
795 }
796 }
797}
798
799crate::impl_resource_type!(RenderPipeline);
800crate::impl_labeled!(RenderPipeline);
801crate::impl_parent_device!(RenderPipeline);
802crate::impl_storage_item!(RenderPipeline);
803crate::impl_trackable!(RenderPipeline);
804
805impl RenderPipeline {
806 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
807 self.raw.as_ref()
808 }
809}