1use alloc::{
2 borrow::{Cow, ToOwned},
3 boxed::Box,
4 string::String,
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,
26 validation::{self, ShaderMetaData},
27 Label,
28};
29
30#[derive(Debug, Default)]
34pub(crate) struct LateSizedBufferGroup {
35 pub(crate) shader_sizes: Vec<wgt::BufferAddress>,
37}
38
39#[allow(clippy::large_enum_variant)]
40pub enum ShaderModuleSource<'a> {
41 #[cfg(feature = "wgsl")]
42 Wgsl(Cow<'a, str>),
43 #[cfg(feature = "glsl")]
44 Glsl(Cow<'a, str>, naga::front::glsl::Options),
45 #[cfg(feature = "spirv")]
46 SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
47 Naga(Cow<'static, naga::Module>),
48 #[doc(hidden)]
51 Dummy(PhantomData<&'a ()>),
52}
53
54#[derive(Clone, Debug)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct ShaderModuleDescriptor<'a> {
57 pub label: Label<'a>,
58 #[cfg_attr(feature = "serde", serde(default))]
59 pub runtime_checks: wgt::ShaderRuntimeChecks,
60}
61
62pub type ShaderModuleDescriptorPassthrough<'a> =
63 wgt::CreateShaderModuleDescriptorPassthrough<'a, Label<'a>>;
64
65#[derive(Debug)]
66pub struct ShaderModule {
67 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynShaderModule>>,
68 pub(crate) device: Arc<Device>,
69 pub(crate) interface: ShaderMetaData,
70 pub(crate) label: String,
72}
73
74impl Drop for ShaderModule {
75 fn drop(&mut self) {
76 resource_log!("Destroy raw {}", self.error_ident());
77 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
79 unsafe {
80 self.device.raw().destroy_shader_module(raw);
81 }
82 }
83}
84
85crate::impl_resource_type!(ShaderModule);
86crate::impl_labeled!(ShaderModule);
87crate::impl_parent_device!(ShaderModule);
88crate::impl_storage_item!(ShaderModule);
89
90impl ShaderModule {
91 pub(crate) fn raw(&self) -> &dyn hal::DynShaderModule {
92 self.raw.as_ref()
93 }
94
95 pub(crate) fn finalize_entry_point_name(
96 &self,
97 stage: naga::ShaderStage,
98 entry_point: Option<&str>,
99 ) -> Result<String, validation::StageError> {
100 match self.interface {
101 ShaderMetaData::Interface(ref interface) => {
102 interface.finalize_entry_point_name(stage, entry_point)
103 }
104 ShaderMetaData::Passthrough(ref interface) => {
105 if let Some(ep) = entry_point {
106 if interface.entry_point_names.contains(ep) {
107 Ok(ep.to_owned())
108 } else {
109 Err(validation::StageError::MissingEntryPoint(ep.to_owned()))
110 }
111 } else {
112 if interface.entry_point_names.len() != 1 {
113 return Err(validation::StageError::MultipleEntryPointsFound);
114 }
115 Ok(interface
116 .entry_point_names
117 .iter()
118 .next()
119 .unwrap()
120 .to_owned())
121 }
122 }
123 }
124 }
125}
126
127#[derive(Clone, Debug, Error)]
129#[non_exhaustive]
130pub enum CreateShaderModuleError {
131 #[cfg(feature = "wgsl")]
132 #[error(transparent)]
133 Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
134 #[cfg(feature = "glsl")]
135 #[error(transparent)]
136 ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
137 #[cfg(feature = "spirv")]
138 #[error(transparent)]
139 ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
140 #[error("Failed to generate the backend-specific code")]
141 Generation,
142 #[error(transparent)]
143 Device(#[from] DeviceError),
144 #[error(transparent)]
145 Validation(#[from] ShaderError<naga::WithSpan<naga::valid::ValidationError>>),
146 #[error(transparent)]
147 MissingFeatures(#[from] MissingFeatures),
148 #[error(
149 "Shader global {bind:?} uses a group index {group} that exceeds the max_bind_groups limit of {limit}."
150 )]
151 InvalidGroupIndex {
152 bind: naga::ResourceBinding,
153 group: u32,
154 limit: u32,
155 },
156 #[error("Generic shader passthrough does not contain any code compatible with this backend.")]
157 NotCompiledForBackend,
158 #[error(
159 "Generic passthrough shaders which use GLSL or DXIL must contain exactly one entry point."
160 )]
161 IncorrectPassthroughEntryPointCount,
162}
163
164impl WebGpuError for CreateShaderModuleError {
165 fn webgpu_error_type(&self) -> ErrorType {
166 match self {
167 Self::Device(e) => e.webgpu_error_type(),
168 Self::MissingFeatures(e) => e.webgpu_error_type(),
169
170 Self::Generation => ErrorType::Internal,
171
172 Self::Validation(..)
173 | Self::InvalidGroupIndex { .. }
174 | Self::IncorrectPassthroughEntryPointCount
175 | Self::NotCompiledForBackend => ErrorType::Validation,
176 #[cfg(feature = "wgsl")]
177 Self::Parsing(..) => ErrorType::Validation,
178 #[cfg(feature = "glsl")]
179 Self::ParsingGlsl(..) => ErrorType::Validation,
180 #[cfg(feature = "spirv")]
181 Self::ParsingSpirV(..) => ErrorType::Validation,
182 }
183 }
184}
185
186#[derive(Clone, Debug)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
190 pub module: SM,
192 pub entry_point: Option<Cow<'a, str>>,
199 pub constants: naga::back::PipelineConstants,
207 pub zero_initialize_workgroup_memory: bool,
212}
213
214pub type ResolvedProgrammableStageDescriptor<'a> =
216 ProgrammableStageDescriptor<'a, Arc<ShaderModule>>;
217
218pub type ImplicitBindGroupCount = u8;
220
221#[derive(Clone, Debug, Error)]
222#[non_exhaustive]
223pub enum ImplicitLayoutError {
224 #[error("Unable to reflect the shader {0:?} interface")]
225 ReflectionError(wgt::ShaderStages),
226 #[error(transparent)]
227 BindGroup(#[from] CreateBindGroupLayoutError),
228 #[error(transparent)]
229 Pipeline(#[from] CreatePipelineLayoutError),
230 #[error("Unable to create implicit pipeline layout from passthrough shader stage: {0:?}")]
231 Passthrough(wgt::ShaderStages),
232}
233
234impl WebGpuError for ImplicitLayoutError {
235 fn webgpu_error_type(&self) -> ErrorType {
236 match self {
237 Self::ReflectionError(_) => ErrorType::Validation,
238 Self::BindGroup(e) => e.webgpu_error_type(),
239 Self::Pipeline(e) => e.webgpu_error_type(),
240 Self::Passthrough(_) => ErrorType::Validation,
241 }
242 }
243}
244
245#[derive(Clone, Debug)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248pub struct ComputePipelineDescriptor<
249 'a,
250 PLL = PipelineLayoutId,
251 SM = ShaderModuleId,
252 PLC = PipelineCacheId,
253> {
254 pub label: Label<'a>,
255 pub layout: Option<PLL>,
257 pub stage: ProgrammableStageDescriptor<'a, SM>,
259 pub cache: Option<PLC>,
261}
262
263pub type ResolvedComputePipelineDescriptor<'a> =
265 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
266
267#[derive(Clone, Debug, Error)]
268#[non_exhaustive]
269pub enum CreateComputePipelineError {
270 #[error(transparent)]
271 Device(#[from] DeviceError),
272 #[error("Unable to derive an implicit layout")]
273 Implicit(#[from] ImplicitLayoutError),
274 #[error("Error matching shader requirements against the pipeline")]
275 Stage(#[from] validation::StageError),
276 #[error("Internal error: {0}")]
277 Internal(String),
278 #[error("Pipeline constant error: {0}")]
279 PipelineConstants(String),
280 #[error(transparent)]
281 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
282 #[error(transparent)]
283 InvalidResource(#[from] InvalidResourceError),
284}
285
286impl WebGpuError for CreateComputePipelineError {
287 fn webgpu_error_type(&self) -> ErrorType {
288 match self {
289 Self::Device(e) => e.webgpu_error_type(),
290 Self::InvalidResource(e) => e.webgpu_error_type(),
291 Self::MissingDownlevelFlags(e) => e.webgpu_error_type(),
292 Self::Implicit(e) => e.webgpu_error_type(),
293 Self::Stage(e) => e.webgpu_error_type(),
294 Self::Internal(_) => ErrorType::Internal,
295 Self::PipelineConstants(_) => ErrorType::Validation,
296 }
297 }
298}
299
300#[derive(Debug)]
301pub struct ComputePipeline {
302 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
303 pub(crate) layout: Arc<PipelineLayout>,
304 pub(crate) device: Arc<Device>,
305 pub(crate) _shader_module: Arc<ShaderModule>,
306 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
307 pub(crate) immediate_slots_required: naga::valid::ImmediateSlots,
308 pub(crate) label: String,
310 pub(crate) tracking_data: TrackingData,
311}
312
313impl Drop for ComputePipeline {
314 fn drop(&mut self) {
315 resource_log!("Destroy raw {}", self.error_ident());
316 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
318 unsafe {
319 self.device.raw().destroy_compute_pipeline(raw);
320 }
321 }
322}
323
324crate::impl_resource_type!(ComputePipeline);
325crate::impl_labeled!(ComputePipeline);
326crate::impl_parent_device!(ComputePipeline);
327crate::impl_storage_item!(ComputePipeline);
328crate::impl_trackable!(ComputePipeline);
329
330impl ComputePipeline {
331 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
332 self.raw.as_ref()
333 }
334
335 pub fn get_bind_group_layout(
336 self: &Arc<Self>,
337 index: u32,
338 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
339 self.layout.get_bind_group_layout(index, self.into())
340 }
341}
342
343#[derive(Clone, Debug, Error)]
344#[non_exhaustive]
345pub enum CreatePipelineCacheError {
346 #[error(transparent)]
347 Device(#[from] DeviceError),
348 #[error("Pipeline cache validation failed")]
349 Validation(#[from] PipelineCacheValidationError),
350 #[error(transparent)]
351 MissingFeatures(#[from] MissingFeatures),
352}
353
354impl WebGpuError for CreatePipelineCacheError {
355 fn webgpu_error_type(&self) -> ErrorType {
356 match self {
357 Self::Device(e) => e.webgpu_error_type(),
358 Self::Validation(e) => e.webgpu_error_type(),
359 Self::MissingFeatures(e) => e.webgpu_error_type(),
360 }
361 }
362}
363
364#[derive(Debug)]
365pub struct PipelineCache {
366 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
367 pub(crate) device: Arc<Device>,
368 pub(crate) label: String,
370}
371
372impl Drop for PipelineCache {
373 fn drop(&mut self) {
374 resource_log!("Destroy raw {}", self.error_ident());
375 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
377 unsafe {
378 self.device.raw().destroy_pipeline_cache(raw);
379 }
380 }
381}
382
383crate::impl_resource_type!(PipelineCache);
384crate::impl_labeled!(PipelineCache);
385crate::impl_parent_device!(PipelineCache);
386crate::impl_storage_item!(PipelineCache);
387
388impl PipelineCache {
389 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
390 self.raw.as_ref()
391 }
392}
393
394#[derive(Clone, Debug)]
396#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
397#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
398pub struct VertexBufferLayout<'a> {
399 pub array_stride: wgt::BufferAddress,
401 pub step_mode: wgt::VertexStepMode,
403 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
405}
406
407impl Default for VertexBufferLayout<'_> {
409 fn default() -> Self {
410 Self {
411 array_stride: Default::default(),
412 step_mode: Default::default(),
413 attributes: Cow::Borrowed(&[]),
414 }
415 }
416}
417
418#[derive(Clone, Debug)]
420#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
421pub struct VertexState<'a, SM = ShaderModuleId> {
422 pub stage: ProgrammableStageDescriptor<'a, SM>,
424 pub buffers: Cow<'a, [Option<VertexBufferLayout<'a>>]>,
426}
427
428pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
430
431#[derive(Clone, Debug)]
433#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
434pub struct FragmentState<'a, SM = ShaderModuleId> {
435 pub stage: ProgrammableStageDescriptor<'a, SM>,
437 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
439}
440
441pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
443
444#[derive(Clone, Debug)]
446#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
447pub struct TaskState<'a, SM = ShaderModuleId> {
448 pub stage: ProgrammableStageDescriptor<'a, SM>,
450}
451
452pub type ResolvedTaskState<'a> = TaskState<'a, Arc<ShaderModule>>;
453
454#[derive(Clone, Debug)]
456#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
457pub struct MeshState<'a, SM = ShaderModuleId> {
458 pub stage: ProgrammableStageDescriptor<'a, SM>,
460}
461
462pub type ResolvedMeshState<'a> = MeshState<'a, Arc<ShaderModule>>;
463
464#[doc(hidden)]
472#[derive(Clone, Debug)]
473#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
474pub enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> {
475 Vertex(VertexState<'a, SM>),
476 Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>),
477}
478
479#[derive(Clone, Debug)]
481#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
482pub struct RenderPipelineDescriptor<
483 'a,
484 PLL = PipelineLayoutId,
485 SM = ShaderModuleId,
486 PLC = PipelineCacheId,
487> {
488 pub label: Label<'a>,
489 pub layout: Option<PLL>,
491 pub vertex: VertexState<'a, SM>,
493 #[cfg_attr(feature = "serde", serde(default))]
495 pub primitive: wgt::PrimitiveState,
496 #[cfg_attr(feature = "serde", serde(default))]
498 pub depth_stencil: Option<wgt::DepthStencilState>,
499 #[cfg_attr(feature = "serde", serde(default))]
501 pub multisample: wgt::MultisampleState,
502 pub fragment: Option<FragmentState<'a, SM>>,
504 pub multiview_mask: Option<NonZeroU32>,
507 pub cache: Option<PLC>,
509}
510#[derive(Clone, Debug)]
512#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
513pub struct MeshPipelineDescriptor<
514 'a,
515 PLL = PipelineLayoutId,
516 SM = ShaderModuleId,
517 PLC = PipelineCacheId,
518> {
519 pub label: Label<'a>,
520 pub layout: Option<PLL>,
522 pub task: Option<TaskState<'a, SM>>,
524 pub mesh: MeshState<'a, SM>,
526 #[cfg_attr(feature = "serde", serde(default))]
528 pub primitive: wgt::PrimitiveState,
529 #[cfg_attr(feature = "serde", serde(default))]
531 pub depth_stencil: Option<wgt::DepthStencilState>,
532 #[cfg_attr(feature = "serde", serde(default))]
534 pub multisample: wgt::MultisampleState,
535 pub fragment: Option<FragmentState<'a, SM>>,
537 pub multiview: Option<NonZeroU32>,
540 pub cache: Option<PLC>,
542}
543
544#[doc(hidden)]
552#[derive(Clone, Debug)]
553#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
554pub struct GeneralRenderPipelineDescriptor<
555 'a,
556 PLL = PipelineLayoutId,
557 SM = ShaderModuleId,
558 PLC = PipelineCacheId,
559> {
560 pub label: Label<'a>,
561 pub layout: Option<PLL>,
563 pub vertex: RenderPipelineVertexProcessor<'a, SM>,
565 #[cfg_attr(feature = "serde", serde(default))]
567 pub primitive: wgt::PrimitiveState,
568 #[cfg_attr(feature = "serde", serde(default))]
570 pub depth_stencil: Option<wgt::DepthStencilState>,
571 #[cfg_attr(feature = "serde", serde(default))]
573 pub multisample: wgt::MultisampleState,
574 pub fragment: Option<FragmentState<'a, SM>>,
576 pub multiview_mask: Option<NonZeroU32>,
579 pub cache: Option<PLC>,
581}
582impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
583 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
584{
585 fn from(value: RenderPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
586 Self {
587 label: value.label,
588 layout: value.layout,
589 vertex: RenderPipelineVertexProcessor::Vertex(value.vertex),
590 primitive: value.primitive,
591 depth_stencil: value.depth_stencil,
592 multisample: value.multisample,
593 fragment: value.fragment,
594 multiview_mask: value.multiview_mask,
595 cache: value.cache,
596 }
597 }
598}
599impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
600 for GeneralRenderPipelineDescriptor<'a, PLL, SM, PLC>
601{
602 fn from(value: MeshPipelineDescriptor<'a, PLL, SM, PLC>) -> Self {
603 Self {
604 label: value.label,
605 layout: value.layout,
606 vertex: RenderPipelineVertexProcessor::Mesh(value.task, value.mesh),
607 primitive: value.primitive,
608 depth_stencil: value.depth_stencil,
609 multisample: value.multisample,
610 fragment: value.fragment,
611 multiview_mask: value.multiview,
612 cache: value.cache,
613 }
614 }
615}
616
617pub type ResolvedGeneralRenderPipelineDescriptor<'a> =
621 GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
622
623#[derive(Clone, Debug)]
624#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
625pub struct PipelineCacheDescriptor<'a> {
626 pub label: Label<'a>,
627 pub data: Option<Cow<'a, [u8]>>,
628 pub fallback: bool,
629}
630
631#[derive(Clone, Debug, Error)]
632#[non_exhaustive]
633pub enum ColorStateError {
634 #[error("Format {0:?} is not renderable")]
635 FormatNotRenderable(wgt::TextureFormat),
636 #[error("Format {0:?} is not blendable")]
637 FormatNotBlendable(wgt::TextureFormat),
638 #[error("Format {0:?} does not have a color aspect")]
639 FormatNotColor(wgt::TextureFormat),
640 #[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:?}.")]
641 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
642 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
643 IncompatibleFormat {
644 pipeline: validation::NumericType,
645 shader: validation::NumericType,
646 },
647 #[error("Invalid write mask {0:?}")]
648 InvalidWriteMask(wgt::ColorWrites),
649 #[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.")]
650 BlendFactorOnUnsupportedTarget {
651 factor: wgt::BlendFactor,
652 target: u32,
653 },
654 #[error(
655 "Blend factor {factor:?} for render target {target} is not valid. Blend factor must be `one` when using min/max blend operations."
656 )]
657 InvalidMinMaxBlendFactor {
658 factor: wgt::BlendFactor,
659 target: u32,
660 },
661}
662
663#[derive(Clone, Debug, Error)]
664#[non_exhaustive]
665pub enum DepthStencilStateError {
666 #[error("Format {0:?} is not renderable")]
667 FormatNotRenderable(wgt::TextureFormat),
668 #[error("Format {0:?} is not a depth/stencil format")]
669 FormatNotDepthOrStencil(wgt::TextureFormat),
670 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
671 FormatNotDepth(wgt::TextureFormat),
672 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
673 FormatNotStencil(wgt::TextureFormat),
674 #[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:?}.")]
675 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
676 #[error("Depth bias is not compatible with non-triangle topology {0:?}")]
677 DepthBiasWithIncompatibleTopology(wgt::PrimitiveTopology),
678 #[error("Depth compare function must be specified for depth format {0:?}")]
679 MissingDepthCompare(wgt::TextureFormat),
680 #[error("Depth write enabled must be specified for depth format {0:?}")]
681 MissingDepthWriteEnabled(wgt::TextureFormat),
682}
683
684#[derive(Clone, Debug, Error)]
685#[non_exhaustive]
686pub enum CreateRenderPipelineError {
687 #[error(transparent)]
688 ColorAttachment(#[from] ColorAttachmentError),
689 #[error(transparent)]
690 Device(#[from] DeviceError),
691 #[error("Unable to derive an implicit layout")]
692 Implicit(#[from] ImplicitLayoutError),
693 #[error("Color state [{0}] is invalid")]
694 ColorState(u8, #[source] ColorStateError),
695 #[error("Depth/stencil state is invalid")]
696 DepthStencilState(#[from] DepthStencilStateError),
697 #[error("Invalid sample count {0}")]
698 InvalidSampleCount(u32),
699 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
700 TooManyVertexBuffers { given: u32, limit: u32 },
701 #[error("The number of bind groups + vertex buffers {given} exceeds the limit {limit}")]
702 TooManyBindGroupsPlusVertexBuffers { given: u32, limit: u32 },
703 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
704 TooManyVertexAttributes { given: u32, limit: u32 },
705 #[error("Vertex attribute location {given} must be less than limit {limit}")]
706 VertexAttributeLocationTooLarge { given: u32, limit: u32 },
707 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
708 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
709 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
710 VertexAttributeStrideTooLarge {
711 location: wgt::ShaderLocation,
712 given: u32,
713 limit: u32,
714 },
715 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
716 UnalignedVertexStride {
717 index: u32,
718 stride: wgt::BufferAddress,
719 },
720 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
721 InvalidVertexAttributeOffset {
722 location: wgt::ShaderLocation,
723 offset: wgt::BufferAddress,
724 },
725 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
726 ShaderLocationClash(u32),
727 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
728 StripIndexFormatForNonStripTopology {
729 strip_index_format: Option<wgt::IndexFormat>,
730 topology: wgt::PrimitiveTopology,
731 },
732 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
733 ConservativeRasterizationNonFillPolygonMode,
734 #[error(transparent)]
735 MissingFeatures(#[from] MissingFeatures),
736 #[error(transparent)]
737 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
738 #[error("Error matching {stage:?} shader requirements against the pipeline")]
739 Stage {
740 stage: wgt::ShaderStages,
741 #[source]
742 error: validation::StageError,
743 },
744 #[error("Internal error in {stage:?} shader: {error}")]
745 Internal {
746 stage: wgt::ShaderStages,
747 error: String,
748 },
749 #[error("Pipeline constant error in {stage:?} shader: {error}")]
750 PipelineConstants {
751 stage: wgt::ShaderStages,
752 error: String,
753 },
754 #[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.")]
755 UnalignedShader { group: u32, binding: u32, size: u64 },
756 #[error("Dual-source blending requires exactly one color target, but {count} color targets are present")]
757 DualSourceBlendingWithMultipleColorTargets { count: usize },
758 #[error("{}", concat!(
759 "At least one color attachment or depth-stencil attachment was expected, ",
760 "but no render target for the pipeline was specified."
761 ))]
762 NoTargetSpecified,
763 #[error(transparent)]
764 InvalidResource(#[from] InvalidResourceError),
765}
766
767impl WebGpuError for CreateRenderPipelineError {
768 fn webgpu_error_type(&self) -> ErrorType {
769 match self {
770 Self::Device(e) => e.webgpu_error_type(),
771 Self::InvalidResource(e) => e.webgpu_error_type(),
772 Self::MissingFeatures(e) => e.webgpu_error_type(),
773 Self::MissingDownlevelFlags(e) => e.webgpu_error_type(),
774
775 Self::Internal { .. } => ErrorType::Internal,
776
777 Self::ColorAttachment(_)
778 | Self::Implicit(_)
779 | Self::ColorState(_, _)
780 | Self::DepthStencilState(_)
781 | Self::InvalidSampleCount(_)
782 | Self::TooManyVertexBuffers { .. }
783 | Self::TooManyBindGroupsPlusVertexBuffers { .. }
784 | Self::TooManyVertexAttributes { .. }
785 | Self::VertexAttributeLocationTooLarge { .. }
786 | Self::VertexStrideTooLarge { .. }
787 | Self::UnalignedVertexStride { .. }
788 | Self::InvalidVertexAttributeOffset { .. }
789 | Self::ShaderLocationClash(_)
790 | Self::StripIndexFormatForNonStripTopology { .. }
791 | Self::ConservativeRasterizationNonFillPolygonMode
792 | Self::Stage { .. }
793 | Self::UnalignedShader { .. }
794 | Self::DualSourceBlendingWithMultipleColorTargets { .. }
795 | Self::NoTargetSpecified
796 | Self::PipelineConstants { .. }
797 | Self::VertexAttributeStrideTooLarge { .. } => ErrorType::Validation,
798 }
799 }
800}
801
802bitflags::bitflags! {
803 #[repr(transparent)]
804 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
805 pub struct PipelineFlags: u32 {
806 const BLEND_CONSTANT = 1 << 0;
807 const STENCIL_REFERENCE = 1 << 1;
808 const WRITES_DEPTH = 1 << 2;
809 const WRITES_STENCIL = 1 << 3;
810 }
811}
812
813#[derive(Clone, Copy, Debug)]
815pub struct VertexStep {
816 pub stride: wgt::BufferAddress,
818
819 pub last_stride: wgt::BufferAddress,
821
822 pub mode: wgt::VertexStepMode,
824}
825
826impl Default for VertexStep {
827 fn default() -> Self {
828 Self {
829 stride: 0,
830 last_stride: 0,
831 mode: wgt::VertexStepMode::Vertex,
832 }
833 }
834}
835
836#[derive(Debug)]
837pub struct RenderPipeline {
838 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
839 pub(crate) device: Arc<Device>,
840 pub(crate) layout: Arc<PipelineLayout>,
841 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
842 pub(crate) pass_context: RenderPassContext,
843 pub(crate) flags: PipelineFlags,
844 pub(crate) topology: wgt::PrimitiveTopology,
845 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
846 pub(crate) vertex_steps: Vec<Option<VertexStep>>,
847 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
848 pub(crate) immediate_slots_required: naga::valid::ImmediateSlots,
849 pub(crate) label: String,
851 pub(crate) tracking_data: TrackingData,
852 pub(crate) is_mesh: bool,
854 pub(crate) has_task_shader: bool,
855}
856
857impl Drop for RenderPipeline {
858 fn drop(&mut self) {
859 resource_log!("Destroy raw {}", self.error_ident());
860 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
862 unsafe {
863 self.device.raw().destroy_render_pipeline(raw);
864 }
865 }
866}
867
868crate::impl_resource_type!(RenderPipeline);
869crate::impl_labeled!(RenderPipeline);
870crate::impl_parent_device!(RenderPipeline);
871crate::impl_storage_item!(RenderPipeline);
872crate::impl_trackable!(RenderPipeline);
873
874impl RenderPipeline {
875 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
876 self.raw.as_ref()
877 }
878
879 pub fn get_bind_group_layout(
880 self: &Arc<Self>,
881 index: u32,
882 ) -> Result<Arc<BindGroupLayout>, GetBindGroupLayoutError> {
883 self.layout.get_bind_group_layout(index, self.into())
884 }
885}