wgpu/player/tests/test.rs

225 lines
7.1 KiB
Rust
Raw Normal View History

2020-07-17 03:56:47 +00:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*! Tester for WebGPU
* It enumerates the available backends on the system,
* and run the tests through them.
*
* Test requirements:
* - all IDs have the backend `Empty`
* - all expected buffers have `MAP_READ` usage
* - last action is `Submit`
* - no swapchain use
2020-07-17 03:56:47 +00:00
!*/
use player::{GlobalPlay, IdentityPassThroughFactory};
2020-07-17 03:56:47 +00:00
use std::{
fs::{read_to_string, File},
2020-08-29 23:03:10 +00:00
io::{Read, Seek, SeekFrom},
2020-07-17 03:56:47 +00:00
path::{Path, PathBuf},
ptr, slice,
};
#[derive(serde::Deserialize)]
struct RawId {
index: u32,
epoch: u32,
}
2020-08-29 23:03:10 +00:00
#[derive(serde::Deserialize)]
enum ExpectedData {
Raw(Vec<u8>),
File(String, usize),
}
impl ExpectedData {
fn len(&self) -> usize {
match self {
ExpectedData::Raw(vec) => vec.len(),
ExpectedData::File(_, size) => *size,
}
}
}
2020-07-17 03:56:47 +00:00
#[derive(serde::Deserialize)]
struct Expectation {
name: String,
buffer: RawId,
offset: wgt::BufferAddress,
2020-08-29 23:03:10 +00:00
data: ExpectedData,
2020-07-17 03:56:47 +00:00
}
#[derive(serde::Deserialize)]
struct Test<'a> {
2020-07-17 03:56:47 +00:00
features: wgt::Features,
expectations: Vec<Expectation>,
actions: Vec<wgc::device::trace::Action<'a>>,
2020-07-17 03:56:47 +00:00
}
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()
2020-07-17 03:56:47 +00:00
}
fn run(
self,
dir: &Path,
global: &wgc::hub::Global<IdentityPassThroughFactory>,
adapter: wgc::id::AdapterId,
2020-08-29 23:03:10 +00:00
test_num: u32,
) {
let backend = adapter.backend();
let device = wgc::id::TypedId::zip(test_num, 0, backend);
let (_, error) = wgc::gfx_select!(adapter => global.adapter_request_device(
adapter,
&wgt::DeviceDescriptor {
label: None,
features: self.features | wgt::Features::MAPPABLE_PRIMARY_BUFFERS,
limits: wgt::Limits::default(),
shader_validation: true,
},
None,
device
));
2020-11-21 05:05:56 +00:00
if let Some(e) = error {
panic!("{:?}", e);
}
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
println!("\t\t\tRunning...");
for action in self.actions {
wgc::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);
wgc::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(),
}
2020-07-18 08:48:14 +00:00
))
.unwrap();
}
2020-07-17 03:56:47 +00:00
println!("\t\t\tWaiting...");
wgc::gfx_select!(device => global.device_poll(device, true)).unwrap();
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 =
wgc::gfx_select!(device => global.buffer_get_mapped_range(buffer, expect.offset, None))
2020-07-18 08:48:14 +00:00
.unwrap();
let contents = unsafe { slice::from_raw_parts(ptr, expect.data.len()) };
2020-08-29 23:03:10 +00:00
let expected_data = match expect.data {
ExpectedData::Raw(vec) => vec,
ExpectedData::File(name, size) => {
let mut bin = vec![0; size];
let mut file = File::open(dir.join(name)).unwrap();
file.seek(SeekFrom::Start(expect.offset)).unwrap();
file.read_exact(&mut bin[..]).unwrap();
bin
}
};
assert_eq!(&expected_data[..], contents);
}
2020-09-05 03:45:00 +00:00
wgc::gfx_select!(device => global.clear_backend(()));
2020-07-17 03:56:47 +00:00
}
}
#[derive(serde::Deserialize)]
struct Corpus {
backends: wgt::BackendBit,
tests: Vec<String>,
}
2020-07-17 03:56:47 +00:00
const BACKENDS: &[wgt::Backend] = &[
wgt::Backend::Vulkan,
wgt::Backend::Metal,
wgt::Backend::Dx12,
wgt::Backend::Dx11,
wgt::Backend::Gl,
];
2020-07-17 03:56:47 +00:00
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();
let global = wgc::hub::Global::new("test", IdentityPassThroughFactory, corpus.backends);
for &backend in BACKENDS {
if !corpus.backends.contains(backend.into()) {
2020-07-17 03:56:47 +00:00
continue;
}
let adapter = match global.request_adapter(
&wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::LowPower,
compatible_surface: None,
},
wgc::instance::AdapterInputs::IdSet(
&[wgc::id::TypedId::zip(0, 0, backend)],
|id| id.backend(),
),
) {
Ok(adapter) => adapter,
Err(_) => continue,
};
println!("\tBackend {:?}", backend);
let supported_features =
wgc::gfx_select!(adapter => global.adapter_features(adapter)).unwrap();
2020-08-29 23:03:10 +00:00
let mut test_num = 0;
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;
}
2020-08-29 23:03:10 +00:00
test.run(dir, &global, adapter, test_num);
test_num += 1;
}
2020-07-17 03:56:47 +00:00
}
}
}
#[test]
fn test_api() {
wgpu_subscriber::initialize_default_subscriber(
std::env::var("WGPU_CHROME_TRACE")
.as_ref()
.map(Path::new)
.ok(),
);
Corpus::run_from(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/data/all.ron"))
2020-07-17 03:56:47 +00:00
}