1#![allow(non_snake_case)]
11
12use crate::{
13 CallSignature, Error,
14 conv::{Convert, convert_all_ty, convert_ty},
15 syntax::*,
16 tplt::{BitcastTemplate, TpltParam},
17 ty::{StructMemberType, StructType, TextureDimensions, TextureType, Ty, Type},
18};
19
20type E = Error;
21
22pub fn type_builtin_fn(
30 name: &str,
31 tplt: Option<&[TpltParam]>,
32 args: &[Type],
33) -> Result<Option<Type>, E> {
34 let err = || {
35 E::Signature(CallSignature {
36 name: name.to_string(),
37 tplt: tplt.map(|t| t.to_vec()),
38 args: args.to_vec(),
39 })
40 };
41
42 match (name, args) {
43 ("bitcast", [a]) if let Some(tplt) = tplt => {
45 let tplt = BitcastTemplate::parse(tplt)?;
46 bitcast_t(tplt.ty(), a).map(Some)
47 }
48 _ if tplt.is_some() => Err(err()),
49 ("all", [a]) => all(a).map(Some),
51 ("any", [a]) => any(a).map(Some),
52 ("select", [a1, a2, a3]) => select(a1, a2, a3).map(Some),
53 ("arrayLength", [a]) => arrayLength(a).map(Some),
55 ("abs", [a]) => abs(a).map(Some),
57 ("acos", [a]) => acos(a).map(Some),
58 ("acosh", [a]) => acosh(a).map(Some),
59 ("asin", [a]) => asin(a).map(Some),
60 ("asinh", [a]) => asinh(a).map(Some),
61 ("atan", [a]) => atan(a).map(Some),
62 ("atanh", [a]) => atanh(a).map(Some),
63 ("atan2", [a1, a2]) => atan2(a1, a2).map(Some),
64 ("ceil", [a]) => ceil(a).map(Some),
65 ("clamp", [a1, a2, a3]) => clamp(a1, a2, a3).map(Some),
66 ("cos", [a]) => cos(a).map(Some),
67 ("cosh", [a]) => cosh(a).map(Some),
68 ("countLeadingZeros", [a]) => countLeadingZeros(a).map(Some),
69 ("countOneBits", [a]) => countOneBits(a).map(Some),
70 ("countTrailingZeros", [a]) => countTrailingZeros(a).map(Some),
71 ("cross", [a1, a2]) => cross(a1, a2).map(Some),
72 ("degrees", [a]) => degrees(a).map(Some),
73 ("determinant", [a]) => determinant(a).map(Some),
74 ("distance", [a1, a2]) => distance(a1, a2).map(Some),
75 ("dot", [a1, a2]) => dot(a1, a2).map(Some),
76 ("dot4U8Packed", [a1, a2]) => dot4U8Packed(a1, a2).map(Some),
77 ("dot4I8Packed", [a1, a2]) => dot4I8Packed(a1, a2).map(Some),
78 ("exp", [a]) => exp(a).map(Some),
79 ("exp2", [a]) => exp2(a).map(Some),
80 ("extractBits", [a1, a2, a3]) => extractBits(a1, a2, a3).map(Some),
81 ("faceForward", [a1, a2, a3]) => faceForward(a1, a2, a3).map(Some),
82 ("firstLeadingBit", [a]) => firstLeadingBit(a).map(Some),
83 ("firstTrailingBit", [a]) => firstTrailingBit(a).map(Some),
84 ("floor", [a]) => floor(a).map(Some),
85 ("fma", [a1, a2, a3]) => fma(a1, a2, a3).map(Some),
86 ("fract", [a]) => fract(a).map(Some),
87 ("frexp", [a]) => frexp(a).map(Some),
88 ("insertBits", [a1, a2, a3, a4]) => insertBits(a1, a2, a3, a4).map(Some),
89 ("inverseSqrt", [a]) => inverseSqrt(a).map(Some),
90 ("ldexp", [a1, a2]) => ldexp(a1, a2).map(Some),
91 ("length", [a]) => length(a).map(Some),
92 ("log", [a]) => log(a).map(Some),
93 ("log2", [a]) => log2(a).map(Some),
94 ("max", [a1, a2]) => max(a1, a2).map(Some),
95 ("min", [a1, a2]) => min(a1, a2).map(Some),
96 ("mix", [a1, a2, a3]) => mix(a1, a2, a3).map(Some),
97 ("modf", [a]) => modf(a).map(Some),
98 ("normalize", [a]) => normalize(a).map(Some),
99 ("pow", [a1, a2]) => pow(a1, a2).map(Some),
100 ("quantizeToF16", [a]) => quantizeToF16(a).map(Some),
101 ("radians", [a]) => radians(a).map(Some),
102 ("reflect", [a1, a2]) => reflect(a1, a2).map(Some),
103 ("refract", [a1, a2, a3]) => refract(a1, a2, a3).map(Some),
104 ("reverseBits", [a]) => reverseBits(a).map(Some),
105 ("round", [a]) => round(a).map(Some),
106 ("saturate", [a]) => saturate(a).map(Some),
107 ("sign", [a]) => sign(a).map(Some),
108 ("sin", [a]) => sin(a).map(Some),
109 ("sinh", [a]) => sinh(a).map(Some),
110 ("smoothstep", [a1, a2, a3]) => smoothstep(a1, a2, a3).map(Some),
111 ("sqrt", [a]) => sqrt(a).map(Some),
112 ("step", [a1, a2]) => step(a1, a2).map(Some),
113 ("tan", [a]) => tan(a).map(Some),
114 ("tanh", [a]) => tanh(a).map(Some),
115 ("transpose", [a]) => transpose(a).map(Some),
116 ("trunc", [a]) => trunc(a).map(Some),
117 ("dpdx", [a]) => dpdx(a).map(Some),
119 ("dpdxCoarse", [a]) => dpdxCoarse(a).map(Some),
120 ("dpdxFine", [a]) => dpdxFine(a).map(Some),
121 ("dpdy", [a]) => dpdy(a).map(Some),
122 ("dpdyCoarse", [a]) => dpdyCoarse(a).map(Some),
123 ("dpdyFine", [a]) => dpdyFine(a).map(Some),
124 ("fwidth", [a]) => fwidth(a).map(Some),
125 ("fwidthCoarse", [a]) => fwidthCoarse(a).map(Some),
126 ("fwidthFine", [a]) => fwidthFine(a).map(Some),
127 ("textureDimensions", [a1]) => textureDimensions(a1, None).map(Some),
129 ("textureDimensions", [a1, a2]) => textureDimensions(a1, Some(a2)).map(Some),
130 ("textureGather", [a1, a2, a3]) => textureGather(a1, a2, a3, None, None, None).map(Some),
131 ("textureGather", [a1, a2, a3, a4]) => {
132 textureGather(a1, a2, a3, Some(a4), None, None).map(Some)
133 }
134 ("textureGather", [a1, a2, a3, a4, a5]) => {
135 textureGather(a1, a2, a3, Some(a4), Some(a5), None).map(Some)
136 }
137 ("textureGather", [a1, a2, a3, a4, a5, a6]) => {
138 textureGather(a1, a2, a3, Some(a4), Some(a5), Some(a6)).map(Some)
139 }
140 ("textureGatherCompare", [a1, a2, a3, a4]) => {
141 textureGatherCompare(a1, a2, a3, a4, None, None).map(Some)
142 }
143 ("textureGatherCompare", [a1, a2, a3, a4, a5]) => {
144 textureGatherCompare(a1, a2, a3, a4, Some(a5), None).map(Some)
145 }
146 ("textureGatherCompare", [a1, a2, a3, a4, a5, a6]) => {
147 textureGatherCompare(a1, a2, a3, a4, Some(a5), Some(a6)).map(Some)
148 }
149 ("textureLoad", [a1, a2]) => textureLoad(a1, a2, None, None).map(Some),
150 ("textureLoad", [a1, a2, a3]) => textureLoad(a1, a2, Some(a3), None).map(Some),
151 ("textureLoad", [a1, a2, a3, a4]) => textureLoad(a1, a2, Some(a3), Some(a4)).map(Some),
152 ("textureNumLayers", [a]) => textureNumLayers(a).map(Some),
153 ("textureNumLevels", [a]) => textureNumLevels(a).map(Some),
154 ("textureNumSamples", [a]) => textureNumSamples(a).map(Some),
155 ("textureSample", [a1, a2, a3]) => textureSample(a1, a2, a3, None, None).map(Some),
156 ("textureSample", [a1, a2, a3, a4]) => textureSample(a1, a2, a3, Some(a4), None).map(Some),
157 ("textureSample", [a1, a2, a3, a4, a5]) => {
158 textureSample(a1, a2, a3, Some(a4), Some(a5)).map(Some)
159 }
160 ("textureSampleBias", [a1, a2, a3, a4]) => {
161 textureSampleBias(a1, a2, a3, a4, None, None).map(Some)
162 }
163 ("textureSampleBias", [a1, a2, a3, a4, a5]) => {
164 textureSampleBias(a1, a2, a3, a4, Some(a5), None).map(Some)
165 }
166 ("textureSampleBias", [a1, a2, a3, a4, a5, a6]) => {
167 textureSampleBias(a1, a2, a3, a4, Some(a5), Some(a6)).map(Some)
168 }
169 ("textureSampleCompare", [a1, a2, a3, a4]) => {
170 textureSampleCompare(a1, a2, a3, a4, None, None).map(Some)
171 }
172 ("textureSampleCompare", [a1, a2, a3, a4, a5]) => {
173 textureSampleCompare(a1, a2, a3, a4, Some(a5), None).map(Some)
174 }
175 ("textureSampleCompare", [a1, a2, a3, a4, a5, a6]) => {
176 textureSampleCompare(a1, a2, a3, a4, Some(a5), Some(a6)).map(Some)
177 }
178 ("textureSampleCompareLevel", [a1, a2, a3, a4]) => {
179 textureSampleCompareLevel(a1, a2, a3, a4, None, None).map(Some)
180 }
181 ("textureSampleCompareLevel", [a1, a2, a3, a4, a5]) => {
182 textureSampleCompareLevel(a1, a2, a3, a4, Some(a5), None).map(Some)
183 }
184 ("textureSampleCompareLevel", [a1, a2, a3, a4, a5, a6]) => {
185 textureSampleCompareLevel(a1, a2, a3, a4, Some(a5), Some(a6)).map(Some)
186 }
187 ("textureSampleGrad", [a1, a2, a3, a4, a5]) => {
188 textureSampleGrad(a1, a2, a3, a4, a5, None, None).map(Some)
189 }
190 ("textureSampleGrad", [a1, a2, a3, a4, a5, a6]) => {
191 textureSampleGrad(a1, a2, a3, a4, a5, Some(a6), None).map(Some)
192 }
193 ("textureSampleGrad", [a1, a2, a3, a4, a5, a6, a7]) => {
194 textureSampleGrad(a1, a2, a3, a4, a5, Some(a6), Some(a7)).map(Some)
195 }
196 ("textureSampleLevel", [a1, a2, a3, a4]) => {
197 textureSampleLevel(a1, a2, a3, a4, None, None).map(Some)
198 }
199 ("textureSampleLevel", [a1, a2, a3, a4, a5]) => {
200 textureSampleLevel(a1, a2, a3, a4, Some(a5), None).map(Some)
201 }
202 ("textureSampleLevel", [a1, a2, a3, a4, a5, a6]) => {
203 textureSampleLevel(a1, a2, a3, a4, Some(a5), Some(a6)).map(Some)
204 }
205 ("textureSampleBaseClampToEdge", [a1, a2, a3]) => {
206 textureSampleBaseClampToEdge(a1, a2, a3).map(Some)
207 }
208 ("textureStore", [a1, a2, a3]) => textureStore(a1, a2, a3, None).map(|()| None),
209 ("textureStore", [a1, a2, a3, a4]) => textureStore(a1, a2, a3, Some(a4)).map(|()| None),
210 ("atomicLoad", [a]) => atomicLoad(a).map(Some),
212 ("atomicStore", [a1, a2]) => atomicStore(a1, a2).map(|()| None),
213 ("atomicAdd", [a1, a2]) => atomicAdd(a1, a2).map(Some),
214 ("atomicSub", [a1, a2]) => atomicSub(a1, a2).map(Some),
215 ("atomicMax", [a1, a2]) => atomicMax(a1, a2).map(Some),
216 ("atomicMin", [a1, a2]) => atomicMin(a1, a2).map(Some),
217 ("atomicAnd", [a1, a2]) => atomicAnd(a1, a2).map(Some),
218 ("atomicOr", [a1, a2]) => atomicOr(a1, a2).map(Some),
219 ("atomicXor", [a1, a2]) => atomicXor(a1, a2).map(Some),
220 ("atomicExchange", [a1, a2]) => atomicExchange(a1, a2).map(Some),
221 ("atomicCompareExchangeWeak", [a1, a2, a3]) => {
222 atomicCompareExchangeWeak(a1, a2, a3).map(Some)
223 }
224 ("pack4x8snorm", [a]) => pack4x8snorm(a).map(Some),
226 ("pack4x8unorm", [a]) => pack4x8unorm(a).map(Some),
227 ("pack4xI8", [a]) => pack4xI8(a).map(Some),
228 ("pack4xU8", [a]) => pack4xU8(a).map(Some),
229 ("pack4xI8Clamp", [a]) => pack4xI8Clamp(a).map(Some),
230 ("pack4xU8Clamp", [a]) => pack4xU8Clamp(a).map(Some),
231 ("pack2x16snorm", [a]) => pack2x16snorm(a).map(Some),
232 ("pack2x16unorm", [a]) => pack2x16unorm(a).map(Some),
233 ("pack2x16float", [a]) => pack2x16float(a).map(Some),
234 ("unpack4x8snorm", [a]) => unpack4x8snorm(a).map(Some),
235 ("unpack4x8unorm", [a]) => unpack4x8unorm(a).map(Some),
236 ("unpack4xI8", [a]) => unpack4xI8(a).map(Some),
237 ("unpack4xU8", [a]) => unpack4xU8(a).map(Some),
238 ("unpack2x16snorm", [a]) => unpack2x16snorm(a).map(Some),
239 ("unpack2x16unorm", [a]) => unpack2x16unorm(a).map(Some),
240 ("unpack2x16float", [a]) => unpack2x16float(a).map(Some),
241 ("storageBarrier", []) => Ok(None),
243 ("textureBarrier", []) => Ok(None),
244 ("workgroupBarrier", []) => Ok(None),
245 ("workgroupUniformLoad", [Type::Ptr(AddressSpace::Workgroup, t, _)]) => {
246 Ok(Some(*t.clone()))
247 }
248 ("subgroupAdd", [a]) => subgroupAdd(a).map(Some),
250 ("subgroupExclusiveAdd", [a]) => subgroupExclusiveAdd(a).map(Some),
251 ("subgroupInclusiveAdd", [a]) => subgroupInclusiveAdd(a).map(Some),
252 ("subgroupAll", [a]) => subgroupAll(a).map(Some),
253 ("subgroupAnd", [a]) => subgroupAnd(a).map(Some),
254 ("subgroupAny", [a]) => subgroupAny(a).map(Some),
255 ("subgroupBallot", [a]) => subgroupBallot(Some(a)).map(Some),
256 #[cfg(feature = "naga-ext")]
257 ("subgroupBallot", []) => subgroupBallot(None).map(Some),
258 ("subgroupBroadcast", [a1, a2]) => subgroupBroadcast(a1, a2).map(Some),
259 ("subgroupBroadcastFirst", [a]) => subgroupBroadcastFirst(a).map(Some),
260 ("subgroupElect", []) => subgroupElect().map(Some),
261 ("subgroupMax", [a]) => subgroupMax(a).map(Some),
262 ("subgroupMin", [a]) => subgroupMin(a).map(Some),
263 ("subgroupMul", [a]) => subgroupMul(a).map(Some),
264 ("subgroupExclusiveMul", [a]) => subgroupExclusiveMul(a).map(Some),
265 ("subgroupInclusiveMul", [a]) => subgroupInclusiveMul(a).map(Some),
266 ("subgroupOr", [a]) => subgroupOr(a).map(Some),
267 ("subgroupShuffle", [a1, a2]) => subgroupShuffle(a1, a2).map(Some),
268 ("subgroupShuffleDown", [a1, a2]) => subgroupShuffleDown(a1, a2).map(Some),
269 ("subgroupShuffleUp", [a1, a2]) => subgroupShuffleUp(a1, a2).map(Some),
270 ("subgroupShuffleXor", [a1, a2]) => subgroupShuffleXor(a1, a2).map(Some),
271 ("subgroupXor", [a]) => subgroupXor(a).map(Some),
272 ("quadBroadcast", [a1, a2]) => quadBroadcast(a1, a2).map(Some),
274 ("quadSwapDiagonal", [a]) => quadSwapDiagonal(a).map(Some),
275 ("quadSwapX", [a]) => quadSwapX(a).map(Some),
276 ("quadSwapY", [a]) => quadSwapY(a).map(Some),
277 #[cfg(feature = "naga-ext")]
279 ("rayQueryInitialize", [a1, a2, a3]) => rayQueryInitialize(a1, a2, a3).map(|()| None),
280 #[cfg(feature = "naga-ext")]
281 ("rayQueryProceed", [a]) => rayQueryProceed(a).map(Some),
282 #[cfg(feature = "naga-ext")]
283 ("rayQueryGenerateIntersection", [a1, a2]) => {
284 rayQueryGenerateIntersection(a1, a2).map(|()| None)
285 }
286 #[cfg(feature = "naga-ext")]
287 ("rayQueryConfirmIntersection", [a]) => rayQueryConfirmIntersection(a).map(|()| None),
288 #[cfg(feature = "naga-ext")]
289 ("rayQueryTerminate", [a]) => rayQueryTerminate(a).map(|()| None),
290 #[cfg(feature = "naga-ext")]
291 ("rayQueryGetCommittedIntersection", [a]) => rayQueryGetCommittedIntersection(a).map(Some),
292 #[cfg(feature = "naga-ext")]
293 ("rayQueryGetCandidateIntersection", [a]) => rayQueryGetCandidateIntersection(a).map(Some),
294 #[cfg(feature = "naga-ext")]
295 ("getCommittedHitVertexPositions", [a]) => getCommittedHitVertexPositions(a).map(Some),
296 #[cfg(feature = "naga-ext")]
297 ("getCandidateHitVertexPositions", [a]) => getCandidateHitVertexPositions(a).map(Some),
298 #[cfg(feature = "naga-ext")]
300 ("traceRay", [a1, a2, a3]) => traceRay(a1, a2, a3).map(|()| None),
301 _ => Err(err()),
302 }
303}
304
305pub(crate) fn frexp_struct_name(ty: &Type) -> Option<&'static str> {
310 match ty {
311 Type::AbstractFloat => Some("__frexp_result_abstract"),
312 Type::F32 => Some("__frexp_result_f32"),
313 Type::F16 => Some("__frexp_result_f16"),
314 #[cfg(feature = "naga-ext")]
315 Type::F64 => Some("__frexp_result_f64"),
316 Type::Vec(n, ty) => match (n, &**ty) {
317 (2, Type::AbstractFloat) => Some("__frexp_result_vec2_abstract"),
318 (2, Type::F32) => Some("__frexp_result_vec2_f32"),
319 (2, Type::F16) => Some("__frexp_result_vec2_f16"),
320 (3, Type::AbstractFloat) => Some("__frexp_result_vec3_abstract"),
321 (3, Type::F32) => Some("__frexp_result_vec3_f32"),
322 (3, Type::F16) => Some("__frexp_result_vec3_f16"),
323 (4, Type::AbstractFloat) => Some("__frexp_result_vec4_abstract"),
324 (4, Type::F32) => Some("__frexp_result_vec4_f32"),
325 (4, Type::F16) => Some("__frexp_result_vec4_f16"),
326 #[cfg(feature = "naga-ext")]
327 (2, Type::F64) => Some("__frexp_result_vec2_f64"),
328 #[cfg(feature = "naga-ext")]
329 (3, Type::F64) => Some("__frexp_result_vec3_f64"),
330 #[cfg(feature = "naga-ext")]
331 (4, Type::F64) => Some("__frexp_result_vec4_f64"),
332 _ => None,
333 },
334 _ => None,
335 }
336}
337
338pub(crate) fn frexp_struct_type(ty: &Type) -> Option<StructType> {
339 frexp_struct_name(ty).map(|name| {
340 let exp_inner_ty = if ty.is_abstract() {
341 Type::AbstractInt
342 } else {
343 Type::I32
344 };
345 let exp_ty = match ty {
346 Type::Vec(n, _) => Type::Vec(*n, Box::new(exp_inner_ty)),
347 _ => exp_inner_ty,
348 };
349 StructType {
350 name: name.to_string(),
351 members: vec![
352 StructMemberType::new("fract".to_string(), ty.clone()),
353 StructMemberType::new("exp".to_string(), exp_ty),
354 ],
355 }
356 })
357}
358
359pub(crate) fn modf_struct_name(ty: &Type) -> Option<&'static str> {
360 match ty {
361 Type::AbstractFloat => Some("__modf_result_abstract"),
362 Type::F32 => Some("__modf_result_f32"),
363 Type::F16 => Some("__modf_result_f16"),
364 #[cfg(feature = "naga-ext")]
365 Type::F64 => Some("__modf_result_f64"),
366 Type::Vec(n, ty) => match (n, &**ty) {
367 (2, Type::AbstractFloat) => Some("__modf_result_vec2_abstract"),
368 (2, Type::F32) => Some("__modf_result_vec2_f32"),
369 (2, Type::F16) => Some("__modf_result_vec2_f16"),
370 (3, Type::AbstractFloat) => Some("__modf_result_vec3_abstract"),
371 (3, Type::F32) => Some("__modf_result_vec3_f32"),
372 (3, Type::F16) => Some("__modf_result_vec3_f16"),
373 (4, Type::AbstractFloat) => Some("__modf_result_vec4_abstract"),
374 (4, Type::F32) => Some("__modf_result_vec4_f32"),
375 (4, Type::F16) => Some("__modf_result_vec4_f16"),
376 #[cfg(feature = "naga-ext")]
377 (2, Type::F64) => Some("__modf_result_vec2_f64"),
378 #[cfg(feature = "naga-ext")]
379 (3, Type::F64) => Some("__modf_result_vec3_f64"),
380 #[cfg(feature = "naga-ext")]
381 (4, Type::F64) => Some("__modf_result_vec4_f64"),
382 _ => None,
383 },
384 _ => None,
385 }
386}
387
388pub(crate) fn atomic_compare_exchange_struct_type(ty: &Type) -> StructType {
389 StructType {
390 name: "__atomic_compare_exchange_result".to_string(),
391 members: vec![
392 StructMemberType::new("old_value".to_string(), ty.clone()),
393 StructMemberType::new("exchanged".to_string(), Type::Bool),
394 ],
395 }
396}
397
398pub(crate) fn modf_struct_type(ty: &Type) -> Option<StructType> {
399 modf_struct_name(ty).map(|name| StructType {
400 name: name.to_string(),
401 members: vec![
402 StructMemberType::new("fract".to_string(), ty.clone()),
403 StructMemberType::new("whole".to_string(), ty.clone()),
404 ],
405 })
406}
407
408#[cfg(feature = "naga-ext")]
409#[allow(unused)]
410pub(crate) fn ray_desc_struct_type() -> StructType {
411 StructType {
412 name: "RayDesc".to_string(),
413 members: vec![
414 StructMemberType::new("flags".to_string(), Type::U32),
415 StructMemberType::new("cull_mask".to_string(), Type::U32),
416 StructMemberType::new("t_min".to_string(), Type::F32),
417 StructMemberType::new("t_max".to_string(), Type::F32),
418 StructMemberType::new("origin".to_string(), Type::Vec(3, Box::new(Type::F32))),
419 StructMemberType::new("dir".to_string(), Type::Vec(3, Box::new(Type::F32))),
420 ],
421 }
422}
423
424#[cfg(feature = "naga-ext")]
425pub(crate) fn ray_intersection_struct_type() -> StructType {
426 StructType {
427 name: "RayIntersection".to_string(),
428 members: vec![
429 StructMemberType::new("kind".to_string(), Type::U32),
430 StructMemberType::new("t".to_string(), Type::F32),
431 StructMemberType::new("instance_custom_data".to_string(), Type::U32),
432 StructMemberType::new("instance_index".to_string(), Type::U32),
433 StructMemberType::new("sbt_record_offset".to_string(), Type::U32),
434 StructMemberType::new("geometry_index".to_string(), Type::U32),
435 StructMemberType::new("primitive_index".to_string(), Type::U32),
436 StructMemberType::new(
437 "barycentrics".to_string(),
438 Type::Vec(2, Box::new(Type::F32)),
439 ),
440 StructMemberType::new("front_face".to_string(), Type::Bool),
441 StructMemberType::new(
442 "object_to_world".to_string(),
443 Type::Mat(4, 3, Box::new(Type::F32)),
444 ),
445 StructMemberType::new(
446 "world_to_object".to_string(),
447 Type::Mat(4, 3, Box::new(Type::F32)),
448 ),
449 ],
450 }
451}
452
453fn inner_is_float(ty: &Type) -> bool {
455 ty.is_float() || matches!(ty, Type::Vec(_, t) if t.is_float())
456}
457fn inner_is_numeric(ty: &Type) -> bool {
458 ty.is_numeric() || matches!(ty, Type::Vec(_, t) if t.is_numeric())
459}
460fn inner_is_integer(ty: &Type) -> bool {
461 ty.is_integer() || matches!(ty, Type::Vec(_, t) if t.is_integer())
462}
463fn inner_is_bool(ty: &Type) -> bool {
464 ty.is_bool() || matches!(ty, Type::Vec(_, t) if t.is_bool())
465}
466
467pub fn bitcast_t(tplt_ty: &Type, e: &Type) -> Result<Type, E> {
478 if tplt_ty.size_of() != e.concretize().size_of() {
479 Err(E::Builtin(
480 "`bitcast` argument must have the same byte length as the template type",
481 ))
482 } else if inner_is_numeric(e) {
483 Ok(tplt_ty.clone())
484 } else {
485 Err(E::Builtin(
486 "`bitcast` expects a numeric scalar or numeric vector argument",
487 ))
488 }
489}
490
491pub fn all(e: &Type) -> Result<Type, E> {
500 if inner_is_bool(e) {
501 Ok(Type::Bool)
502 } else {
503 Err(E::Builtin(
504 "`all` expects a boolean or vector of boolean argument",
505 ))
506 }
507}
508
509pub fn any(e: &Type) -> Result<Type, E> {
513 if inner_is_bool(e) {
514 Ok(Type::Bool)
515 } else {
516 Err(E::Builtin(
517 "`any` expects a boolean or vector of boolean argument",
518 ))
519 }
520}
521
522pub fn select(f: &Type, t: &Type, cond: &Type) -> Result<Type, E> {
526 let ty = convert_ty(f, t).ok_or(E::Builtin(
527 "`select` 1st and 2nd arguments are incompatible",
528 ))?;
529
530 match (ty, cond) {
531 (Type::Vec(n_ty, _), Type::Vec(n_cond, t)) => {
532 if !t.is_bool() {
533 Err(E::Builtin(
534 "`select` 3rd argument must be a boolean or vector of boolean",
535 ))
536 } else if n_ty != n_cond {
537 Err(E::Builtin(
538 "`select` 3rd vector argument has incorrect dimensions",
539 ))
540 } else {
541 Ok(ty.clone())
542 }
543 }
544 (ty, Type::Bool) if ty.is_scalar() || ty.is_vec() => Ok(ty.clone()),
545 (_, Type::Bool) => Err(E::Builtin(
546 "`select` 1st and 2nd arguments must be a scalar or vector",
547 )),
548 (_, _) => Err(E::Builtin(
549 "`select` 3rd argument must be a boolean or vector of boolean",
550 )),
551 }
552}
553
554pub fn arrayLength(p: &Type) -> Result<Type, E> {
563 match p {
564 Type::Ptr(AddressSpace::Storage, t, a_m)
565 if a_m.is_read() && matches!(**t, Type::Array(_, None)) =>
566 {
567 Ok(Type::U32)
568 }
569 _ => Err(E::Builtin(
570 "`arrayLength` argument must be a pointer to runtime-sized array, with `storage` address space and `read` or `read_write` access mode",
571 )),
572 }
573}
574
575pub fn abs(e: &Type) -> Result<Type, E> {
584 inner_is_numeric(e).then_some(e.clone()).ok_or(E::Builtin(
585 "`abs` argument must be a numeric scalar or vector",
586 ))
587}
588
589pub fn acos(e: &Type) -> Result<Type, E> {
595 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
596 "`acos` argument must be a float scalar or vector",
597 ))
598}
599
600pub fn acosh(e: &Type) -> Result<Type, E> {
606 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
607 "`acosh` argument must be a float scalar or vector",
608 ))
609}
610
611pub fn asin(e: &Type) -> Result<Type, E> {
617 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
618 "`asin` argument must be a float scalar or vector",
619 ))
620}
621
622pub fn asinh(e: &Type) -> Result<Type, E> {
626 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
627 "`asinh` argument must be a float scalar or vector",
628 ))
629}
630
631pub fn atan(e: &Type) -> Result<Type, E> {
635 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
636 "`atan` argument must be a float scalar or vector",
637 ))
638}
639
640pub fn atanh(e: &Type) -> Result<Type, E> {
646 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
647 "`atanh` argument must be a float scalar or vector",
648 ))
649}
650
651pub fn atan2(y: &Type, x: &Type) -> Result<Type, E> {
655 let ty = convert_ty(y, x).ok_or(E::Builtin("`atan2 arguments are incompatible`"))?;
656 inner_is_float(ty).then_some(ty.clone()).ok_or(E::Builtin(
657 "`atan2` expects float scalar or vector arguments",
658 ))
659}
660
661pub fn ceil(e: &Type) -> Result<Type, E> {
665 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
666 "`ceil` argument must be a float scalar or vector",
667 ))
668}
669
670pub fn clamp(e: &Type, low: &Type, high: &Type) -> Result<Type, E> {
674 let ty =
675 convert_all_ty([e, low, high]).ok_or(E::Builtin("`clamp` arguments are incompatible"))?;
676 if inner_is_numeric(ty) {
677 Ok(ty.clone())
678 } else {
679 Err(E::Builtin(
680 "`clamp` expects three numeric scalar or vector arguments",
681 ))
682 }
683}
684
685pub fn cos(e: &Type) -> Result<Type, E> {
691 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
692 "`cos` argument must be a float scalar or vector",
693 ))
694}
695
696pub fn cosh(e: &Type) -> Result<Type, E> {
700 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
701 "`cosh` argument must be a float scalar or vector",
702 ))
703}
704
705pub fn countLeadingZeros(e: &Type) -> Result<Type, E> {
709 inner_is_integer(e)
710 .then_some(e.concretize())
711 .ok_or(E::Builtin(
712 "`countLeadingZeros` argument must be a integer scalar or vector",
713 ))
714}
715
716pub fn countOneBits(e: &Type) -> Result<Type, E> {
720 inner_is_integer(e)
721 .then_some(e.concretize())
722 .ok_or(E::Builtin(
723 "`countOneBits` argument must be a integer scalar or vector",
724 ))
725}
726
727pub fn countTrailingZeros(e: &Type) -> Result<Type, E> {
731 inner_is_integer(e)
732 .then_some(e.concretize())
733 .ok_or(E::Builtin(
734 "`countTrailingZeros` argument must be a integer scalar or vector",
735 ))
736}
737
738pub fn cross(a: &Type, b: &Type) -> Result<Type, E> {
742 let ty = convert_ty(a, b).ok_or(E::Builtin("`cross` arguments are incompatible"))?;
743 match ty {
744 Type::Vec(3, t) if t.is_float() => Ok(ty.clone()),
745 _ => Err(E::Builtin(
746 "`cross` expects two 3-component float vector arguments",
747 )),
748 }
749}
750
751pub fn degrees(e: &Type) -> Result<Type, E> {
755 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
756 "`degrees` expects a float scalar or vector argument",
757 ))
758}
759
760pub fn determinant(e: &Type) -> Result<Type, E> {
764 match e {
765 Type::Mat(c, r, t) if c == r => Ok(*t.clone()),
766 _ => Err(E::Builtin("`determinant` expects a square matrix argument")),
767 }
768}
769
770pub fn distance(e1: &Type, e2: &Type) -> Result<Type, E> {
774 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`distance` arguments are incompatible"))?;
775 inner_is_float(ty)
776 .then_some(ty.inner_ty())
777 .ok_or(E::Builtin(
778 "`distance` expects two float scalar or vector arguments",
779 ))
780}
781
782pub fn dot(e1: &Type, e2: &Type) -> Result<Type, E> {
786 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`dot` arguments are incompatible"))?;
787 match ty {
788 Type::Vec(_, t) if t.is_numeric() => Ok(*t.clone()),
789 _ => Err(E::Builtin(
790 "`dot` expects two numeric scalar or vector arguments",
791 )),
792 }
793}
794
795pub fn dot4U8Packed(e1: &Type, e2: &Type) -> Result<Type, E> {
799 if e1.is_convertible_to(&Type::U32) && e2.is_convertible_to(&Type::U32) {
800 Ok(Type::U32)
801 } else {
802 Err(E::Builtin("`dot4U8Packed` expects two u32 arguments"))
803 }
804}
805
806pub fn dot4I8Packed(e1: &Type, e2: &Type) -> Result<Type, E> {
810 if e1.is_convertible_to(&Type::U32) && e2.is_convertible_to(&Type::U32) {
811 Ok(Type::I32)
812 } else {
813 Err(E::Builtin("`dot4I8Packed` expects two u32 arguments"))
814 }
815}
816
817pub fn exp(e: &Type) -> Result<Type, E> {
821 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
822 "`exp` argument must be a float scalar or vector",
823 ))
824}
825
826pub fn exp2(e: &Type) -> Result<Type, E> {
830 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
831 "`exp2` argument must be a float scalar or vector",
832 ))
833}
834
835pub fn extractBits(e: &Type, offset: &Type, count: &Type) -> Result<Type, E> {
839 if !inner_is_integer(e) {
840 Err(E::Builtin(
841 "`extractBits` 1st argument must be an integer scalar or vector",
842 ))
843 } else if offset.is_convertible_to(&Type::U32) && count.is_convertible_to(&Type::U32) {
844 Ok(e.concretize())
845 } else {
846 Err(E::Builtin(
847 "`extractBits` 2nd and 3rd arguments must be u32",
848 ))
849 }
850}
851
852pub fn faceForward(e1: &Type, e2: &Type, e3: &Type) -> Result<Type, E> {
856 let ty = convert_all_ty([e1, e2, e3])
857 .ok_or(E::Builtin("`faceForward` arguments are incompatible"))?;
858 if matches!(ty, Type::Vec(_, t) if t.is_float()) {
859 Ok(ty.clone())
860 } else {
861 Err(E::Builtin(
862 "`faceForward` expects three float vector arguments",
863 ))
864 }
865}
866
867pub fn firstLeadingBit(e: &Type) -> Result<Type, E> {
871 if inner_is_integer(e) {
872 Ok(e.concretize())
873 } else {
874 Err(E::Builtin(
875 "`firstLeadingBit` expects an integer scalar or vector argument",
876 ))
877 }
878}
879
880pub fn firstTrailingBit(e: &Type) -> Result<Type, E> {
884 if inner_is_integer(e) {
885 Ok(e.concretize())
886 } else {
887 Err(E::Builtin(
888 "`firstTrailingBit` expects an integer scalar or vector argument",
889 ))
890 }
891}
892
893pub fn floor(e: &Type) -> Result<Type, E> {
897 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
898 "`floor` argument must be a float scalar or vector",
899 ))
900}
901
902pub fn fma(e1: &Type, e2: &Type, e3: &Type) -> Result<Type, E> {
906 let ty = convert_all_ty([e1, e2, e3]).ok_or(E::Builtin("`fma` arguments are incompatible"))?;
907 inner_is_float(ty).then_some(ty.clone()).ok_or(E::Builtin(
908 "`fma` expects three float scalar or vector arguments",
909 ))
910}
911
912pub fn fract(e: &Type) -> Result<Type, E> {
916 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
917 "`fract` argument must be a float scalar or vector",
918 ))
919}
920
921pub fn frexp(e: &Type) -> Result<Type, E> {
927 if inner_is_float(e) {
928 Ok(frexp_struct_type(e).unwrap().into())
929 } else {
930 Err(E::Builtin(
931 "`frexp` expects a float scalar or vector argument",
932 ))
933 }
934}
935
936pub fn insertBits(e: &Type, newbits: &Type, offset: &Type, count: &Type) -> Result<Type, E> {
940 let ty = convert_ty(e, newbits).ok_or(E::Builtin("`insertBits` arguments are incompatible"))?;
941
942 if !inner_is_integer(ty) {
943 Err(E::Builtin(
944 "`insertBits` 1st argument must be an integer scalar or vector",
945 ))
946 } else if !offset.is_convertible_to(&Type::U32) || !count.is_convertible_to(&Type::U32) {
947 Err(E::Builtin("`insertBits` 3rd and 4th arguments must be u32"))
948 } else {
949 Ok(ty.concretize())
950 }
951}
952
953pub fn inverseSqrt(e: &Type) -> Result<Type, E> {
957 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
958 "`inverseSqrt` argument must be a float scalar or vector",
959 ))
960}
961
962pub fn ldexp(e1: &Type, e2: &Type) -> Result<Type, E> {
966 if !inner_is_float(e1) {
967 Err(E::Builtin(
968 "`ldexp` 1st argument must be a float scalar or vector",
969 ))
970 } else if !e2.inner_ty().is_signed() || !e2.inner_ty().is_integer() {
971 Err(E::Builtin(
972 "`ldexp` 2nd argument must be a signed integer scalar or vector",
973 ))
974 } else if matches!((e1, e2), (Type::Vec(n1, _), Type::Vec(n2, _)) if n1 != n2) {
975 Err(E::Builtin(
976 "`ldexp` vector arguments must have the same number of components",
977 ))
978 } else if e1.is_vec() && !e2.is_vec() || !e1.is_vec() && e2.is_vec() {
979 Err(E::Builtin(
980 "`ldexp` arguments must be both scalar or both vectors",
981 ))
982 } else if e1.is_abstract() && e2.is_concrete() {
983 Ok(e1.concretize())
985 } else {
986 Ok(e1.clone())
987 }
988}
989
990pub fn length(e: &Type) -> Result<Type, E> {
994 inner_is_float(e).then_some(e.inner_ty()).ok_or(E::Builtin(
995 "`length` argument must be a float scalar or vector",
996 ))
997}
998
999pub fn log(e: &Type) -> Result<Type, E> {
1003 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1004 "`log` argument must be a float scalar or vector",
1005 ))
1006}
1007
1008pub fn log2(e: &Type) -> Result<Type, E> {
1012 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1013 "`log2` expects a float scalar or vector argument",
1014 ))
1015}
1016
1017pub fn max(e1: &Type, e2: &Type) -> Result<Type, E> {
1021 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`max` arguments are incompatible"))?;
1022 inner_is_numeric(ty).then_some(ty.clone()).ok_or(E::Builtin(
1023 "`max` expects two numeric scalar or vector arguments",
1024 ))
1025}
1026
1027pub fn min(e1: &Type, e2: &Type) -> Result<Type, E> {
1031 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`min` arguments are incompatible"))?;
1032 inner_is_numeric(ty).then_some(ty.clone()).ok_or(E::Builtin(
1033 "`min` expects two numeric scalar or vector arguments",
1034 ))
1035}
1036
1037pub fn mix(e1: &Type, e2: &Type, e3: &Type) -> Result<Type, E> {
1041 let ty =
1043 convert_ty(e1, e2).ok_or(E::Builtin("`mix` 1st and 2nd arguments are incompatible"))?;
1044
1045 if !inner_is_float(ty) {
1046 Err(E::Builtin(
1047 "`mix` expects three float scalar or vector arguments",
1048 ))
1049 }
1050 else if ty.is_vec() && e3.is_scalar() {
1052 let ty = convert_ty(&ty.inner_ty(), e3)
1053 .and_then(|inner_ty| ty.convert_inner_to(inner_ty))
1054 .ok_or(E::Builtin(
1055 "`mix` 3rd argument is incompatible with 1st and 2nd argument inner type",
1056 ))?;
1057 Ok(ty)
1058 }
1059 else {
1061 let ty = convert_ty(ty, e3).ok_or(E::Builtin(
1062 "`mix` 3rd argument is incompatible with 1st and 2nd arguments",
1063 ))?;
1064 Ok(ty.clone())
1065 }
1066}
1067
1068pub fn modf(e: &Type) -> Result<Type, E> {
1072 if inner_is_float(e) {
1073 Ok(modf_struct_type(e).unwrap().into())
1074 } else {
1075 Err(E::Builtin(
1076 "`modf` expects a float scalar or vector argument",
1077 ))
1078 }
1079}
1080
1081pub fn normalize(e: &Type) -> Result<Type, E> {
1085 match e {
1086 Type::Vec(n, t) if t.is_abstract_int() => Ok(Type::Vec(*n, Type::AbstractFloat.into())),
1088 Type::Vec(_, t) if t.is_float() => Ok(e.clone()),
1089 _ => Err(E::Builtin("`normalize` expects a float vector argument")),
1090 }
1091}
1092
1093pub fn pow(e1: &Type, e2: &Type) -> Result<Type, E> {
1097 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`pow` arguments are incompatible"))?;
1098 inner_is_float(ty).then_some(ty.clone()).ok_or(E::Builtin(
1099 "`pow` argument must be a float scalar or vector",
1100 ))
1101}
1102
1103pub fn quantizeToF16(e: &Type) -> Result<Type, E> {
1107 const ERR: E = E::Builtin("`quantizeToF16` expects a f32 scalar or vector argument");
1108 let ty = e.convert_inner_to(&Type::F32).ok_or(ERR)?;
1109 if ty.is_f32() || ty.is_vec() {
1110 Ok(ty)
1111 } else {
1112 Err(ERR)
1113 }
1114}
1115
1116pub fn radians(e: &Type) -> Result<Type, E> {
1120 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1121 "`radians` argument must be a float scalar or vector",
1122 ))
1123}
1124
1125pub fn reflect(e1: &Type, e2: &Type) -> Result<Type, E> {
1129 let ty = convert_ty(e1, e2).ok_or(E::Builtin("`reflect` arguments are incompatible"))?;
1130 if ty.is_vec() && ty.inner_ty().is_float() {
1131 Ok(ty.clone())
1132 } else {
1133 Err(E::Builtin("`reflect` expects two float vector arguments"))
1134 }
1135}
1136
1137pub fn refract(e1: &Type, e2: &Type, e3: &Type) -> Result<Type, E> {
1141 let ty = convert_ty(e1, e2).ok_or(E::Builtin(
1142 "`refract` 1st and 2nd arguments are incompatible",
1143 ))?;
1144
1145 let ty = convert_ty(&ty.inner_ty(), e3)
1146 .and_then(|inner_ty| ty.convert_inner_to(inner_ty))
1147 .ok_or(E::Builtin(
1148 "`refract` 3rd argument is incompatible with 1st and 2nd argument inner type",
1149 ))?;
1150
1151 if ty.is_vec() && ty.inner_ty().is_float() {
1152 Ok(ty)
1153 } else {
1154 Err(E::Builtin(
1155 "`refract` expects two scalar vector arguments and one scalar argument",
1156 ))
1157 }
1158}
1159
1160pub fn reverseBits(e: &Type) -> Result<Type, E> {
1164 if inner_is_integer(e) {
1165 Ok(e.concretize())
1166 } else {
1167 Err(E::Builtin(
1168 "`reverseBits` expects an integer scalar or vector argument",
1169 ))
1170 }
1171}
1172
1173pub fn round(e: &Type) -> Result<Type, E> {
1177 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1178 "`round` argument must be a float scalar or vector",
1179 ))
1180}
1181
1182pub fn saturate(e: &Type) -> Result<Type, E> {
1186 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1187 "`saturate` argument must be a float scalar or vector",
1188 ))
1189}
1190
1191pub fn sign(e: &Type) -> Result<Type, E> {
1195 if inner_is_numeric(e) && e.inner_ty().is_signed() {
1196 Ok(e.clone())
1197 } else {
1198 Err(E::Builtin(
1199 "`sign` argument must be a signed numeric scalar or vector",
1200 ))
1201 }
1202}
1203
1204pub fn sin(e: &Type) -> Result<Type, E> {
1208 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1209 "`sin` argument must be a float scalar or vector",
1210 ))
1211}
1212
1213pub fn sinh(e: &Type) -> Result<Type, E> {
1217 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1218 "`sinh` argument must be a float scalar or vector",
1219 ))
1220}
1221
1222pub fn smoothstep(edge0: &Type, edge1: &Type, x: &Type) -> Result<Type, E> {
1226 let ty = convert_all_ty([edge0, edge1, x])
1227 .ok_or(E::Builtin("`smoothstep` arguments are incompatible"))?;
1228 inner_is_float(ty).then_some(ty.clone()).ok_or(E::Builtin(
1229 "`smoothstep` expects three float scalar or vector arguments",
1230 ))
1231}
1232
1233pub fn sqrt(e: &Type) -> Result<Type, E> {
1237 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1238 "`sqrt` argument must be a float scalar or vector",
1239 ))
1240}
1241
1242pub fn step(edge: &Type, x: &Type) -> Result<Type, E> {
1246 let ty = convert_all_ty([edge, x]).ok_or(E::Builtin("`step` arguments are incompatible"))?;
1247 inner_is_float(ty).then_some(ty.clone()).ok_or(E::Builtin(
1248 "`step` expects two float scalar or vector arguments",
1249 ))
1250}
1251
1252pub fn tan(e: &Type) -> Result<Type, E> {
1256 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1257 "`tan` argument must be a float scalar or vector",
1258 ))
1259}
1260
1261pub fn tanh(e: &Type) -> Result<Type, E> {
1265 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1266 "`tanh` argument must be a float scalar or vector",
1267 ))
1268}
1269
1270pub fn transpose(e: &Type) -> Result<Type, E> {
1274 match e {
1275 Type::Mat(r, c, ty) => Ok(Type::Mat(*c, *r, ty.clone())),
1276 _ => Err(E::Builtin("`transpose` expects a matrix argument")),
1277 }
1278}
1279
1280pub fn trunc(e: &Type) -> Result<Type, E> {
1284 inner_is_float(e).then_some(e.clone()).ok_or(E::Builtin(
1285 "`trunc` argument must be a float scalar or vector",
1286 ))
1287}
1288
1289pub fn dpdx(e: &Type) -> Result<Type, E> {
1298 let ty = e.convert_inner_to(&Type::F32);
1299 if let Some(ty) = ty
1300 && (ty.is_scalar() || ty.is_vec())
1301 {
1302 Ok(ty)
1303 } else {
1304 Err(E::Builtin(
1305 "`dpdx` expects a `f32` scalar or vector argument",
1306 ))
1307 }
1308}
1309
1310pub fn dpdxCoarse(e: &Type) -> Result<Type, E> {
1314 let ty = e.convert_inner_to(&Type::F32);
1315 if let Some(ty) = ty
1316 && (ty.is_scalar() || ty.is_vec())
1317 {
1318 Ok(ty)
1319 } else {
1320 Err(E::Builtin(
1321 "`dpdxCoarse` expects a `f32` scalar or vector argument",
1322 ))
1323 }
1324}
1325
1326pub fn dpdxFine(e: &Type) -> Result<Type, E> {
1330 let ty = e.convert_inner_to(&Type::F32);
1331 if let Some(ty) = ty
1332 && (ty.is_scalar() || ty.is_vec())
1333 {
1334 Ok(ty)
1335 } else {
1336 Err(E::Builtin(
1337 "`dpdxFine` expects a `f32` scalar or vector argument",
1338 ))
1339 }
1340}
1341
1342pub fn dpdy(e: &Type) -> Result<Type, E> {
1346 let ty = e.convert_inner_to(&Type::F32);
1347 if let Some(ty) = ty
1348 && (ty.is_scalar() || ty.is_vec())
1349 {
1350 Ok(ty)
1351 } else {
1352 Err(E::Builtin(
1353 "`dpdy` expects a `f32` scalar or vector argument",
1354 ))
1355 }
1356}
1357
1358pub fn dpdyCoarse(e: &Type) -> Result<Type, E> {
1362 let ty = e.convert_inner_to(&Type::F32);
1363 if let Some(ty) = ty
1364 && (ty.is_scalar() || ty.is_vec())
1365 {
1366 Ok(ty)
1367 } else {
1368 Err(E::Builtin(
1369 "`dpdyCoarse` expects a `f32` scalar or vector argument",
1370 ))
1371 }
1372}
1373
1374pub fn dpdyFine(e: &Type) -> Result<Type, E> {
1378 let ty = e.convert_inner_to(&Type::F32);
1379 if let Some(ty) = ty
1380 && (ty.is_scalar() || ty.is_vec())
1381 {
1382 Ok(ty)
1383 } else {
1384 Err(E::Builtin(
1385 "`dpdyFine` expects a `f32` scalar or vector argument",
1386 ))
1387 }
1388}
1389
1390pub fn fwidth(e: &Type) -> Result<Type, E> {
1394 let ty = e.convert_inner_to(&Type::F32);
1395 if let Some(ty) = ty
1396 && (ty.is_scalar() || ty.is_vec())
1397 {
1398 Ok(ty)
1399 } else {
1400 Err(E::Builtin(
1401 "`fwidth` expects a `f32` scalar or vector argument",
1402 ))
1403 }
1404}
1405
1406pub fn fwidthCoarse(e: &Type) -> Result<Type, E> {
1410 let ty = e.convert_inner_to(&Type::F32);
1411 if let Some(ty) = ty
1412 && (ty.is_scalar() || ty.is_vec())
1413 {
1414 Ok(ty)
1415 } else {
1416 Err(E::Builtin(
1417 "`fwidthCoarse` expects a `f32` scalar or vector argument",
1418 ))
1419 }
1420}
1421
1422pub fn fwidthFine(e: &Type) -> Result<Type, E> {
1426 let ty = e.convert_inner_to(&Type::F32);
1427 if let Some(ty) = ty
1428 && (ty.is_scalar() || ty.is_vec())
1429 {
1430 Ok(ty)
1431 } else {
1432 Err(E::Builtin(
1433 "`fwidthFine` expects a `f32` scalar or vector argument",
1434 ))
1435 }
1436}
1437
1438pub fn textureDimensions(t: &Type, level: Option<&Type>) -> Result<Type, E> {
1447 match t {
1448 Type::Texture(t) => {
1449 let ret = match t.dimensions() {
1450 TextureDimensions::D1 => Type::U32,
1451 TextureDimensions::D2 => Type::Vec(2, Type::U32.into()),
1452 TextureDimensions::D3 => Type::Vec(3, Type::U32.into()),
1453 };
1454
1455 if let Some(l) = level
1456 && !l.is_integer()
1457 {
1458 Err(E::Builtin(
1459 "`textureDimensions` 2nd argument must be an integer",
1460 ))
1461 } else {
1462 Ok(ret)
1463 }
1464 }
1465 _ => Err(E::Builtin(
1466 "`textureDimensions` 1st argument must be a texture",
1467 )),
1468 }
1469}
1470
1471pub fn textureGather(
1476 e1: &Type,
1477 e2: &Type,
1478 _e3: &Type,
1479 _e4: Option<&Type>,
1480 _e5: Option<&Type>,
1481 _e6: Option<&Type>,
1482) -> Result<Type, E> {
1483 if let Type::Texture(t) = e1 {
1484 if t.is_depth() {
1485 Ok(Type::Vec(4, Type::F32.into()))
1486 } else {
1487 Err(E::Builtin(
1488 "the first argument to `textureGather` must be either a depth texture or an integer",
1489 ))
1490 }
1491 } else if let Type::Texture(t) = e2 {
1492 if let Some(sample_type) = t.sampled_type() {
1493 Ok(Type::Vec(4, Box::new(sample_type.into())))
1494 } else {
1495 Err(E::Builtin(
1496 "the 2nd argument to `textureGather` must be a sampled texture when the 1st one is an integer",
1497 ))
1498 }
1499 } else {
1500 Err(E::Builtin(
1501 "`textureGather` expects a texture in the 1st or 2nd argument",
1502 ))
1503 }
1504}
1505
1506pub fn textureGatherCompare(
1511 e1: &Type,
1512 _e2: &Type,
1513 _e3: &Type,
1514 _e4: &Type,
1515 _e5: Option<&Type>,
1516 _e6: Option<&Type>,
1517) -> Result<Type, E> {
1518 if let Type::Texture(t) = e1
1519 && t.is_depth()
1520 {
1521 Ok(Type::Vec(4, Type::F32.into()))
1522 } else {
1523 Err(E::Builtin(
1524 "`textureGatherCompare` 1st argument must be a depth texture",
1525 ))
1526 }
1527}
1528
1529pub fn textureLoad(
1534 e1: &Type,
1535 _e2: &Type,
1536 _e3: Option<&Type>,
1537 _e4: Option<&Type>,
1538) -> Result<Type, E> {
1539 if let Type::Texture(t) = e1 {
1540 if t.is_cube() {
1541 Err(E::Builtin("`textureLoad` does not support cube textures"))
1542 } else if t.is_depth() || *t == TextureType::DepthMultisampled2D {
1543 Ok(Type::F32)
1545 } else {
1546 Ok(Type::Vec(4, Box::new(t.channel_type().into())))
1547 }
1548 } else {
1549 Err(E::Builtin("`textureLoad` 1st argument must be a texture"))
1550 }
1551}
1552
1553pub fn textureNumLayers(t: &Type) -> Result<Type, E> {
1557 if let Type::Texture(t) = t
1558 && t.is_arrayed()
1559 {
1560 Ok(Type::U32)
1561 } else {
1562 Err(E::Builtin(
1563 "`textureNumLayers` expects an array texture argument",
1564 ))
1565 }
1566}
1567
1568pub fn textureNumLevels(t: &Type) -> Result<Type, E> {
1572 if let Type::Texture(t) = t
1573 && (t.is_sampled() || t.is_depth())
1574 {
1575 Ok(Type::U32)
1576 } else {
1577 Err(E::Builtin(
1578 "`textureNumLevels` expects an sampled or depth texture argument",
1579 ))
1580 }
1581}
1582
1583pub fn textureNumSamples(t: &Type) -> Result<Type, E> {
1587 if let Type::Texture(t) = t
1588 && t.is_multisampled()
1589 {
1590 Ok(Type::U32)
1591 } else {
1592 Err(E::Builtin(
1593 "`textureNumSamples` expects a multisampled texture argument",
1594 ))
1595 }
1596}
1597
1598pub fn textureSample(
1603 e1: &Type,
1604 _e2: &Type,
1605 _e3: &Type,
1606 _e4: Option<&Type>,
1607 _e5: Option<&Type>,
1608) -> Result<Type, E> {
1609 if let Type::Texture(t) = e1 {
1610 if t.is_sampled() {
1611 Ok(Type::Vec(4, Type::F32.into()))
1612 } else if t.is_depth() {
1613 Ok(Type::F32)
1614 } else {
1615 Err(E::Builtin(
1616 "`textureSample` first argument must be a sampled or depth texture",
1617 ))
1618 }
1619 } else {
1620 Err(E::Builtin(
1621 "`textureSample` first argument must be a sampled or depth texture",
1622 ))
1623 }
1624}
1625
1626pub fn textureSampleBias(
1631 e1: &Type,
1632 _e2: &Type,
1633 _e3: &Type,
1634 _e4: &Type,
1635 _e5: Option<&Type>,
1636 _e6: Option<&Type>,
1637) -> Result<Type, E> {
1638 if let Type::Texture(t) = e1 {
1639 if t.dimensions() == TextureDimensions::D1 {
1640 Err(E::Builtin(
1641 "`textureSampleBias` texture cannot be 1-dimensional",
1642 ))
1643 } else if t.is_sampled() {
1644 Ok(Type::Vec(4, Type::F32.into()))
1645 } else {
1646 Err(E::Builtin(
1647 "`textureSampleBias` first argument must be a sampled texture",
1648 ))
1649 }
1650 } else {
1651 Err(E::Builtin(
1652 "`textureSampleBias` first argument must be a sampled texture",
1653 ))
1654 }
1655}
1656
1657pub fn textureSampleCompare(
1662 e1: &Type,
1663 _e2: &Type,
1664 _e3: &Type,
1665 _e4: &Type,
1666 _e5: Option<&Type>,
1667 _e6: Option<&Type>,
1668) -> Result<Type, E> {
1669 if let Type::Texture(t) = e1
1670 && t.is_depth()
1671 {
1672 Ok(Type::F32)
1673 } else {
1674 Err(E::Builtin(
1675 "`textureSampleCompare` first argument must be a depth texture",
1676 ))
1677 }
1678}
1679
1680pub fn textureSampleCompareLevel(
1685 e1: &Type,
1686 _e2: &Type,
1687 _e3: &Type,
1688 _e4: &Type,
1689 _e5: Option<&Type>,
1690 _e6: Option<&Type>,
1691) -> Result<Type, E> {
1692 if let Type::Texture(t) = e1
1693 && t.is_depth()
1694 {
1695 Ok(Type::F32)
1696 } else {
1697 Err(E::Builtin(
1698 "`textureSampleCompareLevel` first argument must be a depth texture",
1699 ))
1700 }
1701}
1702
1703pub fn textureSampleGrad(
1708 e1: &Type,
1709 _e2: &Type,
1710 _e3: &Type,
1711 _e4: &Type,
1712 _e5: &Type,
1713 _e6: Option<&Type>,
1714 _e7: Option<&Type>,
1715) -> Result<Type, E> {
1716 if let Type::Texture(t) = e1 {
1717 if cfg!(feature = "naga-ext") && t.dimensions() == TextureDimensions::D1 {
1718 Ok(Type::Vec(4, Type::F32.into()))
1720 } else if t.dimensions() == TextureDimensions::D1 {
1721 Err(E::Builtin(
1722 "`textureSampleGrad` texture cannot be 1-dimensional",
1723 ))
1724 } else if t.is_sampled() {
1725 Ok(Type::Vec(4, Type::F32.into()))
1726 } else {
1727 Err(E::Builtin(
1728 "`textureSampleGrad` first argument must be a sampled texture",
1729 ))
1730 }
1731 } else {
1732 Err(E::Builtin(
1733 "`textureSampleGrad` first argument must be a sampled texture",
1734 ))
1735 }
1736}
1737
1738pub fn textureSampleLevel(
1743 e1: &Type,
1744 _e2: &Type,
1745 _e3: &Type,
1746 _e4: &Type,
1747 _e5: Option<&Type>,
1748 _e6: Option<&Type>,
1749) -> Result<Type, E> {
1750 if let Type::Texture(t) = e1 {
1751 if t.is_sampled() {
1752 Ok(Type::Vec(4, Type::F32.into()))
1753 } else if t.is_depth() {
1754 Ok(Type::F32)
1755 } else {
1756 Err(E::Builtin(
1757 "`textureSampleLevel` first argument must be a sampled or depth texture",
1758 ))
1759 }
1760 } else {
1761 Err(E::Builtin(
1762 "`textureSampleLevel` first argument must be a sampled or depth texture",
1763 ))
1764 }
1765}
1766
1767pub fn textureSampleBaseClampToEdge(e1: &Type, _e2: &Type, _e3: &Type) -> Result<Type, E> {
1771 if matches!(
1772 e1,
1773 Type::Texture(TextureType::Sampled2D(SampledType::F32) | TextureType::External)
1774 ) {
1775 Ok(Type::Vec(4, Type::F32.into()))
1776 } else {
1777 Err(E::Builtin(
1778 "`textureSampleBaseClampToEdge` first argument must be a `texture_2d<f32> ` or `texture_external`",
1779 ))
1780 }
1781}
1782
1783pub fn textureStore(e1: &Type, _e2: &Type, _e3: &Type, _e4: Option<&Type>) -> Result<(), E> {
1788 if let Type::Texture(t) = e1
1789 && t.is_storage()
1790 {
1791 Ok(())
1792 } else {
1793 Err(E::Builtin(
1794 "`textureStore` first argument must be a storage texture",
1795 ))
1796 }
1797}
1798
1799pub fn atomicLoad(e: &Type) -> Result<Type, E> {
1808 if let Type::Ptr(a_s, ptr_ty, a_m) = e
1809 && let Type::Atomic(ty) = &**ptr_ty
1810 {
1811 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1812 Err(E::Builtin(
1813 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1814 ))
1815 } else if *a_m != AccessMode::ReadWrite {
1816 Err(E::Builtin(
1817 "the access mode of the atomic pointer argument must be `read_write`",
1818 ))
1819 } else {
1820 Ok(*ty.clone())
1821 }
1822 } else {
1823 Err(E::Builtin(
1824 "`atomicLoad` expects a pointer to atomic argument",
1825 ))
1826 }
1827}
1828
1829pub fn atomicStore(e1: &Type, e2: &Type) -> Result<(), E> {
1833 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1834 && let Type::Atomic(ty) = &**ptr_ty
1835 {
1836 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1837 Err(E::Builtin(
1838 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1839 ))
1840 } else if *a_m != AccessMode::ReadWrite {
1841 Err(E::Builtin(
1842 "the access mode of the atomic pointer argument must be `read_write`",
1843 ))
1844 } else if e2.is_convertible_to(ty) {
1845 Ok(())
1846 } else {
1847 Err(E::Builtin(
1848 "`atomicStore` 2nd argument is incompatible with the atomic pointer type",
1849 ))
1850 }
1851 } else {
1852 Err(E::Builtin(
1853 "`atomicStore` expects a pointer to atomic argument",
1854 ))
1855 }
1856}
1857
1858pub fn atomicAdd(e1: &Type, e2: &Type) -> Result<Type, E> {
1862 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1863 && let Type::Atomic(ty) = &**ptr_ty
1864 {
1865 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1866 Err(E::Builtin(
1867 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1868 ))
1869 } else if *a_m != AccessMode::ReadWrite {
1870 Err(E::Builtin(
1871 "the access mode of the atomic pointer argument must be `read_write`",
1872 ))
1873 } else if e2.is_convertible_to(ty) {
1874 Ok(*ty.clone())
1875 } else {
1876 Err(E::Builtin(
1877 "`atomicAdd` 2nd argument is incompatible with the atomic pointer type",
1878 ))
1879 }
1880 } else {
1881 Err(E::Builtin(
1882 "`atomicAdd` expects a pointer to atomic argument",
1883 ))
1884 }
1885}
1886
1887pub fn atomicSub(e1: &Type, e2: &Type) -> Result<Type, E> {
1891 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1892 && let Type::Atomic(ty) = &**ptr_ty
1893 {
1894 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1895 Err(E::Builtin(
1896 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1897 ))
1898 } else if *a_m != AccessMode::ReadWrite {
1899 Err(E::Builtin(
1900 "the access mode of the atomic pointer argument must be `read_write`",
1901 ))
1902 } else if e2.is_convertible_to(ty) {
1903 Ok(*ty.clone())
1904 } else {
1905 Err(E::Builtin(
1906 "`atomicSub` 2nd argument is incompatible with the atomic pointer type",
1907 ))
1908 }
1909 } else {
1910 Err(E::Builtin(
1911 "`atomicSub` expects a pointer to atomic argument",
1912 ))
1913 }
1914}
1915
1916pub fn atomicMax(e1: &Type, e2: &Type) -> Result<Type, E> {
1920 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1921 && let Type::Atomic(ty) = &**ptr_ty
1922 {
1923 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1924 Err(E::Builtin(
1925 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1926 ))
1927 } else if *a_m != AccessMode::ReadWrite {
1928 Err(E::Builtin(
1929 "the access mode of the atomic pointer argument must be `read_write`",
1930 ))
1931 } else if e2.is_convertible_to(ty) {
1932 Ok(*ty.clone())
1933 } else {
1934 Err(E::Builtin(
1935 "`atomicMax` 2nd argument is incompatible with the atomic pointer type",
1936 ))
1937 }
1938 } else {
1939 Err(E::Builtin(
1940 "`atomicMax` expects a pointer to atomic argument",
1941 ))
1942 }
1943}
1944
1945pub fn atomicMin(e1: &Type, e2: &Type) -> Result<Type, E> {
1949 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1950 && let Type::Atomic(ty) = &**ptr_ty
1951 {
1952 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1953 Err(E::Builtin(
1954 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1955 ))
1956 } else if *a_m != AccessMode::ReadWrite {
1957 Err(E::Builtin(
1958 "the access mode of the atomic pointer argument must be `read_write`",
1959 ))
1960 } else if e2.is_convertible_to(ty) {
1961 Ok(*ty.clone())
1962 } else {
1963 Err(E::Builtin(
1964 "`atomicMin` 2nd argument is incompatible with the atomic pointer type",
1965 ))
1966 }
1967 } else {
1968 Err(E::Builtin(
1969 "`atomicMin` expects a pointer to atomic argument",
1970 ))
1971 }
1972}
1973
1974pub fn atomicAnd(e1: &Type, e2: &Type) -> Result<Type, E> {
1978 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
1979 && let Type::Atomic(ty) = &**ptr_ty
1980 {
1981 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
1982 Err(E::Builtin(
1983 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
1984 ))
1985 } else if *a_m != AccessMode::ReadWrite {
1986 Err(E::Builtin(
1987 "the access mode of the atomic pointer argument must be `read_write`",
1988 ))
1989 } else if e2.is_convertible_to(ty) {
1990 Ok(*ty.clone())
1991 } else {
1992 Err(E::Builtin(
1993 "`atomicAnd` 2nd argument is incompatible with the atomic pointer type",
1994 ))
1995 }
1996 } else {
1997 Err(E::Builtin(
1998 "`atomicAnd` expects a pointer to atomic argument",
1999 ))
2000 }
2001}
2002
2003pub fn atomicOr(e1: &Type, e2: &Type) -> Result<Type, E> {
2007 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
2008 && let Type::Atomic(ty) = &**ptr_ty
2009 {
2010 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
2011 Err(E::Builtin(
2012 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
2013 ))
2014 } else if *a_m != AccessMode::ReadWrite {
2015 Err(E::Builtin(
2016 "the access mode of the atomic pointer argument must be `read_write`",
2017 ))
2018 } else if e2.is_convertible_to(ty) {
2019 Ok(*ty.clone())
2020 } else {
2021 Err(E::Builtin(
2022 "`atomicOr` 2nd argument is incompatible with the atomic pointer type",
2023 ))
2024 }
2025 } else {
2026 Err(E::Builtin(
2027 "`atomicOr` expects a pointer to atomic argument",
2028 ))
2029 }
2030}
2031
2032pub fn atomicXor(e1: &Type, e2: &Type) -> Result<Type, E> {
2036 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
2037 && let Type::Atomic(ty) = &**ptr_ty
2038 {
2039 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
2040 Err(E::Builtin(
2041 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
2042 ))
2043 } else if *a_m != AccessMode::ReadWrite {
2044 Err(E::Builtin(
2045 "the access mode of the atomic pointer argument must be `read_write`",
2046 ))
2047 } else if e2.is_convertible_to(ty) {
2048 Ok(*ty.clone())
2049 } else {
2050 Err(E::Builtin(
2051 "`atomicXor` 2nd argument is incompatible with the atomic pointer type",
2052 ))
2053 }
2054 } else {
2055 Err(E::Builtin(
2056 "`atomicXor` expects a pointer to atomic argument",
2057 ))
2058 }
2059}
2060
2061pub fn atomicExchange(e1: &Type, e2: &Type) -> Result<Type, E> {
2065 if let Type::Ptr(a_s, ptr_ty, a_m) = e1
2066 && let Type::Atomic(ty) = &**ptr_ty
2067 {
2068 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
2069 Err(E::Builtin(
2070 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
2071 ))
2072 } else if *a_m != AccessMode::ReadWrite {
2073 Err(E::Builtin(
2074 "the access mode of the atomic pointer argument must be `read_write`",
2075 ))
2076 } else if e2.is_convertible_to(ty) {
2077 Ok(*ty.clone())
2078 } else {
2079 Err(E::Builtin(
2080 "`atomicExchange` 2nd argument is incompatible with the atomic pointer type",
2081 ))
2082 }
2083 } else {
2084 Err(E::Builtin(
2085 "`atomicExchange` expects a pointer to atomic argument",
2086 ))
2087 }
2088}
2089
2090pub fn atomicCompareExchangeWeak(e1: &Type, e2: &Type, e3: &Type) -> Result<Type, E> {
2094 let Type::Ptr(a_s, ptr_ty, a_m) = e1 else {
2095 return Err(E::Builtin(
2096 "`atomicCompareExchangeWeak` expects a pointer to atomic argument",
2097 ));
2098 };
2099 let Type::Atomic(ty) = &**ptr_ty else {
2100 return Err(E::Builtin(
2101 "`atomicCompareExchangeWeak` expects a pointer to atomic argument",
2102 ));
2103 };
2104 if *a_s != AddressSpace::Storage && *a_s != AddressSpace::Workgroup {
2105 Err(E::Builtin(
2106 "the address space of the atomic pointer argument must be `storage` or `workgroup`",
2107 ))
2108 } else if *a_m != AccessMode::ReadWrite {
2109 Err(E::Builtin(
2110 "the access mode of the atomic pointer argument must be `read_write`",
2111 ))
2112 } else if !e2.is_convertible_to(ty) && !e3.is_convertible_to(ty) {
2113 Err(E::Builtin(
2114 "`atomicCompareExchangeWeak` 2nd and 3rd arguments are incompatible with the atomic pointer type",
2115 ))
2116 } else if !e2.is_convertible_to(ty) {
2117 Err(E::Builtin(
2118 "`atomicCompareExchangeWeak` 2nd argument is incompatible with the atomic pointer type",
2119 ))
2120 } else if !e3.is_convertible_to(ty) {
2121 Err(E::Builtin(
2122 "`atomicCompareExchangeWeak` 3rd argument is incompatible with the atomic pointer type",
2123 ))
2124 } else {
2125 Ok(atomic_compare_exchange_struct_type(ty).into())
2126 }
2127}
2128
2129pub fn pack4x8snorm(e: &Type) -> Result<Type, E> {
2138 if e.is_convertible_to(&Type::Vec(4, Type::F32.into())) {
2139 Ok(Type::U32)
2140 } else {
2141 Err(E::Builtin("`pack4x8snorm` expects a `vec4<f32>` argument"))
2142 }
2143}
2144
2145pub fn pack4x8unorm(e: &Type) -> Result<Type, E> {
2149 if e.is_convertible_to(&Type::Vec(4, Type::F32.into())) {
2150 Ok(Type::U32)
2151 } else {
2152 Err(E::Builtin("`pack4x8unorm` expects a `vec4<f32>` argument"))
2153 }
2154}
2155
2156pub fn pack4xI8(e: &Type) -> Result<Type, E> {
2160 if e.is_convertible_to(&Type::Vec(4, Type::I32.into())) {
2161 Ok(Type::U32)
2162 } else {
2163 Err(E::Builtin("`pack4xI8` expects a `vec4<i32>` argument"))
2164 }
2165}
2166
2167pub fn pack4xU8(e: &Type) -> Result<Type, E> {
2171 if e.is_convertible_to(&Type::Vec(4, Type::U32.into())) {
2172 Ok(Type::U32)
2173 } else {
2174 Err(E::Builtin("`pack4xU8` expects a `vec4<u32>` argument"))
2175 }
2176}
2177
2178pub fn pack4xI8Clamp(e: &Type) -> Result<Type, E> {
2182 if e.is_convertible_to(&Type::Vec(4, Type::I32.into())) {
2183 Ok(Type::U32)
2184 } else {
2185 Err(E::Builtin("`pack4xI8Clamp` expects a `vec4<i32>` argument"))
2186 }
2187}
2188
2189pub fn pack4xU8Clamp(e: &Type) -> Result<Type, E> {
2193 if e.is_convertible_to(&Type::Vec(4, Type::U32.into())) {
2194 Ok(Type::U32)
2195 } else {
2196 Err(E::Builtin("`pack4xU8Clamp` expects a `vec4<u32>` argument"))
2197 }
2198}
2199
2200pub fn pack2x16snorm(e: &Type) -> Result<Type, E> {
2204 if e.is_convertible_to(&Type::Vec(2, Type::F32.into())) {
2205 Ok(Type::U32)
2206 } else {
2207 Err(E::Builtin("`pack2x16snorm` expects a `vec2<f32>` argument"))
2208 }
2209}
2210
2211pub fn pack2x16unorm(e: &Type) -> Result<Type, E> {
2215 if e.is_convertible_to(&Type::Vec(2, Type::F32.into())) {
2216 Ok(Type::U32)
2217 } else {
2218 Err(E::Builtin("`pack2x16unorm` expects a `vec2<f32>` argument"))
2219 }
2220}
2221
2222pub fn pack2x16float(e: &Type) -> Result<Type, E> {
2226 if e.is_convertible_to(&Type::Vec(2, Type::F32.into())) {
2227 Ok(Type::U32)
2228 } else {
2229 Err(E::Builtin("`pack2x16float` expects a `vec2<f32>` argument"))
2230 }
2231}
2232
2233pub fn unpack4x8snorm(e: &Type) -> Result<Type, E> {
2237 if e.is_convertible_to(&Type::U32) {
2238 Ok(Type::Vec(4, Type::F32.into()))
2239 } else {
2240 Err(E::Builtin("`unpack4x8snorm` expects a `u32` argument"))
2241 }
2242}
2243
2244pub fn unpack4x8unorm(e: &Type) -> Result<Type, E> {
2248 if e.is_convertible_to(&Type::U32) {
2249 Ok(Type::Vec(4, Type::F32.into()))
2250 } else {
2251 Err(E::Builtin("`unpack4x8unorm` expects a `u32` argument"))
2252 }
2253}
2254
2255pub fn unpack4xI8(e: &Type) -> Result<Type, E> {
2259 if e.is_convertible_to(&Type::U32) {
2260 Ok(Type::Vec(4, Type::I32.into()))
2261 } else {
2262 Err(E::Builtin("`unpack4xI8` expects a `u32` argument"))
2263 }
2264}
2265
2266pub fn unpack4xU8(e: &Type) -> Result<Type, E> {
2270 if e.is_convertible_to(&Type::U32) {
2271 Ok(Type::Vec(4, Type::U32.into()))
2272 } else {
2273 Err(E::Builtin("`unpack4xU8` expects a `u32` argument"))
2274 }
2275}
2276
2277pub fn unpack2x16snorm(e: &Type) -> Result<Type, E> {
2281 if e.is_convertible_to(&Type::U32) {
2282 Ok(Type::Vec(2, Type::F32.into()))
2283 } else {
2284 Err(E::Builtin("`unpack2x16snorm` expects a `u32` argument"))
2285 }
2286}
2287
2288pub fn unpack2x16unorm(e: &Type) -> Result<Type, E> {
2292 if e.is_convertible_to(&Type::U32) {
2293 Ok(Type::Vec(2, Type::F32.into()))
2294 } else {
2295 Err(E::Builtin("`unpack2x16unorm` expects a `u32` argument"))
2296 }
2297}
2298
2299pub fn unpack2x16float(e: &Type) -> Result<Type, E> {
2303 if e.is_convertible_to(&Type::U32) {
2304 Ok(Type::Vec(2, Type::F32.into()))
2305 } else {
2306 Err(E::Builtin("`unpack2x16float` expects a `u32` argument"))
2307 }
2308}
2309
2310pub fn subgroupAdd(e: &Type) -> Result<Type, E> {
2319 if inner_is_numeric(e) {
2320 Ok(e.concretize())
2321 } else {
2322 Err(E::Builtin(
2323 "`subgroupAdd` expects a numeric scalar or vector argument",
2324 ))
2325 }
2326}
2327
2328pub fn subgroupExclusiveAdd(e: &Type) -> Result<Type, E> {
2332 if inner_is_numeric(e) {
2333 Ok(e.concretize())
2334 } else {
2335 Err(E::Builtin(
2336 "`subgroupExclusiveAdd` expects a numeric scalar or vector argument",
2337 ))
2338 }
2339}
2340
2341pub fn subgroupInclusiveAdd(e: &Type) -> Result<Type, E> {
2345 if inner_is_numeric(e) {
2346 Ok(e.concretize())
2347 } else {
2348 Err(E::Builtin(
2349 "`subgroupInclusiveAdd` expects a numeric scalar or vector argument",
2350 ))
2351 }
2352}
2353
2354pub fn subgroupAll(e: &Type) -> Result<Type, E> {
2358 if e.is_bool() {
2359 Ok(Type::Bool)
2360 } else {
2361 Err(E::Builtin("`subgroupAll` expects a boolean argument"))
2362 }
2363}
2364
2365pub fn subgroupAnd(e: &Type) -> Result<Type, E> {
2369 if inner_is_integer(e) {
2370 Ok(e.concretize())
2371 } else {
2372 Err(E::Builtin(
2373 "`subgroupAnd` expects an integer scalar or vector argument",
2374 ))
2375 }
2376}
2377
2378pub fn subgroupAny(e: &Type) -> Result<Type, E> {
2382 if e.is_bool() {
2383 Ok(Type::Bool)
2384 } else {
2385 Err(E::Builtin("`subgroupAny` expects a boolean argument"))
2386 }
2387}
2388
2389pub fn subgroupBallot(pred: Option<&Type>) -> Result<Type, E> {
2395 if let Some(pred) = pred
2396 && pred.is_bool()
2397 {
2398 Ok(Type::Vec(4, Type::U32.into()))
2399 } else if pred.is_none() && cfg!(feature = "naga-ext") {
2400 Ok(Type::Vec(4, Type::U32.into()))
2401 } else {
2402 Err(E::Builtin("`subgroupBallot` expects a boolean argument"))
2403 }
2404}
2405
2406pub fn subgroupBroadcast(e: &Type, id: &Type) -> Result<Type, E> {
2410 if inner_is_numeric(e) && id.is_integer() {
2411 Ok(e.concretize())
2412 } else {
2413 Err(E::Builtin(
2414 "`subgroupBroadcast` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2415 ))
2416 }
2417}
2418
2419pub fn subgroupBroadcastFirst(e: &Type) -> Result<Type, E> {
2423 if inner_is_numeric(e) {
2424 Ok(e.concretize())
2425 } else {
2426 Err(E::Builtin(
2427 "`subgroupBroadcastFirst` expects a numeric scalar or vector argument",
2428 ))
2429 }
2430}
2431
2432pub fn subgroupElect() -> Result<Type, E> {
2436 Ok(Type::Bool)
2437}
2438
2439pub fn subgroupMax(e: &Type) -> Result<Type, E> {
2443 if inner_is_numeric(e) {
2444 Ok(e.concretize())
2445 } else {
2446 Err(E::Builtin(
2447 "`subgroupMax` expects a numeric scalar or vector argument",
2448 ))
2449 }
2450}
2451
2452pub fn subgroupMin(e: &Type) -> Result<Type, E> {
2456 if inner_is_numeric(e) {
2457 Ok(e.concretize())
2458 } else {
2459 Err(E::Builtin(
2460 "`subgroupMin` expects a numeric scalar or vector argument",
2461 ))
2462 }
2463}
2464
2465pub fn subgroupMul(e: &Type) -> Result<Type, E> {
2469 if inner_is_numeric(e) {
2470 Ok(e.concretize())
2471 } else {
2472 Err(E::Builtin(
2473 "`subgroupMul` expects a numeric scalar or vector argument",
2474 ))
2475 }
2476}
2477
2478pub fn subgroupExclusiveMul(e: &Type) -> Result<Type, E> {
2482 if inner_is_numeric(e) {
2483 Ok(e.concretize())
2484 } else {
2485 Err(E::Builtin(
2486 "`subgroupExclusiveMul` expects a numeric scalar or vector argument",
2487 ))
2488 }
2489}
2490
2491pub fn subgroupInclusiveMul(e: &Type) -> Result<Type, E> {
2495 if inner_is_numeric(e) {
2496 Ok(e.concretize())
2497 } else {
2498 Err(E::Builtin(
2499 "`subgroupInclusiveMul` expects a numeric scalar or vector argument",
2500 ))
2501 }
2502}
2503
2504pub fn subgroupOr(e: &Type) -> Result<Type, E> {
2508 if inner_is_integer(e) {
2509 Ok(e.concretize())
2510 } else {
2511 Err(E::Builtin(
2512 "`subgroupOr` expects an integer scalar or vector argument",
2513 ))
2514 }
2515}
2516
2517pub fn subgroupShuffle(e: &Type, id: &Type) -> Result<Type, E> {
2521 if inner_is_numeric(e) && id.is_integer() {
2522 Ok(e.concretize())
2523 } else {
2524 Err(E::Builtin(
2525 "`subgroupShuffle` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2526 ))
2527 }
2528}
2529
2530pub fn subgroupShuffleDown(e: &Type, delta: &Type) -> Result<Type, E> {
2534 if inner_is_numeric(e) && delta.is_convertible_to(&Type::U32) {
2535 Ok(e.concretize())
2536 } else {
2537 Err(E::Builtin(
2538 "`subgroupShuffleDown` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2539 ))
2540 }
2541}
2542
2543pub fn subgroupShuffleUp(e: &Type, delta: &Type) -> Result<Type, E> {
2547 if inner_is_numeric(e) && delta.is_convertible_to(&Type::U32) {
2548 Ok(e.concretize())
2549 } else {
2550 Err(E::Builtin(
2551 "`subgroupShuffleUp` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2552 ))
2553 }
2554}
2555
2556pub fn subgroupShuffleXor(e: &Type, mask: &Type) -> Result<Type, E> {
2560 if inner_is_numeric(e) && mask.is_convertible_to(&Type::U32) {
2561 Ok(e.concretize())
2562 } else {
2563 Err(E::Builtin(
2564 "`subgroupShuffleXor` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2565 ))
2566 }
2567}
2568
2569pub fn subgroupXor(e: &Type) -> Result<Type, E> {
2573 if inner_is_integer(e) {
2574 Ok(e.concretize())
2575 } else {
2576 Err(E::Builtin(
2577 "`subgroupXor` expects an integer scalar or vector argument",
2578 ))
2579 }
2580}
2581
2582pub fn quadBroadcast(e: &Type, id: &Type) -> Result<Type, E> {
2591 if inner_is_numeric(e) && id.is_integer() {
2592 Ok(e.concretize())
2593 } else {
2594 Err(E::Builtin(
2595 "`quadBroadcast` expects a numeric scalar or vector 1st argument and an integer 2nd argument",
2596 ))
2597 }
2598}
2599
2600pub fn quadSwapDiagonal(e: &Type) -> Result<Type, E> {
2604 if inner_is_numeric(e) {
2605 Ok(e.concretize())
2606 } else {
2607 Err(E::Builtin(
2608 "`quadSwapDiagonal` expects a numeric scalar or vector argument",
2609 ))
2610 }
2611}
2612
2613pub fn quadSwapX(e: &Type) -> Result<Type, E> {
2617 if inner_is_numeric(e) {
2618 Ok(e.concretize())
2619 } else {
2620 Err(E::Builtin(
2621 "`quadSwapX` expects a numeric scalar or vector argument",
2622 ))
2623 }
2624}
2625
2626pub fn quadSwapY(e: &Type) -> Result<Type, E> {
2630 if inner_is_numeric(e) {
2631 Ok(e.concretize())
2632 } else {
2633 Err(E::Builtin(
2634 "`quadSwapY` expects a numeric scalar or vector argument",
2635 ))
2636 }
2637}
2638
2639#[cfg(feature = "naga-ext")]
2648pub fn rayQueryInitialize(rq: &Type, accel_struct: &Type, ray_desc: &Type) -> Result<(), E> {
2649 if matches!(
2650 rq,
2651 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2652 ) && matches!(accel_struct, Type::AccelerationStructure(_))
2653 && matches!(ray_desc, Type::Struct(s) if s.name == "RayDesc")
2654 {
2655 Ok(())
2656 } else {
2657 Err(E::Builtin(
2658 "`rayQueryInitialize` expects a pointer to `ray_query`, an acceleration structure and a `RayDesc` argument",
2659 ))
2660 }
2661}
2662
2663#[cfg(feature = "naga-ext")]
2665pub fn rayQueryProceed(rq: &Type) -> Result<Type, E> {
2666 if matches!(
2667 rq,
2668 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2669 ) {
2670 Ok(Type::Bool)
2671 } else {
2672 Err(E::Builtin(
2673 "`rayQueryProceed` expects a pointer to `ray_query` argument",
2674 ))
2675 }
2676}
2677
2678#[cfg(feature = "naga-ext")]
2680pub fn rayQueryGenerateIntersection(rq: &Type, hit_t: &Type) -> Result<(), E> {
2681 if !matches!(
2682 rq,
2683 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2684 ) {
2685 Err(E::Builtin(
2686 "`rayQueryGenerateIntersection` 1st argument must be a pointer to `ray_query`",
2687 ))
2688 } else if hit_t.is_convertible_to(&Type::F32) {
2689 Ok(())
2690 } else {
2691 Err(E::Builtin(
2692 "`rayQueryGenerateIntersection` 2nd argument must be a `f32`",
2693 ))
2694 }
2695}
2696
2697#[cfg(feature = "naga-ext")]
2699pub fn rayQueryConfirmIntersection(rq: &Type) -> Result<(), E> {
2700 if !matches!(
2701 rq,
2702 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2703 ) {
2704 Err(E::Builtin(
2705 "`rayQueryConfirmIntersection` expects a pointer to `ray_query` argument",
2706 ))
2707 } else {
2708 Ok(())
2709 }
2710}
2711
2712#[cfg(feature = "naga-ext")]
2714pub fn rayQueryTerminate(rq: &Type) -> Result<(), E> {
2715 if !matches!(
2716 rq,
2717 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2718 ) {
2719 Err(E::Builtin(
2720 "`rayQueryTerminate` expects a pointer to `ray_query` argument",
2721 ))
2722 } else {
2723 Ok(())
2724 }
2725}
2726
2727#[cfg(feature = "naga-ext")]
2729pub fn rayQueryGetCommittedIntersection(e: &Type) -> Result<Type, E> {
2730 if matches!(
2731 e,
2732 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2733 ) {
2734 Ok(ray_intersection_struct_type().into())
2735 } else {
2736 Err(E::Builtin(
2737 "`rayQueryGetCommittedIntersection` expects a pointer to `ray_query` argument",
2738 ))
2739 }
2740}
2741
2742#[cfg(feature = "naga-ext")]
2744pub fn rayQueryGetCandidateIntersection(e: &Type) -> Result<Type, E> {
2745 if matches!(
2746 e,
2747 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2748 ) {
2749 Ok(ray_intersection_struct_type().into())
2750 } else {
2751 Err(E::Builtin(
2752 "`rayQueryGetCandidateIntersection` expects a pointer to `ray_query` argument",
2753 ))
2754 }
2755}
2756
2757#[cfg(feature = "naga-ext")]
2759pub fn getCommittedHitVertexPositions(e: &Type) -> Result<Type, E> {
2760 if matches!(
2761 e,
2762 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2763 ) {
2764 Ok(Type::Array(
2765 Box::new(Type::Vec(3, Box::new(Type::F32))),
2766 Some(3),
2767 ))
2768 } else {
2769 Err(E::Builtin(
2770 "`getCommittedHitVertexPositions` expects a pointer to `ray_query` argument",
2771 ))
2772 }
2773}
2774
2775#[cfg(feature = "naga-ext")]
2777pub fn getCandidateHitVertexPositions(e: &Type) -> Result<Type, E> {
2778 if matches!(
2779 e,
2780 Type::Ptr(AddressSpace::Function, t, AccessMode::ReadWrite) if matches!(**t, Type::RayQuery(_))
2781 ) {
2782 Ok(Type::Array(
2783 Box::new(Type::Vec(3, Box::new(Type::F32))),
2784 Some(3),
2785 ))
2786 } else {
2787 Err(E::Builtin(
2788 "`getCandidateHitVertexPositions` expects a pointer to `ray_query` argument",
2789 ))
2790 }
2791}
2792
2793#[cfg(feature = "naga-ext")]
2800pub fn traceRay(accel_struct: &Type, ray_desc: &Type, payload: &Type) -> Result<(), E> {
2801 if matches!(accel_struct, Type::AccelerationStructure(_))
2802 && matches!(ray_desc, Type::Struct(s) if s.name == "RayDesc")
2803 && matches!(
2804 payload,
2805 Type::Ptr(
2806 AddressSpace::RayPayload | AddressSpace::IncomingRayPayload,
2807 _,
2808 _
2809 )
2810 )
2811 {
2812 Ok(())
2813 } else {
2814 Err(E::Builtin(
2815 "`traceRay` expects an acceleration structure, a `RayDesc` and a pointer to a `ray_payload` or `incoming_ray_payload` variable",
2816 ))
2817 }
2818}