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;
13
14pub use crate::pipeline_cache::PipelineCacheValidationError;
15use crate::{
16 binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError, PipelineLayout},
17 command::ColorAttachmentError,
18 device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext},
19 id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId},
20 resource::{InvalidResourceError, Labeled, TrackingData},
21 resource_log, validation, Label,
22};
23
24#[derive(Debug)]
28pub(crate) struct LateSizedBufferGroup {
29 pub(crate) shader_sizes: Vec<wgt::BufferAddress>,
31}
32
33#[allow(clippy::large_enum_variant)]
34pub enum ShaderModuleSource<'a> {
35 #[cfg(feature = "wgsl")]
36 Wgsl(Cow<'a, str>),
37 #[cfg(feature = "glsl")]
38 Glsl(Cow<'a, str>, naga::front::glsl::Options),
39 #[cfg(feature = "spirv")]
40 SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
41 Naga(Cow<'static, naga::Module>),
42 #[doc(hidden)]
45 Dummy(PhantomData<&'a ()>),
46}
47
48#[derive(Clone, Debug)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct ShaderModuleDescriptor<'a> {
51 pub label: Label<'a>,
52 #[cfg_attr(feature = "serde", serde(default))]
53 pub runtime_checks: wgt::ShaderRuntimeChecks,
54}
55
56pub type ShaderModuleDescriptorPassthrough<'a> =
57 wgt::CreateShaderModuleDescriptorPassthrough<'a, Label<'a>>;
58
59#[derive(Debug)]
60pub struct ShaderModule {
61 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynShaderModule>>,
62 pub(crate) device: Arc<Device>,
63 pub(crate) interface: Option<validation::Interface>,
64 pub(crate) label: String,
66}
67
68impl Drop for ShaderModule {
69 fn drop(&mut self) {
70 resource_log!("Destroy raw {}", self.error_ident());
71 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
73 unsafe {
74 self.device.raw().destroy_shader_module(raw);
75 }
76 }
77}
78
79crate::impl_resource_type!(ShaderModule);
80crate::impl_labeled!(ShaderModule);
81crate::impl_parent_device!(ShaderModule);
82crate::impl_storage_item!(ShaderModule);
83
84impl ShaderModule {
85 pub(crate) fn raw(&self) -> &dyn hal::DynShaderModule {
86 self.raw.as_ref()
87 }
88
89 pub(crate) fn finalize_entry_point_name(
90 &self,
91 stage_bit: wgt::ShaderStages,
92 entry_point: Option<&str>,
93 ) -> Result<String, validation::StageError> {
94 match &self.interface {
95 Some(interface) => interface.finalize_entry_point_name(stage_bit, entry_point),
96 None => entry_point
97 .map(|ep| ep.to_string())
98 .ok_or(validation::StageError::NoEntryPointFound),
99 }
100 }
101}
102
103#[derive(Clone, Debug, Error)]
105#[non_exhaustive]
106pub enum CreateShaderModuleError {
107 #[cfg(feature = "wgsl")]
108 #[error(transparent)]
109 Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
110 #[cfg(feature = "glsl")]
111 #[error(transparent)]
112 ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
113 #[cfg(feature = "spirv")]
114 #[error(transparent)]
115 ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
116 #[error("Failed to generate the backend-specific code")]
117 Generation,
118 #[error(transparent)]
119 Device(#[from] DeviceError),
120 #[error(transparent)]
121 Validation(#[from] ShaderError<naga::WithSpan<naga::valid::ValidationError>>),
122 #[error(transparent)]
123 MissingFeatures(#[from] MissingFeatures),
124 #[error(
125 "Shader global {bind:?} uses a group index {group} that exceeds the max_bind_groups limit of {limit}."
126 )]
127 InvalidGroupIndex {
128 bind: naga::ResourceBinding,
129 group: u32,
130 limit: u32,
131 },
132}
133
134#[derive(Clone, Debug)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
138 pub module: SM,
140 pub entry_point: Option<Cow<'a, str>>,
147 pub constants: naga::back::PipelineConstants,
155 pub zero_initialize_workgroup_memory: bool,
160}
161
162pub type ResolvedProgrammableStageDescriptor<'a> =
164 ProgrammableStageDescriptor<'a, Arc<ShaderModule>>;
165
166pub type ImplicitBindGroupCount = u8;
168
169#[derive(Clone, Debug, Error)]
170#[non_exhaustive]
171pub enum ImplicitLayoutError {
172 #[error("The implicit_pipeline_ids arg is required")]
173 MissingImplicitPipelineIds,
174 #[error("Missing IDs for deriving {0} bind groups")]
175 MissingIds(ImplicitBindGroupCount),
176 #[error("Unable to reflect the shader {0:?} interface")]
177 ReflectionError(wgt::ShaderStages),
178 #[error(transparent)]
179 BindGroup(#[from] CreateBindGroupLayoutError),
180 #[error(transparent)]
181 Pipeline(#[from] CreatePipelineLayoutError),
182}
183
184#[derive(Clone, Debug)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
187pub struct ComputePipelineDescriptor<
188 'a,
189 PLL = PipelineLayoutId,
190 SM = ShaderModuleId,
191 PLC = PipelineCacheId,
192> {
193 pub label: Label<'a>,
194 pub layout: Option<PLL>,
196 pub stage: ProgrammableStageDescriptor<'a, SM>,
198 pub cache: Option<PLC>,
200}
201
202pub type ResolvedComputePipelineDescriptor<'a> =
204 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
205
206#[derive(Clone, Debug, Error)]
207#[non_exhaustive]
208pub enum CreateComputePipelineError {
209 #[error(transparent)]
210 Device(#[from] DeviceError),
211 #[error("Unable to derive an implicit layout")]
212 Implicit(#[from] ImplicitLayoutError),
213 #[error("Error matching shader requirements against the pipeline")]
214 Stage(#[from] validation::StageError),
215 #[error("Internal error: {0}")]
216 Internal(String),
217 #[error("Pipeline constant error: {0}")]
218 PipelineConstants(String),
219 #[error(transparent)]
220 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
221 #[error(transparent)]
222 InvalidResource(#[from] InvalidResourceError),
223}
224
225#[derive(Debug)]
226pub struct ComputePipeline {
227 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
228 pub(crate) layout: Arc<PipelineLayout>,
229 pub(crate) device: Arc<Device>,
230 pub(crate) _shader_module: Arc<ShaderModule>,
231 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
232 pub(crate) label: String,
234 pub(crate) tracking_data: TrackingData,
235}
236
237impl Drop for ComputePipeline {
238 fn drop(&mut self) {
239 resource_log!("Destroy raw {}", self.error_ident());
240 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
242 unsafe {
243 self.device.raw().destroy_compute_pipeline(raw);
244 }
245 }
246}
247
248crate::impl_resource_type!(ComputePipeline);
249crate::impl_labeled!(ComputePipeline);
250crate::impl_parent_device!(ComputePipeline);
251crate::impl_storage_item!(ComputePipeline);
252crate::impl_trackable!(ComputePipeline);
253
254impl ComputePipeline {
255 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
256 self.raw.as_ref()
257 }
258}
259
260#[derive(Clone, Debug, Error)]
261#[non_exhaustive]
262pub enum CreatePipelineCacheError {
263 #[error(transparent)]
264 Device(#[from] DeviceError),
265 #[error("Pipeline cache validation failed")]
266 Validation(#[from] PipelineCacheValidationError),
267 #[error(transparent)]
268 MissingFeatures(#[from] MissingFeatures),
269}
270
271#[derive(Debug)]
272pub struct PipelineCache {
273 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
274 pub(crate) device: Arc<Device>,
275 pub(crate) label: String,
277}
278
279impl Drop for PipelineCache {
280 fn drop(&mut self) {
281 resource_log!("Destroy raw {}", self.error_ident());
282 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
284 unsafe {
285 self.device.raw().destroy_pipeline_cache(raw);
286 }
287 }
288}
289
290crate::impl_resource_type!(PipelineCache);
291crate::impl_labeled!(PipelineCache);
292crate::impl_parent_device!(PipelineCache);
293crate::impl_storage_item!(PipelineCache);
294
295impl PipelineCache {
296 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
297 self.raw.as_ref()
298 }
299}
300
301#[derive(Clone, Debug)]
303#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
304#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
305pub struct VertexBufferLayout<'a> {
306 pub array_stride: wgt::BufferAddress,
308 pub step_mode: wgt::VertexStepMode,
310 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
312}
313
314#[derive(Clone, Debug)]
316#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
317pub struct VertexState<'a, SM = ShaderModuleId> {
318 pub stage: ProgrammableStageDescriptor<'a, SM>,
320 pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
322}
323
324pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
326
327#[derive(Clone, Debug)]
329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
330pub struct FragmentState<'a, SM = ShaderModuleId> {
331 pub stage: ProgrammableStageDescriptor<'a, SM>,
333 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
335}
336
337pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
339
340#[derive(Clone, Debug)]
342#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
343pub struct RenderPipelineDescriptor<
344 'a,
345 PLL = PipelineLayoutId,
346 SM = ShaderModuleId,
347 PLC = PipelineCacheId,
348> {
349 pub label: Label<'a>,
350 pub layout: Option<PLL>,
352 pub vertex: VertexState<'a, SM>,
354 #[cfg_attr(feature = "serde", serde(default))]
356 pub primitive: wgt::PrimitiveState,
357 #[cfg_attr(feature = "serde", serde(default))]
359 pub depth_stencil: Option<wgt::DepthStencilState>,
360 #[cfg_attr(feature = "serde", serde(default))]
362 pub multisample: wgt::MultisampleState,
363 pub fragment: Option<FragmentState<'a, SM>>,
365 pub multiview: Option<NonZeroU32>,
368 pub cache: Option<PLC>,
370}
371
372pub type ResolvedRenderPipelineDescriptor<'a> =
374 RenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
375
376#[derive(Clone, Debug)]
377#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
378pub struct PipelineCacheDescriptor<'a> {
379 pub label: Label<'a>,
380 pub data: Option<Cow<'a, [u8]>>,
381 pub fallback: bool,
382}
383
384#[derive(Clone, Debug, Error)]
385#[non_exhaustive]
386pub enum ColorStateError {
387 #[error("Format {0:?} is not renderable")]
388 FormatNotRenderable(wgt::TextureFormat),
389 #[error("Format {0:?} is not blendable")]
390 FormatNotBlendable(wgt::TextureFormat),
391 #[error("Format {0:?} does not have a color aspect")]
392 FormatNotColor(wgt::TextureFormat),
393 #[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:?}.")]
394 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
395 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
396 IncompatibleFormat {
397 pipeline: validation::NumericType,
398 shader: validation::NumericType,
399 },
400 #[error("Invalid write mask {0:?}")]
401 InvalidWriteMask(wgt::ColorWrites),
402}
403
404#[derive(Clone, Debug, Error)]
405#[non_exhaustive]
406pub enum DepthStencilStateError {
407 #[error("Format {0:?} is not renderable")]
408 FormatNotRenderable(wgt::TextureFormat),
409 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
410 FormatNotDepth(wgt::TextureFormat),
411 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
412 FormatNotStencil(wgt::TextureFormat),
413 #[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:?}.")]
414 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
415}
416
417#[derive(Clone, Debug, Error)]
418#[non_exhaustive]
419pub enum CreateRenderPipelineError {
420 #[error(transparent)]
421 ColorAttachment(#[from] ColorAttachmentError),
422 #[error(transparent)]
423 Device(#[from] DeviceError),
424 #[error("Unable to derive an implicit layout")]
425 Implicit(#[from] ImplicitLayoutError),
426 #[error("Color state [{0}] is invalid")]
427 ColorState(u8, #[source] ColorStateError),
428 #[error("Depth/stencil state is invalid")]
429 DepthStencilState(#[from] DepthStencilStateError),
430 #[error("Invalid sample count {0}")]
431 InvalidSampleCount(u32),
432 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
433 TooManyVertexBuffers { given: u32, limit: u32 },
434 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
435 TooManyVertexAttributes { given: u32, limit: u32 },
436 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
437 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
438 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
439 VertexAttributeStrideTooLarge {
440 location: wgt::ShaderLocation,
441 given: u32,
442 limit: u32,
443 },
444 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
445 UnalignedVertexStride {
446 index: u32,
447 stride: wgt::BufferAddress,
448 },
449 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
450 InvalidVertexAttributeOffset {
451 location: wgt::ShaderLocation,
452 offset: wgt::BufferAddress,
453 },
454 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
455 ShaderLocationClash(u32),
456 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
457 StripIndexFormatForNonStripTopology {
458 strip_index_format: Option<wgt::IndexFormat>,
459 topology: wgt::PrimitiveTopology,
460 },
461 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
462 ConservativeRasterizationNonFillPolygonMode,
463 #[error(transparent)]
464 MissingFeatures(#[from] MissingFeatures),
465 #[error(transparent)]
466 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
467 #[error("Error matching {stage:?} shader requirements against the pipeline")]
468 Stage {
469 stage: wgt::ShaderStages,
470 #[source]
471 error: validation::StageError,
472 },
473 #[error("Internal error in {stage:?} shader: {error}")]
474 Internal {
475 stage: wgt::ShaderStages,
476 error: String,
477 },
478 #[error("Pipeline constant error in {stage:?} shader: {error}")]
479 PipelineConstants {
480 stage: wgt::ShaderStages,
481 error: String,
482 },
483 #[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.")]
484 UnalignedShader { group: u32, binding: u32, size: u64 },
485 #[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.")]
486 BlendFactorOnUnsupportedTarget {
487 factor: wgt::BlendFactor,
488 target: u32,
489 },
490 #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
491 PipelineExpectsShaderToUseDualSourceBlending,
492 #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
493 ShaderExpectsPipelineToUseDualSourceBlending,
494 #[error("{}", concat!(
495 "At least one color attachment or depth-stencil attachment was expected, ",
496 "but no render target for the pipeline was specified."
497 ))]
498 NoTargetSpecified,
499 #[error(transparent)]
500 InvalidResource(#[from] InvalidResourceError),
501}
502
503bitflags::bitflags! {
504 #[repr(transparent)]
505 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
506 pub struct PipelineFlags: u32 {
507 const BLEND_CONSTANT = 1 << 0;
508 const STENCIL_REFERENCE = 1 << 1;
509 const WRITES_DEPTH = 1 << 2;
510 const WRITES_STENCIL = 1 << 3;
511 }
512}
513
514#[derive(Clone, Copy, Debug)]
516pub struct VertexStep {
517 pub stride: wgt::BufferAddress,
519
520 pub last_stride: wgt::BufferAddress,
522
523 pub mode: wgt::VertexStepMode,
525}
526
527impl Default for VertexStep {
528 fn default() -> Self {
529 Self {
530 stride: 0,
531 last_stride: 0,
532 mode: wgt::VertexStepMode::Vertex,
533 }
534 }
535}
536
537#[derive(Debug)]
538pub struct RenderPipeline {
539 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
540 pub(crate) device: Arc<Device>,
541 pub(crate) layout: Arc<PipelineLayout>,
542 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
543 pub(crate) pass_context: RenderPassContext,
544 pub(crate) flags: PipelineFlags,
545 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
546 pub(crate) vertex_steps: Vec<VertexStep>,
547 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
548 pub(crate) label: String,
550 pub(crate) tracking_data: TrackingData,
551}
552
553impl Drop for RenderPipeline {
554 fn drop(&mut self) {
555 resource_log!("Destroy raw {}", self.error_ident());
556 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
558 unsafe {
559 self.device.raw().destroy_render_pipeline(raw);
560 }
561 }
562}
563
564crate::impl_resource_type!(RenderPipeline);
565crate::impl_labeled!(RenderPipeline);
566crate::impl_parent_device!(RenderPipeline);
567crate::impl_storage_item!(RenderPipeline);
568crate::impl_trackable!(RenderPipeline);
569
570impl RenderPipeline {
571 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
572 self.raw.as_ref()
573 }
574}