playtest: move the actions together with expectations

This commit is contained in:
Dzmitry Malyshau 2020-07-17 10:59:02 -04:00
parent acef9206a6
commit eb7bdcd012
4 changed files with 145 additions and 142 deletions

View File

@ -12,11 +12,6 @@ keywords = ["graphics"]
license = "MPL-2.0"
publish = false
[lib]
[[bin]]
name = "play"
[features]
[dependencies]

View File

@ -1,17 +1,6 @@
(
backends: (bits: 0x7),
tests: [
(
path: "buffer-copy.ron",
features: (bits: 0x0),
expectations: [
(
name: "basic",
buffer: (index: 0, epoch: 1),
offset: 0,
data: [0x00, 0x00, 0x80, 0xBF],
)
],
),
"buffer-copy.ron",
],
)

View File

@ -1,23 +1,34 @@
[
CreateBuffer(
id: Id(0, 1, Empty),
desc: (
label: "",
size: 16,
usage: (
bits: 41,
(
features: (bits: 0x0),
expectations: [
(
name: "basic",
buffer: (index: 0, epoch: 1),
offset: 0,
data: [0x00, 0x00, 0x80, 0xBF],
)
],
actions: [
CreateBuffer(
id: Id(0, 1, Empty),
desc: (
label: "",
size: 16,
usage: (
bits: 41,
),
mapped_at_creation: false,
),
mapped_at_creation: false,
),
),
WriteBuffer(
id: Id(0, 1, Empty),
data: "data1.bin",
range: (
start: 0,
end: 16,
WriteBuffer(
id: Id(0, 1, Empty),
data: "data1.bin",
range: (
start: 0,
end: 16,
),
queued: true,
),
queued: true,
),
Submit(1, []),
]
Submit(1, []),
],
)

View File

@ -10,6 +10,7 @@
* - all IDs have the backend `Empty`
* - all expected buffers have `MAP_READ` usage
* - last action is `Submit`
* - no swapchain use
!*/
use player::{gfx_select, GlobalPlay, IdentityPassThroughFactory};
@ -35,15 +36,88 @@ struct Expectation {
#[derive(serde::Deserialize)]
struct Test {
path: String,
features: wgt::Features,
expectations: Vec<Expectation>,
actions: Vec<wgc::device::trace::Action>,
}
extern "C" fn map_callback(status: wgc::resource::BufferMapAsyncStatus, _user_data: *mut u8) {
match status {
wgc::resource::BufferMapAsyncStatus::Success => (),
_ => panic!("Unable to map"),
}
}
impl Test {
fn load(path: PathBuf, backend: wgt::Backend) -> Self {
let backend_name = match backend {
wgt::Backend::Vulkan => "Vulkan",
wgt::Backend::Metal => "Metal",
wgt::Backend::Dx12 => "Dx12",
wgt::Backend::Dx11 => "Dx11",
wgt::Backend::Gl => "Gl",
_ => unreachable!(),
};
let string = read_to_string(path).unwrap().replace("Empty", backend_name);
ron::de::from_str(&string).unwrap()
}
fn run(
self,
dir: &Path,
global: &wgc::hub::Global<IdentityPassThroughFactory>,
adapter: wgc::id::AdapterId,
) {
let backend = adapter.backend();
let device = gfx_select!(adapter => global.adapter_request_device(
adapter,
&wgt::DeviceDescriptor {
features: self.features | wgt::Features::MAPPABLE_PRIMARY_BUFFERS,
limits: wgt::Limits::default(),
shader_validation: true,
},
None,
wgc::id::TypedId::zip(1, 0, backend)
))
.unwrap();
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
println!("\t\t\tRunning...");
for action in self.actions {
gfx_select!(device => global.process(device, action, dir, &mut command_buffer_id_manager));
}
println!("\t\t\tMapping...");
for expect in &self.expectations {
let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend);
gfx_select!(device => global.buffer_map_async(
buffer,
expect.offset .. expect.offset+expect.data.len() as wgt::BufferAddress,
wgc::resource::BufferMapOperation {
host: wgc::device::HostMap::Read,
callback: map_callback,
user_data: ptr::null_mut(),
}
));
}
println!("\t\t\tWaiting...");
gfx_select!(device => global.device_poll(device, true));
for expect in self.expectations {
println!("\t\t\tChecking {}", expect.name);
let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend);
let ptr =
gfx_select!(device => global.buffer_get_mapped_range(buffer, expect.offset, None));
let contents = unsafe { slice::from_raw_parts(ptr, expect.data.len()) };
assert_eq!(&expect.data[..], contents);
}
}
}
#[derive(serde::Deserialize)]
struct Corpus {
backends: wgt::BackendBit,
tests: Vec<Test>,
tests: Vec<String>,
}
const BACKENDS: &[wgt::Backend] = &[
@ -54,116 +128,50 @@ const BACKENDS: &[wgt::Backend] = &[
wgt::Backend::Gl,
];
extern "C" fn map_callback(status: wgc::resource::BufferMapAsyncStatus, _user_data: *mut u8) {
match status {
wgc::resource::BufferMapAsyncStatus::Success => (),
_ => panic!("Unable to map"),
}
}
impl Corpus {
fn run_from(path: PathBuf) {
println!("Corpus {:?}", path);
let dir = path.parent().unwrap();
let corpus: Corpus = ron::de::from_reader(File::open(&path).unwrap()).unwrap();
fn run_test(
test: Test,
dir: &Path,
global: &wgc::hub::Global<IdentityPassThroughFactory>,
adapter: wgc::id::AdapterId,
) {
println!("\t\tTest '{:?}'", test.path);
let device = gfx_select!(adapter => global.adapter_request_device(
adapter,
&wgt::DeviceDescriptor {
features: test.features | wgt::Features::MAPPABLE_PRIMARY_BUFFERS,
limits: wgt::Limits::default(),
shader_validation: true,
},
None,
wgc::id::TypedId::zip(1, 0, adapter.backend())
))
.unwrap();
let backend = device.backend();
let backend_name = match backend {
wgt::Backend::Vulkan => "Vulkan",
wgt::Backend::Metal => "Metal",
wgt::Backend::Dx12 => "Dx12",
wgt::Backend::Dx11 => "Dx11",
wgt::Backend::Gl => "Gl",
_ => unreachable!(),
};
let string = read_to_string(dir.join(test.path))
.unwrap()
.replace("Empty", backend_name);
let actions: Vec<wgc::device::trace::Action> = ron::de::from_str(&string).unwrap();
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
println!("\t\t\tRunning...");
for action in actions {
gfx_select!(device => global.process(device, action, dir, &mut command_buffer_id_manager));
}
println!("\t\t\tMapping...");
for expect in &test.expectations {
let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend);
gfx_select!(device => global.buffer_map_async(
buffer,
expect.offset .. expect.offset+expect.data.len() as wgt::BufferAddress,
wgc::resource::BufferMapOperation {
host: wgc::device::HostMap::Read,
callback: map_callback,
user_data: ptr::null_mut(),
}
));
}
println!("\t\t\tWaiting...");
gfx_select!(device => global.device_poll(device, true));
for expect in test.expectations {
println!("\t\t\tChecking {}", expect.name);
let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend);
let ptr =
gfx_select!(device => global.buffer_get_mapped_range(buffer, expect.offset, None));
let contents = unsafe { slice::from_raw_parts(ptr, expect.data.len()) };
assert_eq!(&expect.data[..], contents);
}
}
fn run_corpus(path: PathBuf) {
println!("Corpus {:?}", path);
let mut corpus: Corpus = ron::de::from_reader(File::open(&path).unwrap()).unwrap();
let global = wgc::hub::Global::new("test", IdentityPassThroughFactory, corpus.backends);
for &backend in BACKENDS {
if !corpus.backends.contains(backend.into()) {
continue;
}
let adapter = match global.pick_adapter(
&wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::Default,
compatible_surface: None,
},
wgc::instance::AdapterInputs::IdSet(&[wgc::id::TypedId::zip(0, 0, backend)], |id| {
id.backend()
}),
) {
Some(adapter) => adapter,
None => continue,
};
println!("\tBackend {:?}", backend);
let supported_features = gfx_select!(adapter => global.adapter_features(adapter));
for test in corpus.tests.drain(..) {
if !supported_features.contains(test.features) {
println!(
"\t\tSkipped due to missing features {:?}",
test.features - supported_features
);
let global = wgc::hub::Global::new("test", IdentityPassThroughFactory, corpus.backends);
for &backend in BACKENDS {
if !corpus.backends.contains(backend.into()) {
continue;
}
run_test(test, path.parent().unwrap(), &global, adapter);
let adapter = match global.pick_adapter(
&wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::Default,
compatible_surface: None,
},
wgc::instance::AdapterInputs::IdSet(
&[wgc::id::TypedId::zip(0, 0, backend)],
|id| id.backend(),
),
) {
Some(adapter) => adapter,
None => continue,
};
println!("\tBackend {:?}", backend);
let supported_features = gfx_select!(adapter => global.adapter_features(adapter));
for test_path in &corpus.tests {
println!("\t\tTest '{:?}'", test_path);
let test = Test::load(dir.join(test_path), adapter.backend());
if !supported_features.contains(test.features) {
println!(
"\t\tSkipped due to missing features {:?}",
test.features - supported_features
);
continue;
}
test.run(dir, &global, adapter);
}
}
}
}
#[test]
fn test_api() {
run_corpus(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/data/all.ron"))
Corpus::run_from(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/data/all.ron"))
}