Skip to content

Commit 89a0ebf

Browse files
jimblandyteoxoy
authored andcommitted
[naga] Test CallResult and AtomicResult population.
Add tests to ensure that validation checks that `CallResult` and `AtomicResult` expressions actually have their values provided by `Call` and `Atomic` statements, and not `Emit` statements.
1 parent 59cd0e9 commit 89a0ebf

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed

naga/tests/root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod example_wgsl;
22
mod snapshots;
33
mod spirv_capabilities;
4+
mod validation;
45
mod wgsl_errors;

naga/tests/validation.rs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
use naga::{valid, Expression, Function, Scalar};
2+
3+
#[test]
4+
fn emit_atomic_result() {
5+
use naga::{Module, Type, TypeInner};
6+
7+
// We want to ensure that the *only* problem with the code is the
8+
// use of an `Emit` statement instead of an `Atomic` statement. So
9+
// validate two versions of the module varying only in that
10+
// aspect.
11+
//
12+
// Looking at uses of the `atomic` makes it easy to identify the
13+
// differences between the two variants.
14+
fn variant(
15+
atomic: bool,
16+
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> {
17+
let span = naga::Span::default();
18+
let mut module = Module::default();
19+
let ty_u32 = module.types.insert(
20+
Type {
21+
name: Some("u32".into()),
22+
inner: TypeInner::Scalar(Scalar::U32),
23+
},
24+
span,
25+
);
26+
let ty_atomic_u32 = module.types.insert(
27+
Type {
28+
name: Some("atomic<u32>".into()),
29+
inner: TypeInner::Atomic(Scalar::U32),
30+
},
31+
span,
32+
);
33+
let var_atomic = module.global_variables.append(
34+
naga::GlobalVariable {
35+
name: Some("atomic_global".into()),
36+
space: naga::AddressSpace::WorkGroup,
37+
binding: None,
38+
ty: ty_atomic_u32,
39+
init: None,
40+
},
41+
span,
42+
);
43+
44+
let mut fun = Function::default();
45+
let ex_global = fun
46+
.expressions
47+
.append(Expression::GlobalVariable(var_atomic), span);
48+
let ex_42 = fun
49+
.expressions
50+
.append(Expression::Literal(naga::Literal::U32(42)), span);
51+
let ex_result = fun.expressions.append(
52+
Expression::AtomicResult {
53+
ty: ty_u32,
54+
comparison: false,
55+
},
56+
span,
57+
);
58+
59+
if atomic {
60+
fun.body.push(
61+
naga::Statement::Atomic {
62+
pointer: ex_global,
63+
fun: naga::AtomicFunction::Add,
64+
value: ex_42,
65+
result: ex_result,
66+
},
67+
span,
68+
);
69+
} else {
70+
fun.body.push(
71+
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)),
72+
span,
73+
);
74+
}
75+
76+
module.functions.append(fun, span);
77+
78+
valid::Validator::new(
79+
valid::ValidationFlags::default(),
80+
valid::Capabilities::all(),
81+
)
82+
.validate(&module)
83+
}
84+
85+
variant(true).expect("module should validate");
86+
assert!(variant(false).is_err());
87+
}
88+
89+
#[test]
90+
fn emit_call_result() {
91+
use naga::{Module, Type, TypeInner};
92+
93+
// We want to ensure that the *only* problem with the code is the
94+
// use of an `Emit` statement instead of a `Call` statement. So
95+
// validate two versions of the module varying only in that
96+
// aspect.
97+
//
98+
// Looking at uses of the `call` makes it easy to identify the
99+
// differences between the two variants.
100+
fn variant(
101+
call: bool,
102+
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> {
103+
let span = naga::Span::default();
104+
let mut module = Module::default();
105+
let ty_u32 = module.types.insert(
106+
Type {
107+
name: Some("u32".into()),
108+
inner: TypeInner::Scalar(Scalar::U32),
109+
},
110+
span,
111+
);
112+
113+
let mut fun_callee = Function {
114+
result: Some(naga::FunctionResult {
115+
ty: ty_u32,
116+
binding: None,
117+
}),
118+
..Function::default()
119+
};
120+
let ex_42 = fun_callee
121+
.expressions
122+
.append(Expression::Literal(naga::Literal::U32(42)), span);
123+
fun_callee
124+
.body
125+
.push(naga::Statement::Return { value: Some(ex_42) }, span);
126+
let fun_callee = module.functions.append(fun_callee, span);
127+
128+
let mut fun_caller = Function::default();
129+
let ex_result = fun_caller
130+
.expressions
131+
.append(Expression::CallResult(fun_callee), span);
132+
133+
if call {
134+
fun_caller.body.push(
135+
naga::Statement::Call {
136+
function: fun_callee,
137+
arguments: vec![],
138+
result: Some(ex_result),
139+
},
140+
span,
141+
);
142+
} else {
143+
fun_caller.body.push(
144+
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)),
145+
span,
146+
);
147+
}
148+
149+
module.functions.append(fun_caller, span);
150+
151+
valid::Validator::new(
152+
valid::ValidationFlags::default(),
153+
valid::Capabilities::all(),
154+
)
155+
.validate(&module)
156+
}
157+
158+
variant(true).expect("should validate");
159+
assert!(variant(false).is_err());
160+
}
161+
162+
#[test]
163+
fn emit_workgroup_uniform_load_result() {
164+
use naga::{Module, Type, TypeInner};
165+
166+
// We want to ensure that the *only* problem with the code is the
167+
// use of an `Emit` statement instead of an `Atomic` statement. So
168+
// validate two versions of the module varying only in that
169+
// aspect.
170+
//
171+
// Looking at uses of the `wg_load` makes it easy to identify the
172+
// differences between the two variants.
173+
fn variant(
174+
wg_load: bool,
175+
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> {
176+
let span = naga::Span::default();
177+
let mut module = Module::default();
178+
let ty_u32 = module.types.insert(
179+
Type {
180+
name: Some("u32".into()),
181+
inner: TypeInner::Scalar(Scalar::U32),
182+
},
183+
span,
184+
);
185+
let var_workgroup = module.global_variables.append(
186+
naga::GlobalVariable {
187+
name: Some("workgroup_global".into()),
188+
space: naga::AddressSpace::WorkGroup,
189+
binding: None,
190+
ty: ty_u32,
191+
init: None,
192+
},
193+
span,
194+
);
195+
196+
let mut fun = Function::default();
197+
let ex_global = fun
198+
.expressions
199+
.append(Expression::GlobalVariable(var_workgroup), span);
200+
let ex_result = fun
201+
.expressions
202+
.append(Expression::WorkGroupUniformLoadResult { ty: ty_u32 }, span);
203+
204+
if wg_load {
205+
fun.body.push(
206+
naga::Statement::WorkGroupUniformLoad {
207+
pointer: ex_global,
208+
result: ex_result,
209+
},
210+
span,
211+
);
212+
} else {
213+
fun.body.push(
214+
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)),
215+
span,
216+
);
217+
}
218+
219+
module.functions.append(fun, span);
220+
221+
valid::Validator::new(
222+
valid::ValidationFlags::default(),
223+
valid::Capabilities::all(),
224+
)
225+
.validate(&module)
226+
}
227+
228+
variant(true).expect("module should validate");
229+
assert!(variant(false).is_err());
230+
}

0 commit comments

Comments
 (0)