-
Notifications
You must be signed in to change notification settings - Fork 909
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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.
- Loading branch information
Showing
2 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
mod example_wgsl; | ||
mod snapshots; | ||
mod spirv_capabilities; | ||
mod validation; | ||
mod wgsl_errors; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
use naga::{valid, Expression, Function, Scalar}; | ||
|
||
#[test] | ||
fn emit_atomic_result() { | ||
use naga::{Module, Type, TypeInner}; | ||
|
||
// We want to ensure that the *only* problem with the code is the | ||
// use of an `Emit` statement instead of an `Atomic` statement. So | ||
// validate two versions of the module varying only in that | ||
// aspect. | ||
// | ||
// Looking at uses of the `atomic` makes it easy to identify the | ||
// differences between the two variants. | ||
fn variant( | ||
atomic: bool, | ||
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> { | ||
let span = naga::Span::default(); | ||
let mut module = Module::default(); | ||
let ty_u32 = module.types.insert( | ||
Type { | ||
name: Some("u32".into()), | ||
inner: TypeInner::Scalar(Scalar::U32), | ||
}, | ||
span, | ||
); | ||
let ty_atomic_u32 = module.types.insert( | ||
Type { | ||
name: Some("atomic<u32>".into()), | ||
inner: TypeInner::Atomic(Scalar::U32), | ||
}, | ||
span, | ||
); | ||
let var_atomic = module.global_variables.append( | ||
naga::GlobalVariable { | ||
name: Some("atomic_global".into()), | ||
space: naga::AddressSpace::WorkGroup, | ||
binding: None, | ||
ty: ty_atomic_u32, | ||
init: None, | ||
}, | ||
span, | ||
); | ||
|
||
let mut fun = Function::default(); | ||
let ex_global = fun | ||
.expressions | ||
.append(Expression::GlobalVariable(var_atomic), span); | ||
let ex_42 = fun | ||
.expressions | ||
.append(Expression::Literal(naga::Literal::U32(42)), span); | ||
let ex_result = fun.expressions.append( | ||
Expression::AtomicResult { | ||
ty: ty_u32, | ||
comparison: false, | ||
}, | ||
span, | ||
); | ||
|
||
if atomic { | ||
fun.body.push( | ||
naga::Statement::Atomic { | ||
pointer: ex_global, | ||
fun: naga::AtomicFunction::Add, | ||
value: ex_42, | ||
result: ex_result, | ||
}, | ||
span, | ||
); | ||
} else { | ||
fun.body.push( | ||
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)), | ||
span, | ||
); | ||
} | ||
|
||
module.functions.append(fun, span); | ||
|
||
valid::Validator::new( | ||
valid::ValidationFlags::default(), | ||
valid::Capabilities::all(), | ||
) | ||
.validate(&module) | ||
} | ||
|
||
variant(true).expect("module should validate"); | ||
assert!(variant(false).is_err()); | ||
} | ||
|
||
#[test] | ||
fn emit_call_result() { | ||
use naga::{Module, Type, TypeInner}; | ||
|
||
// We want to ensure that the *only* problem with the code is the | ||
// use of an `Emit` statement instead of a `Call` statement. So | ||
// validate two versions of the module varying only in that | ||
// aspect. | ||
// | ||
// Looking at uses of the `call` makes it easy to identify the | ||
// differences between the two variants. | ||
fn variant( | ||
call: bool, | ||
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> { | ||
let span = naga::Span::default(); | ||
let mut module = Module::default(); | ||
let ty_u32 = module.types.insert( | ||
Type { | ||
name: Some("u32".into()), | ||
inner: TypeInner::Scalar(Scalar::U32), | ||
}, | ||
span, | ||
); | ||
|
||
let mut fun_callee = Function { | ||
result: Some(naga::FunctionResult { | ||
ty: ty_u32, | ||
binding: None, | ||
}), | ||
..Function::default() | ||
}; | ||
let ex_42 = fun_callee | ||
.expressions | ||
.append(Expression::Literal(naga::Literal::U32(42)), span); | ||
fun_callee | ||
.body | ||
.push(naga::Statement::Return { value: Some(ex_42) }, span); | ||
let fun_callee = module.functions.append(fun_callee, span); | ||
|
||
let mut fun_caller = Function::default(); | ||
let ex_result = fun_caller | ||
.expressions | ||
.append(Expression::CallResult(fun_callee), span); | ||
|
||
if call { | ||
fun_caller.body.push( | ||
naga::Statement::Call { | ||
function: fun_callee, | ||
arguments: vec![], | ||
result: Some(ex_result), | ||
}, | ||
span, | ||
); | ||
} else { | ||
fun_caller.body.push( | ||
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)), | ||
span, | ||
); | ||
} | ||
|
||
module.functions.append(fun_caller, span); | ||
|
||
valid::Validator::new( | ||
valid::ValidationFlags::default(), | ||
valid::Capabilities::all(), | ||
) | ||
.validate(&module) | ||
} | ||
|
||
variant(true).expect("should validate"); | ||
assert!(variant(false).is_err()); | ||
} | ||
|
||
#[test] | ||
fn emit_workgroup_uniform_load_result() { | ||
use naga::{Module, Type, TypeInner}; | ||
|
||
// We want to ensure that the *only* problem with the code is the | ||
// use of an `Emit` statement instead of an `Atomic` statement. So | ||
// validate two versions of the module varying only in that | ||
// aspect. | ||
// | ||
// Looking at uses of the `wg_load` makes it easy to identify the | ||
// differences between the two variants. | ||
fn variant( | ||
wg_load: bool, | ||
) -> Result<naga::valid::ModuleInfo, naga::WithSpan<naga::valid::ValidationError>> { | ||
let span = naga::Span::default(); | ||
let mut module = Module::default(); | ||
let ty_u32 = module.types.insert( | ||
Type { | ||
name: Some("u32".into()), | ||
inner: TypeInner::Scalar(Scalar::U32), | ||
}, | ||
span, | ||
); | ||
let var_workgroup = module.global_variables.append( | ||
naga::GlobalVariable { | ||
name: Some("workgroup_global".into()), | ||
space: naga::AddressSpace::WorkGroup, | ||
binding: None, | ||
ty: ty_u32, | ||
init: None, | ||
}, | ||
span, | ||
); | ||
|
||
let mut fun = Function::default(); | ||
let ex_global = fun | ||
.expressions | ||
.append(Expression::GlobalVariable(var_workgroup), span); | ||
let ex_result = fun | ||
.expressions | ||
.append(Expression::WorkGroupUniformLoadResult { ty: ty_u32 }, span); | ||
|
||
if wg_load { | ||
fun.body.push( | ||
naga::Statement::WorkGroupUniformLoad { | ||
pointer: ex_global, | ||
result: ex_result, | ||
}, | ||
span, | ||
); | ||
} else { | ||
fun.body.push( | ||
naga::Statement::Emit(naga::Range::new_from_bounds(ex_result, ex_result)), | ||
span, | ||
); | ||
} | ||
|
||
module.functions.append(fun, span); | ||
|
||
valid::Validator::new( | ||
valid::ValidationFlags::default(), | ||
valid::Capabilities::all(), | ||
) | ||
.validate(&module) | ||
} | ||
|
||
variant(true).expect("module should validate"); | ||
assert!(variant(false).is_err()); | ||
} |