use wgpu::{DownlevelFlags, Limits}; use crate::shader::{shader_input_output_test, InputStorageType, ShaderTest}; use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters}; fn create_numeric_builtin_test() -> Vec { let mut tests = Vec::new(); #[rustfmt::skip] let clamp_values: &[(f32, f32, f32, &[f32])] = &[ // value - low - high - valid outputs // normal clamps ( 20.0, 0.0, 10.0, &[10.0]), ( -10.0, 0.0, 10.0, &[0.0]), ( 5.0, 0.0, 10.0, &[5.0]), // med-of-three or min/max ( 3.0, 2.0, 1.0, &[1.0, 2.0]), ]; for &(input, low, high, output) in clamp_values { let mut test = ShaderTest::new( format!("clamp({input}, {low}, {high}) == {output:?}"), String::from("value: f32, low: f32, high: f32"), String::from("output[0] = bitcast(clamp(input.value, input.low, input.high));"), &[input, low, high], &[output[0]], ); for &extra in &output[1..] { test = test.extra_output_values(&[extra]); } tests.push(test); } tests } #[gpu_test] static NUMERIC_BUILTINS: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Storage, create_numeric_builtin_test(), ) }); fn create_int64_atomic_min_max_test() -> Vec { let mut tests = Vec::new(); let test = ShaderTest::new( "atomicMax".into(), "value: u64".into(), "atomicMin(&output, 0lu); atomicMax(&output, 2lu);".into(), &[0], &[2], ) .output_type("atomic".into()); tests.push(test); let test = ShaderTest::new( "atomicMin".into(), "value: u64".into(), "atomicMax(&output, 100lu); atomicMin(&output, 4lu);".into(), &[0], &[4], ) .output_type("atomic".into()); tests.push(test); tests } #[gpu_test] static INT64_ATOMIC_MIN_MAX: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .features(wgpu::Features::SHADER_INT64 | wgpu::Features::SHADER_INT64_ATOMIC_MIN_MAX) .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Storage, create_int64_atomic_min_max_test(), ) }); fn create_int64_atomic_all_ops_test() -> Vec { let mut tests = Vec::new(); let test = ShaderTest::new( "atomicAdd".into(), "value: u64".into(), "atomicStore(&output, 0lu); atomicAdd(&output, 1lu); atomicAdd(&output, 1lu);".into(), &[0], &[2], ) .output_type("atomic".into()); tests.push(test); let test = ShaderTest::new( "atomicAnd".into(), "value: u64".into(), "atomicStore(&output, 31lu); atomicAnd(&output, 30lu); atomicAnd(&output, 3lu);".into(), &[0], &[2], ) .output_type("atomic".into()); tests.push(test); let test = ShaderTest::new( "atomicOr".into(), "value: u64".into(), "atomicStore(&output, 0lu); atomicOr(&output, 3lu); atomicOr(&output, 6lu);".into(), &[0], &[7], ) .output_type("atomic".into()); tests.push(test); tests } #[gpu_test] static INT64_ATOMIC_ALL_OPS: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .features(wgpu::Features::SHADER_INT64 | wgpu::Features::SHADER_INT64_ATOMIC_ALL_OPS) .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Storage, create_int64_atomic_all_ops_test(), ) }); fn create_float32_atomic_test() -> Vec { let mut tests = Vec::new(); let test = ShaderTest::new( "atomicAdd".into(), "value: f32".into(), "atomicStore(&output, 0.0); atomicAdd(&output, -0.50); atomicAdd(&output, 1.75);".into(), &[0_f32], &[1.25_f32], ) .output_type("atomic".into()); tests.push(test); let test = ShaderTest::new( "atomicAdd".into(), "value: f32".into(), "atomicStore(&output, 0.0); atomicSub(&output, -2.5); atomicSub(&output, 3.0);".into(), &[0_f32], &[-0.5_f32], ) .output_type("atomic".into()); tests.push(test); tests } #[gpu_test] static FLOAT32_ATOMIC: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .features(wgpu::Features::SHADER_FLOAT32_ATOMIC) .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) .run_async(|ctx| { shader_input_output_test(ctx, InputStorageType::Storage, create_float32_atomic_test()) }); // See https://github.com/gfx-rs/wgpu/issues/5276 /* fn create_int64_polyfill_test() -> Vec { let mut tests = Vec::new(); let u64_clz_values: &[(u64, u32)] = &[ (u64::MAX, 0), (1, 63), (2, 62), (3, 62), (1 << 63, 0), (1 << 62, 1), (0, 64), ]; for &(input, output) in u64_clz_values { let test = ShaderTest::new( format!("countLeadingZeros({input}lu) == {output:?}"), String::from("value: u64"), String::from("output[0] = u32(countLeadingZeros(input.value));"), &[input], &[output], ); tests.push(test); } let i64_clz_values: &[(i64, u32)] = &[ (i64::MAX, 1), (i64::MIN, 0), (1, 63), (1 << 62, 1), (-1 << 62, 0), (0, 64), (-1, 0), ]; for &(input, output) in i64_clz_values { let test = ShaderTest::new( format!("countLeadingZeros({input}li) == {output:?}"), String::from("value: i64"), String::from("output[0] = u32(countLeadingZeros(input.value));"), &[input], &[output], ); tests.push(test); } let u64_flb_values: &[(u64, u32)] = &[ (u64::MAX, 63), (1, 0), (2, 1), (3, 1), (1 << 63, 63), (1 << 62, 62), (0, u32::MAX), ]; for &(input, output) in u64_flb_values { let test = ShaderTest::new( format!("firstLeadingBit({input}lu) == {output:?}"), String::from("value: u64"), String::from("output[0] = u32(firstLeadingBit(input.value));"), &[input], &[output], ); tests.push(test); } let i64_flb_values: &[(i64, u32)] = &[ (i64::MAX, 62), (i64::MIN, 62), (1, 0), (1 << 62, 62), (-1 << 62, 61), (0, u32::MAX), (-1, u32::MAX), ]; for &(input, output) in i64_flb_values { let test = ShaderTest::new( format!("firstLeadingBit({input}li) == {output:?}"), String::from("value: i64"), String::from("output[0] = u32(firstLeadingBit(input.value));"), &[input], &[output], ); tests.push(test); } tests } #[gpu_test] static INT64_POLYFILL: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .features(Features::SHADER_INT64) .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) .run_async(|ctx| { shader_input_output_test(ctx, InputStorageType::Storage, create_int64_polyfill_test()) }); */