mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
[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.
This commit is contained in:
parent
59cd0e964b
commit
89a0ebfbd6
@ -1,4 +1,5 @@
|
||||
mod example_wgsl;
|
||||
mod snapshots;
|
||||
mod spirv_capabilities;
|
||||
mod validation;
|
||||
mod wgsl_errors;
|
||||
|
230
naga/tests/validation.rs
Normal file
230
naga/tests/validation.rs
Normal file
@ -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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user