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}
134
135impl WebGpuError for CreateShaderModuleError {
136 fn webgpu_error_type(&self) -> ErrorType {
137 let e: &dyn WebGpuError = match self {
138 Self::Device(e) => e,
139 Self::MissingFeatures(e) => e,
140
141 Self::Generation => return ErrorType::Internal,
142
143 Self::Validation(..) | Self::InvalidGroupIndex { .. } => return ErrorType::Validation,
144 #[cfg(feature = "wgsl")]
145 Self::Parsing(..) => return ErrorType::Validation,
146 #[cfg(feature = "glsl")]
147 Self::ParsingGlsl(..) => return ErrorType::Validation,
148 #[cfg(feature = "spirv")]
149 Self::ParsingSpirV(..) => return ErrorType::Validation,
150 };
151 e.webgpu_error_type()
152 }
153}
154
155#[derive(Clone, Debug)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
158pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
159 pub module: SM,
161 pub entry_point: Option<Cow<'a, str>>,
168 pub constants: naga::back::PipelineConstants,
176 pub zero_initialize_workgroup_memory: bool,
181}
182
183pub type ResolvedProgrammableStageDescriptor<'a> =
185 ProgrammableStageDescriptor<'a, Arc<ShaderModule>>;
186
187pub type ImplicitBindGroupCount = u8;
189
190#[derive(Clone, Debug, Error)]
191#[non_exhaustive]
192pub enum ImplicitLayoutError {
193 #[error("Unable to reflect the shader {0:?} interface")]
194 ReflectionError(wgt::ShaderStages),
195 #[error(transparent)]
196 BindGroup(#[from] CreateBindGroupLayoutError),
197 #[error(transparent)]
198 Pipeline(#[from] CreatePipelineLayoutError),
199}
200
201impl WebGpuError for ImplicitLayoutError {
202 fn webgpu_error_type(&self) -> ErrorType {
203 let e: &dyn WebGpuError = match self {
204 Self::ReflectionError(_) => return ErrorType::Validation,
205 Self::BindGroup(e) => e,
206 Self::Pipeline(e) => e,
207 };
208 e.webgpu_error_type()
209 }
210}
211
212#[derive(Clone, Debug)]
214#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
215pub struct ComputePipelineDescriptor<
216 'a,
217 PLL = PipelineLayoutId,
218 SM = ShaderModuleId,
219 PLC = PipelineCacheId,
220> {
221 pub label: Label<'a>,
222 pub layout: Option<PLL>,
224 pub stage: ProgrammableStageDescriptor<'a, SM>,
226 pub cache: Option<PLC>,
228}
229
230pub type ResolvedComputePipelineDescriptor<'a> =
232 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
233
234#[derive(Clone, Debug, Error)]
235#[non_exhaustive]
236pub enum CreateComputePipelineError {
237 #[error(transparent)]
238 Device(#[from] DeviceError),
239 #[error("Unable to derive an implicit layout")]
240 Implicit(#[from] ImplicitLayoutError),
241 #[error("Error matching shader requirements against the pipeline")]
242 Stage(#[from] validation::StageError),
243 #[error("Internal error: {0}")]
244 Internal(String),
245 #[error("Pipeline constant error: {0}")]
246 PipelineConstants(String),
247 #[error(transparent)]
248 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
249 #[error(transparent)]
250 InvalidResource(#[from] InvalidResourceError),
251}
252
253impl WebGpuError for CreateComputePipelineError {
254 fn webgpu_error_type(&self) -> ErrorType {
255 let e: &dyn WebGpuError = match self {
256 Self::Device(e) => e,
257 Self::InvalidResource(e) => e,
258 Self::MissingDownlevelFlags(e) => e,
259 Self::Implicit(e) => e,
260 Self::Stage(e) => e,
261 Self::Internal(_) => return ErrorType::Internal,
262 Self::PipelineConstants(_) => return ErrorType::Validation,
263 };
264 e.webgpu_error_type()
265 }
266}
267
268#[derive(Debug)]
269pub struct ComputePipeline {
270 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
271 pub(crate) layout: Arc<PipelineLayout>,
272 pub(crate) device: Arc<Device>,
273 pub(crate) _shader_module: Arc<ShaderModule>,
274 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
275 pub(crate) label: String,
277 pub(crate) tracking_data: TrackingData,
278}
279
280impl Drop for ComputePipeline {
281 fn drop(&mut self) {
282 resource_log!("Destroy raw {}", self.error_ident());
283 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
285 unsafe {
286 self.device.raw().destroy_compute_pipeline(raw);
287 }
288 }
289}
290
291crate::impl_resource_type!(ComputePipeline);
292crate::impl_labeled!(ComputePipeline);
293crate::impl_parent_device!(ComputePipeline);
294crate::impl_storage_item!(ComputePipeline);
295crate::impl_trackable!(ComputePipeline);
296
297impl ComputePipeline {
298 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
299 self.raw.as_ref()
300 }
301}
302
303#[derive(Clone, Debug, Error)]
304#[non_exhaustive]
305pub enum CreatePipelineCacheError {
306 #[error(transparent)]
307 Device(#[from] DeviceError),
308 #[error("Pipeline cache validation failed")]
309 Validation(#[from] PipelineCacheValidationError),
310 #[error(transparent)]
311 MissingFeatures(#[from] MissingFeatures),
312}
313
314impl WebGpuError for CreatePipelineCacheError {
315 fn webgpu_error_type(&self) -> ErrorType {
316 let e: &dyn WebGpuError = match self {
317 Self::Device(e) => e,
318 Self::Validation(e) => e,
319 Self::MissingFeatures(e) => e,
320 };
321 e.webgpu_error_type()
322 }
323}
324
325#[derive(Debug)]
326pub struct PipelineCache {
327 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
328 pub(crate) device: Arc<Device>,
329 pub(crate) label: String,
331}
332
333impl Drop for PipelineCache {
334 fn drop(&mut self) {
335 resource_log!("Destroy raw {}", self.error_ident());
336 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
338 unsafe {
339 self.device.raw().destroy_pipeline_cache(raw);
340 }
341 }
342}
343
344crate::impl_resource_type!(PipelineCache);
345crate::impl_labeled!(PipelineCache);
346crate::impl_parent_device!(PipelineCache);
347crate::impl_storage_item!(PipelineCache);
348
349impl PipelineCache {
350 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
351 self.raw.as_ref()
352 }
353}
354
355#[derive(Clone, Debug)]
357#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
358#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
359pub struct VertexBufferLayout<'a> {
360 pub array_stride: wgt::BufferAddress,
362 pub step_mode: wgt::VertexStepMode,
364 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
366}
367
368impl Default for VertexBufferLayout<'_> {
370 fn default() -> Self {
371 Self {
372 array_stride: Default::default(),
373 step_mode: Default::default(),
374 attributes: Cow::Borrowed(&[]),
375 }
376 }
377}
378
379#[derive(Clone, Debug)]
381#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
382pub struct VertexState<'a, SM = ShaderModuleId> {
383 pub stage: ProgrammableStageDescriptor<'a, SM>,
385 pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
387}
388
389pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
391
392#[derive(Clone, Debug)]
394#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
395pub struct FragmentState<'a, SM = ShaderModuleId> {
396 pub stage: ProgrammableStageDescriptor<'a, SM>,
398 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
400}
401
402pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
404
405#[derive(Clone, Debug)]
407#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
408pub struct TaskState<'a, SM = ShaderModuleId> {
409 pub stage: ProgrammableStageDescriptor<'a, SM>,
411}
412
413pub type ResolvedTaskState<'a> = TaskState<'a, Arc<ShaderModule>>;
414
415#[derive(Clone, Debug)]
417#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
418pub struct MeshState<'a, SM = ShaderModuleId> {
419 pub stage: ProgrammableStageDescriptor<'a, SM>,
421}
422
423pub type ResolvedMeshState<'a> = MeshState<'a, Arc<ShaderModule>>;
424
425#[derive(Clone, Debug)]
426#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
427pub(crate) enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> {
428 Vertex(VertexState<'a, SM>),
429 Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>),
430}
431
432#[derive(Clone, Debug)]
434#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
435pub struct RenderPipelineDescriptor<
436 'a,
437 PLL = PipelineLayoutId,
438 SM = ShaderModuleId,
439 PLC = PipelineCacheId,
440> {
441 pub label: Label<'a>,
442 pub layout: Option<PLL>,
444 pub vertex: VertexState<'a, SM>,
446 #[cfg_attr(feature = "serde", serde(default))]
448 pub primitive: wgt::PrimitiveState,
449 #[cfg_attr(feature = "serde", serde(default))]
451 pub depth_stencil: Option<wgt::DepthStencilState>,
452 #[cfg_attr(feature = "serde", serde(default))]
454 pub multisample: wgt::MultisampleState,
455 pub fragment: Option<FragmentState<'a, SM>>,
457 pub multiview: Option<NonZeroU32>,
460 pub cache: Option<PLC>,
462}
463#[derive(Clone, Debug)]
465#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
466pub struct MeshPipelineDescriptor<
467 'a,
468 PLL = PipelineLayoutId,
469 SM = ShaderModuleId,
470 PLC = PipelineCacheId,
471> {
472 pub label: Label<'a>,
473 pub layout: Option<PLL>,
475 pub task: Option<TaskState<'a, SM>>,
477 pub mesh: MeshState<'a, SM>,
479 #[cfg_attr(feature = "serde", serde(default))]
481 pub primitive: wgt::PrimitiveState,
482 #[cfg_attr(feature = "serde", serde(default))]
484 pub depth_stencil: Option<wgt::DepthStencilState>,
485 #[cfg_attr(feature = "serde", serde(default))]
487 pub multisample: wgt::MultisampleState,
488 pub fragment: Option<FragmentState<'a, SM>>,
490 pub multiview: Option<NonZeroU32>,
493 pub cache: Option<PLC>,
495}
496
497#[derive(Clone, Debug)]
499#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
500pub(crate) struct GeneralRenderPipelineDescriptor<
501 'a,
502 PLL = PipelineLayoutId,
503 SM = ShaderModuleId,
504 PLC = PipelineCacheId,
505> {
506 pub label: Label<'a>,
507 pub layout: Option<PLL>,
509 pub vertex: RenderPipelineVertexProcessor<'a, SM>,
511 #[cfg_attr(feature = "serde", serde(default))]
513 pub primitive: wgt::PrimitiveState,
514 #[cfg_attr(feature = "serde", serde(default))]
516 pub depth_stencil: Option<wgt::DepthStencilState>,
517 #[cfg_attr(feature = "serde", serde(default))]
519 pub multisample: wgt::MultisampleState,
520 pub fragment: Option<FragmentState<'a, SM>>,
522 pub multiview: Option<NonZeroU32>,
525 pub cache: Option<PLC>,
527}
528impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
529 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
530{
531 fn from(value: RenderPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
532 Self {
533 label: value.label,
534 layout: value.layout,
535 vertex: RenderPipelineVertexProcessor::Vertex(value.vertex),
536 primitive: value.primitive,
537 depth_stencil: value.depth_stencil,
538 multisample: value.multisample,
539 fragment: value.fragment,
540 multiview: value.multiview,
541 cache: value.cache,
542 }
543 }
544}
545impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
546 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
547{
548 fn from(value: MeshPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
549 Self {
550 label: value.label,
551 layout: value.layout,
552 vertex: RenderPipelineVertexProcessor::Mesh(value.task, value.mesh),
553 primitive: value.primitive,
554 depth_stencil: value.depth_stencil,
555 multisample: value.multisample,
556 fragment: value.fragment,
557 multiview: value.multiview,
558 cache: value.cache,
559 }
560 }
561}
562
563pub(crate) type ResolvedGeneralRenderPipelineDescriptor<'a> =
565 GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
566
567#[derive(Clone, Debug)]
568#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
569pub struct PipelineCacheDescriptor<'a> {
570 pub label: Label<'a>,
571 pub data: Option<Cow<'a, [u8]>>,
572 pub fallback: bool,
573}
574
575#[derive(Clone, Debug, Error)]
576#[non_exhaustive]
577pub enum ColorStateError {
578 #[error("Format {0:?} is not renderable")]
579 FormatNotRenderable(wgt::TextureFormat),
580 #[error("Format {0:?} is not blendable")]
581 FormatNotBlendable(wgt::TextureFormat),
582 #[error("Format {0:?} does not have a color aspect")]
583 FormatNotColor(wgt::TextureFormat),
584 #[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:?}.")]
585 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
586 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
587 IncompatibleFormat {
588 pipeline: validation::NumericType,
589 shader: validation::NumericType,
590 },
591 #[error("Invalid write mask {0:?}")]
592 InvalidWriteMask(wgt::ColorWrites),
593}
594
595#[derive(Clone, Debug, Error)]
596#[non_exhaustive]
597pub enum DepthStencilStateError {
598 #[error("Format {0:?} is not renderable")]
599 FormatNotRenderable(wgt::TextureFormat),
600 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
601 FormatNotDepth(wgt::TextureFormat),
602 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
603 FormatNotStencil(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}
607
608#[derive(Clone, Debug, Error)]
609#[non_exhaustive]
610pub enum CreateRenderPipelineError {
611 #[error(transparent)]
612 ColorAttachment(#[from] ColorAttachmentError),
613 #[error(transparent)]
614 Device(#[from] DeviceError),
615 #[error("Unable to derive an implicit layout")]
616 Implicit(#[from] ImplicitLayoutError),
617 #[error("Color state [{0}] is invalid")]
618 ColorState(u8, #[source] ColorStateError),
619 #[error("Depth/stencil state is invalid")]
620 DepthStencilState(#[from] DepthStencilStateError),
621 #[error("Invalid sample count {0}")]
622 InvalidSampleCount(u32),
623 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
624 TooManyVertexBuffers { given: u32, limit: u32 },
625 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
626 TooManyVertexAttributes { given: u32, limit: u32 },
627 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
628 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
629 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
630 VertexAttributeStrideTooLarge {
631 location: wgt::ShaderLocation,
632 given: u32,
633 limit: u32,
634 },
635 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
636 UnalignedVertexStride {
637 index: u32,
638 stride: wgt::BufferAddress,
639 },
640 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
641 InvalidVertexAttributeOffset {
642 location: wgt::ShaderLocation,
643 offset: wgt::BufferAddress,
644 },
645 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
646 ShaderLocationClash(u32),
647 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
648 StripIndexFormatForNonStripTopology {
649 strip_index_format: Option<wgt::IndexFormat>,
650 topology: wgt::PrimitiveTopology,
651 },
652 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
653 ConservativeRasterizationNonFillPolygonMode,
654 #[error(transparent)]
655 MissingFeatures(#[from] MissingFeatures),
656 #[error(transparent)]
657 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
658 #[error("Error matching {stage:?} shader requirements against the pipeline")]
659 Stage {
660 stage: wgt::ShaderStages,
661 #[source]
662 error: validation::StageError,
663 },
664 #[error("Internal error in {stage:?} shader: {error}")]
665 Internal {
666 stage: wgt::ShaderStages,
667 error: String,
668 },
669 #[error("Pipeline constant error in {stage:?} shader: {error}")]
670 PipelineConstants {
671 stage: wgt::ShaderStages,
672 error: String,
673 },
674 #[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.")]
675 UnalignedShader { group: u32, binding: u32, size: u64 },
676 #[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.")]
677 BlendFactorOnUnsupportedTarget {
678 factor: wgt::BlendFactor,
679 target: u32,
680 },
681 #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
682 PipelineExpectsShaderToUseDualSourceBlending,
683 #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
684 ShaderExpectsPipelineToUseDualSourceBlending,
685 #[error("{}", concat!(
686 "At least one color attachment or depth-stencil attachment was expected, ",
687 "but no render target for the pipeline was specified."
688 ))]
689 NoTargetSpecified,
690 #[error(transparent)]
691 InvalidResource(#[from] InvalidResourceError),
692}
693
694impl WebGpuError for CreateRenderPipelineError {
695 fn webgpu_error_type(&self) -> ErrorType {
696 let e: &dyn WebGpuError = match self {
697 Self::Device(e) => e,
698 Self::InvalidResource(e) => e,
699 Self::MissingFeatures(e) => e,
700 Self::MissingDownlevelFlags(e) => e,
701
702 Self::Internal { .. } => return ErrorType::Internal,
703
704 Self::ColorAttachment(_)
705 | Self::Implicit(_)
706 | Self::ColorState(_, _)
707 | Self::DepthStencilState(_)
708 | Self::InvalidSampleCount(_)
709 | Self::TooManyVertexBuffers { .. }
710 | Self::TooManyVertexAttributes { .. }
711 | Self::VertexStrideTooLarge { .. }
712 | Self::UnalignedVertexStride { .. }
713 | Self::InvalidVertexAttributeOffset { .. }
714 | Self::ShaderLocationClash(_)
715 | Self::StripIndexFormatForNonStripTopology { .. }
716 | Self::ConservativeRasterizationNonFillPolygonMode
717 | Self::Stage { .. }
718 | Self::UnalignedShader { .. }
719 | Self::BlendFactorOnUnsupportedTarget { .. }
720 | Self::PipelineExpectsShaderToUseDualSourceBlending
721 | Self::ShaderExpectsPipelineToUseDualSourceBlending
722 | Self::NoTargetSpecified
723 | Self::PipelineConstants { .. }
724 | Self::VertexAttributeStrideTooLarge { .. } => return ErrorType::Validation,
725 };
726 e.webgpu_error_type()
727 }
728}
729
730bitflags::bitflags! {
731 #[repr(transparent)]
732 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
733 pub struct PipelineFlags: u32 {
734 const BLEND_CONSTANT = 1 << 0;
735 const STENCIL_REFERENCE = 1 << 1;
736 const WRITES_DEPTH = 1 << 2;
737 const WRITES_STENCIL = 1 << 3;
738 }
739}
740
741#[derive(Clone, Copy, Debug)]
743pub struct VertexStep {
744 pub stride: wgt::BufferAddress,
746
747 pub last_stride: wgt::BufferAddress,
749
750 pub mode: wgt::VertexStepMode,
752}
753
754impl Default for VertexStep {
755 fn default() -> Self {
756 Self {
757 stride: 0,
758 last_stride: 0,
759 mode: wgt::VertexStepMode::Vertex,
760 }
761 }
762}
763
764#[derive(Debug)]
765pub struct RenderPipeline {
766 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
767 pub(crate) device: Arc<Device>,
768 pub(crate) layout: Arc<PipelineLayout>,
769 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
770 pub(crate) pass_context: RenderPassContext,
771 pub(crate) flags: PipelineFlags,
772 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
773 pub(crate) vertex_steps: Vec<VertexStep>,
774 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
775 pub(crate) label: String,
777 pub(crate) tracking_data: TrackingData,
778 pub(crate) is_mesh: bool,
780}
781
782impl Drop for RenderPipeline {
783 fn drop(&mut self) {
784 resource_log!("Destroy raw {}", self.error_ident());
785 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
787 unsafe {
788 self.device.raw().destroy_render_pipeline(raw);
789 }
790 }
791}
792
793crate::impl_resource_type!(RenderPipeline);
794crate::impl_labeled!(RenderPipeline);
795crate::impl_parent_device!(RenderPipeline);
796crate::impl_storage_item!(RenderPipeline);
797crate::impl_trackable!(RenderPipeline);
798
799impl RenderPipeline {
800 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
801 self.raw.as_ref()
802 }
803}