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