wgpu_core/validation/
shader_io_deductions.rs1use core::fmt::{self, Debug, Display, Formatter};
2
3#[cfg(doc)]
4#[expect(unused_imports)]
5use crate::validation::StageError;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum MaxVertexShaderOutputDeduction {
12 PointListPrimitiveTopology,
15}
16
17impl MaxVertexShaderOutputDeduction {
18 pub fn for_variables(self) -> u32 {
19 match self {
20 Self::PointListPrimitiveTopology => 1,
21 }
22 }
23
24 pub fn for_location(self) -> u32 {
25 match self {
26 Self::PointListPrimitiveTopology => 0,
27 }
28 }
29}
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum MaxFragmentShaderInputDeduction {
36 InterStageBuiltIn(InterStageBuiltIn),
37}
38
39impl MaxFragmentShaderInputDeduction {
40 pub fn for_variables(self) -> u32 {
41 match self {
42 Self::InterStageBuiltIn(builtin) => match builtin {
43 InterStageBuiltIn::FrontFacing
44 | InterStageBuiltIn::SampleIndex
45 | InterStageBuiltIn::SampleMask
46 | InterStageBuiltIn::PrimitiveIndex
47 | InterStageBuiltIn::SubgroupInvocationId
48 | InterStageBuiltIn::SubgroupSize
49 | InterStageBuiltIn::ViewIndex
50 | InterStageBuiltIn::PointCoord => 1,
51 InterStageBuiltIn::Barycentric => 3,
52 InterStageBuiltIn::Position => 0,
53 },
54 }
55 }
56
57 pub fn from_inter_stage_builtin(builtin: naga::BuiltIn) -> Option<Self> {
58 use naga::BuiltIn;
59
60 Some(Self::InterStageBuiltIn(match builtin {
61 BuiltIn::Position { .. } => InterStageBuiltIn::Position,
62 BuiltIn::FrontFacing => InterStageBuiltIn::FrontFacing,
63 BuiltIn::SampleIndex => InterStageBuiltIn::SampleIndex,
64 BuiltIn::SampleMask => InterStageBuiltIn::SampleMask,
65 BuiltIn::PrimitiveIndex => InterStageBuiltIn::PrimitiveIndex,
66 BuiltIn::SubgroupSize => InterStageBuiltIn::SubgroupSize,
67 BuiltIn::SubgroupInvocationId => InterStageBuiltIn::SubgroupInvocationId,
68 BuiltIn::PointCoord => InterStageBuiltIn::PointCoord,
69 BuiltIn::Barycentric { .. } => InterStageBuiltIn::Barycentric,
70 BuiltIn::ViewIndex => InterStageBuiltIn::ViewIndex,
71 BuiltIn::BaseInstance
72 | BuiltIn::BaseVertex
73 | BuiltIn::ClipDistance
74 | BuiltIn::CullDistance
75 | BuiltIn::InstanceIndex
76 | BuiltIn::PointSize
77 | BuiltIn::VertexIndex
78 | BuiltIn::DrawIndex
79 | BuiltIn::FragDepth
80 | BuiltIn::GlobalInvocationId
81 | BuiltIn::LocalInvocationId
82 | BuiltIn::LocalInvocationIndex
83 | BuiltIn::WorkGroupId
84 | BuiltIn::WorkGroupSize
85 | BuiltIn::NumWorkGroups
86 | BuiltIn::NumSubgroups
87 | BuiltIn::SubgroupId
88 | BuiltIn::MeshTaskSize
89 | BuiltIn::CullPrimitive
90 | BuiltIn::PointIndex
91 | BuiltIn::LineIndices
92 | BuiltIn::TriangleIndices
93 | BuiltIn::VertexCount
94 | BuiltIn::Vertices
95 | BuiltIn::PrimitiveCount
96 | BuiltIn::Primitives
97 | BuiltIn::RayInvocationId
98 | BuiltIn::NumRayInvocations
99 | BuiltIn::InstanceCustomData
100 | BuiltIn::GeometryIndex
101 | BuiltIn::WorldRayOrigin
102 | BuiltIn::WorldRayDirection
103 | BuiltIn::ObjectRayOrigin
104 | BuiltIn::ObjectRayDirection
105 | BuiltIn::RayTmin
106 | BuiltIn::RayTCurrentMax
107 | BuiltIn::ObjectToWorld
108 | BuiltIn::WorldToObject
109 | BuiltIn::HitKind => return None,
110 }))
111 }
112}
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
119pub enum InterStageBuiltIn {
120 Position,
122 FrontFacing,
123 SampleIndex,
124 SampleMask,
125 PrimitiveIndex,
126 SubgroupInvocationId,
127 SubgroupSize,
128
129 PointCoord,
131 Barycentric,
132 ViewIndex,
133}
134
135pub(in crate::validation) fn display_deductions_as_optional_list<T>(
136 deductions: &[T],
137 accessor: fn(&T) -> u32,
138) -> impl Display + '_
139where
140 T: Debug,
141{
142 struct DisplayFromFn<F>(F);
143
144 impl<F> Display for DisplayFromFn<F>
145 where
146 F: Fn(&mut Formatter<'_>) -> fmt::Result,
147 {
148 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
149 let Self(inner) = self;
150 inner(f)
151 }
152 }
153
154 DisplayFromFn(move |f: &mut Formatter<'_>| {
155 let relevant_deductions = deductions
156 .iter()
157 .map(|deduction| (deduction, accessor(deduction)))
158 .filter(|(_, effective_deduction)| *effective_deduction > 0);
159 if relevant_deductions.clone().next().is_some() {
160 writeln!(f, "; note that some deductions apply during validation:")?;
161 let mut wrote_something = false;
162 for deduction in deductions {
163 let deducted_amount = accessor(deduction);
164 if deducted_amount > 0 {
165 writeln!(f, "\n- {deduction:?}: {}", accessor(deduction))?;
166 wrote_something = true;
167 }
168 }
169 debug_assert!(
170 wrote_something,
171 "no substantial deductions found in error display"
172 );
173 }
174 Ok(())
175 })
176}