mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
204 lines
6.9 KiB
Rust
204 lines
6.9 KiB
Rust
use arrayvec::ArrayVec;
|
|
use wgpu::{DownlevelCapabilities, DownlevelFlags, Features, InstanceFlags, Limits};
|
|
|
|
use crate::{
|
|
report::AdapterReport, FailureApplicationReasons, FailureBehavior, FailureCase,
|
|
GpuTestConfiguration,
|
|
};
|
|
|
|
const LOWEST_DOWNLEVEL_PROPERTIES: wgpu::DownlevelCapabilities = DownlevelCapabilities {
|
|
flags: wgpu::DownlevelFlags::empty(),
|
|
limits: wgpu::DownlevelLimits {},
|
|
shader_model: wgpu::ShaderModel::Sm2,
|
|
};
|
|
|
|
/// This information determines if a test should run.
|
|
#[derive(Clone)]
|
|
pub struct TestParameters {
|
|
pub required_features: Features,
|
|
pub required_downlevel_caps: DownlevelCapabilities,
|
|
pub required_limits: Limits,
|
|
|
|
pub required_instance_flags: InstanceFlags,
|
|
|
|
/// On Dx12, specifically test against the Fxc compiler.
|
|
///
|
|
/// For testing workarounds to Fxc bugs.
|
|
pub force_fxc: bool,
|
|
|
|
/// Conditions under which this test should be skipped.
|
|
pub skips: Vec<FailureCase>,
|
|
|
|
/// Conditions under which this test should be run, but is expected to fail.
|
|
pub failures: Vec<FailureCase>,
|
|
}
|
|
|
|
impl Default for TestParameters {
|
|
fn default() -> Self {
|
|
Self {
|
|
required_features: Features::empty(),
|
|
required_downlevel_caps: LOWEST_DOWNLEVEL_PROPERTIES,
|
|
required_limits: Limits::downlevel_webgl2_defaults(),
|
|
required_instance_flags: InstanceFlags::empty(),
|
|
force_fxc: false,
|
|
// By default we skip the noop backend, and enable it if the test
|
|
// parameters ask us to remove it.
|
|
skips: vec![FailureCase::backend(wgpu::Backends::NOOP)],
|
|
failures: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Builder pattern to make it easier
|
|
impl TestParameters {
|
|
/// Set of common features that most internal tests require for compute and readback.
|
|
pub fn test_features_limits(self) -> Self {
|
|
self.downlevel_flags(DownlevelFlags::COMPUTE_SHADERS)
|
|
.limits(wgpu::Limits::downlevel_defaults())
|
|
}
|
|
|
|
/// Set the list of features this test requires.
|
|
pub fn features(mut self, features: Features) -> Self {
|
|
self.required_features |= features;
|
|
self
|
|
}
|
|
|
|
pub fn downlevel_flags(mut self, downlevel_flags: DownlevelFlags) -> Self {
|
|
self.required_downlevel_caps.flags |= downlevel_flags;
|
|
self
|
|
}
|
|
|
|
/// Set the limits needed for the test.
|
|
pub fn limits(mut self, limits: Limits) -> Self {
|
|
self.required_limits = limits;
|
|
self
|
|
}
|
|
|
|
/// Sets the instance flags that the test requires.
|
|
pub fn instance_flags(mut self, instance_flags: InstanceFlags) -> Self {
|
|
self.required_instance_flags |= instance_flags;
|
|
self
|
|
}
|
|
|
|
pub fn force_fxc(mut self, force_fxc: bool) -> Self {
|
|
self.force_fxc = force_fxc;
|
|
self
|
|
}
|
|
|
|
/// Mark the test as always failing, but not to be skipped.
|
|
pub fn expect_fail(mut self, when: FailureCase) -> Self {
|
|
self.failures.push(when);
|
|
self
|
|
}
|
|
|
|
/// Mark the test as always failing, and needing to be skipped.
|
|
pub fn skip(mut self, when: FailureCase) -> Self {
|
|
self.skips.push(when);
|
|
self
|
|
}
|
|
|
|
/// Enable testing against the noop backend and miri.
|
|
///
|
|
/// The noop backend does not execute any operations, but allows us to test
|
|
/// validation and memory safety.
|
|
pub fn enable_noop(mut self) -> Self {
|
|
self.skips
|
|
.retain(|case| *case != FailureCase::backend(wgpu::Backends::NOOP));
|
|
self
|
|
}
|
|
}
|
|
|
|
/// Information about a test, including if if it should be skipped.
|
|
pub struct TestInfo {
|
|
pub skip: bool,
|
|
pub failure_application_reasons: FailureApplicationReasons,
|
|
pub failures: Vec<FailureCase>,
|
|
pub running_msg: String,
|
|
}
|
|
|
|
impl TestInfo {
|
|
pub(crate) fn from_configuration(test: &GpuTestConfiguration, adapter: &AdapterReport) -> Self {
|
|
// Figure out if a test is unsupported, and why.
|
|
let mut unsupported_reasons: ArrayVec<_, 4> = ArrayVec::new();
|
|
let missing_features = test.params.required_features - adapter.features;
|
|
if !missing_features.is_empty() {
|
|
unsupported_reasons.push("Features");
|
|
}
|
|
|
|
if !test.params.required_limits.check_limits(&adapter.limits) {
|
|
unsupported_reasons.push("Limits");
|
|
}
|
|
|
|
let missing_downlevel_flags =
|
|
test.params.required_downlevel_caps.flags - adapter.downlevel_caps.flags;
|
|
if !missing_downlevel_flags.is_empty() {
|
|
unsupported_reasons.push("Downlevel Flags");
|
|
}
|
|
|
|
if test.params.required_downlevel_caps.shader_model > adapter.downlevel_caps.shader_model {
|
|
unsupported_reasons.push("Shader Model");
|
|
}
|
|
|
|
// Produce a lower-case version of the adapter info, for comparison against
|
|
// `parameters.skips` and `parameters.failures`.
|
|
let adapter_lowercase_info = wgpu::AdapterInfo {
|
|
name: adapter.info.name.to_lowercase(),
|
|
driver: adapter.info.driver.to_lowercase(),
|
|
..adapter.info.clone()
|
|
};
|
|
|
|
// Check if we should skip the test altogether.
|
|
let skip_application_reason = test
|
|
.params
|
|
.skips
|
|
.iter()
|
|
.find_map(|case| case.applies_to_adapter(&adapter_lowercase_info));
|
|
|
|
let mut applicable_cases = Vec::with_capacity(test.params.failures.len());
|
|
let mut failure_application_reasons = FailureApplicationReasons::empty();
|
|
let mut flaky = false;
|
|
for failure in &test.params.failures {
|
|
if let Some(reasons) = failure.applies_to_adapter(&adapter_lowercase_info) {
|
|
failure_application_reasons.insert(reasons);
|
|
applicable_cases.push(failure.clone());
|
|
flaky |= matches!(failure.behavior, FailureBehavior::Ignore);
|
|
}
|
|
}
|
|
|
|
let mut skip = false;
|
|
let running_msg = if let Some(reasons) = skip_application_reason {
|
|
skip = true;
|
|
|
|
let names: ArrayVec<_, 4> = reasons.iter_names().map(|(name, _)| name).collect();
|
|
let names_text = names.join(" | ");
|
|
|
|
format!("Skipped Failure: {names_text}")
|
|
} else if !unsupported_reasons.is_empty() {
|
|
skip = true;
|
|
format!("Unsupported: {}", unsupported_reasons.join(" | "))
|
|
} else if !failure_application_reasons.is_empty() {
|
|
if cfg!(target_arch = "wasm32") {
|
|
skip = true;
|
|
}
|
|
|
|
let names: ArrayVec<_, 4> = failure_application_reasons
|
|
.iter_names()
|
|
.map(|(name, _)| name)
|
|
.collect();
|
|
let names_text = names.join(" & ");
|
|
let flaky_text = if flaky { " Flaky " } else { " " };
|
|
|
|
format!("Executed{flaky_text}Failure: {names_text}")
|
|
} else {
|
|
String::from("Executed")
|
|
};
|
|
|
|
Self {
|
|
skip,
|
|
failure_application_reasons,
|
|
failures: applicable_cases,
|
|
running_msg,
|
|
}
|
|
}
|
|
}
|