Add image comparison to all examples

This commit is contained in:
Connor Fitzgerald 2021-06-20 02:32:21 -04:00
parent 22b8e2851f
commit ec74722d57
27 changed files with 344 additions and 29 deletions

2
.gitignore vendored
View File

@ -17,4 +17,4 @@
wgpu/red.png wgpu/red.png
# Output from invalid comparison tests # Output from invalid comparison tests
**/screenshot-difference.png **/*-difference.png

View File

@ -87,6 +87,26 @@ git = "https://github.com/gfx-rs/naga"
tag = "gfx-26" tag = "gfx-26"
features = ["wgsl-in", "spv-out"] features = ["wgsl-in", "spv-out"]
[[example]]
name="boids"
path="examples/boids/main.rs"
test = true
[[example]]
name="bunnymark"
path="examples/bunnymark/main.rs"
test = true
[[example]]
name="conservative-raster"
path="examples/conservative-raster/main.rs"
test = true
[[example]]
name="cube"
path="examples/cube/main.rs"
test = true
[[example]] [[example]]
name="hello-compute" name="hello-compute"
test = true test = true
@ -99,6 +119,31 @@ required-features = ["spirv"]
name="mipmap" name="mipmap"
test = true test = true
[[example]]
name="msaa-line"
path="examples/msaa-line/main.rs"
test = true
[[example]]
name="shadow"
path="examples/shadow/main.rs"
test = true
[[example]]
name="skybox"
path="examples/skybox/main.rs"
test = true
[[example]]
name="texture-arrays"
path="examples/texture-arrays/main.rs"
test = true
[[example]]
name="water"
path="examples/water/main.rs"
test = true
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.73" # remember to change version in wiki as well wasm-bindgen = "0.2.73" # remember to change version in wiki as well
web-sys = { version = "=0.3.50", features = [ web-sys = { version = "=0.3.50", features = [

View File

@ -1,7 +1,10 @@
// Flocking boids example with gpu compute update pass // Flocking boids example with gpu compute update pass
// adapted from https://github.com/austinEng/webgpu-samples/blob/master/src/examples/computeBoids.ts // adapted from https://github.com/austinEng/webgpu-samples/blob/master/src/examples/computeBoids.ts
use rand::distributions::{Distribution, Uniform}; use rand::{
distributions::{Distribution, Uniform},
SeedableRng,
};
use std::{borrow::Cow, mem}; use std::{borrow::Cow, mem};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
@ -168,7 +171,7 @@ impl framework::Example for Example {
// buffer for all particles data of type [(posx,posy,velx,vely),...] // buffer for all particles data of type [(posx,posy,velx,vely),...]
let mut initial_particle_data = vec![0.0f32; (4 * NUM_PARTICLES) as usize]; let mut initial_particle_data = vec![0.0f32; (4 * NUM_PARTICLES) as usize];
let mut rng = rand::thread_rng(); let mut rng = rand::rngs::StdRng::seed_from_u64(42);
let unif = Uniform::new_inclusive(-1.0, 1.0); let unif = Uniform::new_inclusive(-1.0, 1.0);
for particle_instance_chunk in initial_particle_data.chunks_mut(4) { for particle_instance_chunk in initial_particle_data.chunks_mut(4) {
particle_instance_chunk[0] = unif.sample(&mut rng); // posx particle_instance_chunk[0] = unif.sample(&mut rng); // posx
@ -314,3 +317,16 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("boids"); framework::run::<Example>("boids");
} }
#[test]
fn boids() {
framework::test::<Example>(
concat!(env!("CARGO_MANIFEST_DIR"), "/examples/boids/screenshot.png"),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
0,
50,
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -349,3 +349,19 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("bunnymark"); framework::run::<Example>("bunnymark");
} }
#[test]
fn bunnymark() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/bunnymark/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
0,
50,
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -73,7 +73,7 @@ impl framework::Example for Example {
} }
fn init( fn init(
sc_desc: &wgpu::SwapChainDescriptor, sc_desc: &wgpu::SwapChainDescriptor,
adapter: &wgpu::Adapter, _adapter: &wgpu::Adapter,
device: &wgpu::Device, device: &wgpu::Device,
_queue: &wgpu::Queue, _queue: &wgpu::Queue,
) -> Self { ) -> Self {
@ -133,7 +133,7 @@ impl framework::Example for Example {
multisample: wgpu::MultisampleState::default(), multisample: wgpu::MultisampleState::default(),
}); });
let pipeline_lines = if adapter let pipeline_lines = if device
.features() .features()
.contains(wgpu::Features::NON_FILL_POLYGON_MODE) .contains(wgpu::Features::NON_FILL_POLYGON_MODE)
{ {
@ -312,3 +312,19 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("conservative-raster"); framework::run::<Example>("conservative-raster");
} }
#[test]
fn conservative_raster() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/conservative-raster/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
0,
0,
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -379,3 +379,32 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("cube"); framework::run::<Example>("cube");
} }
#[test]
fn cube() {
framework::test::<Example>(
concat!(env!("CARGO_MANIFEST_DIR"), "/examples/cube/screenshot.png"),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
1,
3,
);
}
#[test]
fn cube_lines() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/cube/screenshot-lines.png"
),
1024,
768,
wgpu::Features::NON_FILL_POLYGON_MODE,
framework::test_common::TestParameters::default(),
1,
3,
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,13 +1,13 @@
use std::future::Future;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{future::Future};
use winit::{ use winit::{
event::{self, WindowEvent}, event::{self, WindowEvent},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
}; };
#[path = "../tests/common/mod.rs"] #[path = "../tests/common/mod.rs"]
mod test_common; pub mod test_common;
#[rustfmt::skip] #[rustfmt::skip]
#[allow(unused)] #[allow(unused)]
@ -365,20 +365,28 @@ pub fn run<E: Example>(title: &str) {
} }
#[cfg(test)] #[cfg(test)]
pub fn test<E: Example>(image_path: &str, width: u32, height: u32, tollerance: u8, max_outliers: usize) { #[allow(dead_code)]
pub fn test<E: Example>(
image_path: &str,
width: u32,
height: u32,
optional_features: wgpu::Features,
base_test_parameters: test_common::TestParameters,
tollerance: u8,
max_outliers: usize,
) {
use std::num::NonZeroU32; use std::num::NonZeroU32;
assert_eq!(width % 64, 0, "width needs to be aligned 64"); assert_eq!(width % 64, 0, "width needs to be aligned 64");
let _optional = E::optional_features(); let features = E::required_features() | optional_features;
let features = E::required_features();
let mut limits = E::required_limits(); let mut limits = E::required_limits();
if limits == wgpu::Limits::default() { if limits == wgpu::Limits::default() {
limits = test_common::lowest_reasonable_limits(); limits = test_common::lowest_reasonable_limits();
} }
test_common::initialize_test( test_common::initialize_test(
test_common::TestParameters::default() base_test_parameters
.features(features) .features(features)
.limits(limits), .limits(limits),
|ctx| { |ctx| {

View File

@ -484,7 +484,9 @@ fn mipmap() {
), ),
1024, 1024,
768, 768,
10, // Mipmap sampling is highly variant between impls. wgpu::Features::default(),
10, framework::test_common::TestParameters::default(),
15, // Mipmap sampling is highly variant between impls. This is currently bounded by the M1
40,
); );
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

After

Width:  |  Height:  |  Size: 542 KiB

View File

@ -282,3 +282,19 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("msaa-line"); framework::run::<Example>("msaa-line");
} }
#[test]
fn msaa_line() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/msaa-line/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
0,
1 << 15, // MSAA is comically different between vendors, 32k is a decent limit
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -821,3 +821,19 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("shadow"); framework::run::<Example>("shadow");
} }
#[test]
fn shadow() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/shadow/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
1,
1,
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -459,3 +459,67 @@ impl framework::Example for Skybox {
fn main() { fn main() {
framework::run::<Skybox>("skybox"); framework::run::<Skybox>("skybox");
} }
#[test]
fn skybox() {
framework::test::<Skybox>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/skybox/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
2,
3,
);
}
#[test]
fn skybox_bc1() {
framework::test::<Skybox>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/skybox/screenshot-bc1.png"
),
1024,
768,
wgpu::Features::TEXTURE_COMPRESSION_BC,
framework::test_common::TestParameters::default(),
4,
0,
);
}
#[test]
fn skybox_etc2() {
framework::test::<Skybox>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/skybox/screenshot-etc2.png"
),
1024,
768,
wgpu::Features::TEXTURE_COMPRESSION_ETC2,
framework::test_common::TestParameters::default(),
1, // TODO
1, // TODO
);
}
#[test]
fn skybox_astc() {
framework::test::<Skybox>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/skybox/screenshot-astc.png"
),
1024,
768,
wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR,
framework::test_common::TestParameters::default(),
1, // TODO
1, // TODO
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 455 KiB

View File

@ -73,6 +73,6 @@ fn fs_entity(in: EntityOutput) -> [[location(0)]] vec4<f32> {
let normal = normalize(in.normal); let normal = normalize(in.normal);
let reflected = incident - 2.0 * dot(normal, incident) * normal; let reflected = incident - 2.0 * dot(normal, incident) * normal;
let reflected_color = textureSample(r_texture, r_sampler, reflected); let reflected_color = textureSample(r_texture, r_sampler, reflected).rgb;
return vec4<f32>(0.1, 0.1, 0.1, 0.1) + 0.5 * reflected_color; return vec4<f32>(vec3<f32>(0.1) + 0.5 * reflected_color, 1.0);
} }

View File

@ -100,7 +100,7 @@ impl framework::Example for Example {
f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => { f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => {
wgpu::include_spirv_raw!("non-uniform.frag.spv") wgpu::include_spirv_raw!("non-uniform.frag.spv")
} }
f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => { f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING | wgpu::Features::PUSH_CONSTANTS) => {
uniform_workaround = true; uniform_workaround = true;
wgpu::include_spirv_raw!("uniform.frag.spv") wgpu::include_spirv_raw!("uniform.frag.spv")
} }
@ -322,3 +322,73 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("texture-arrays"); framework::run::<Example>("texture-arrays");
} }
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
#[test]
fn texture_arrays_constant() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/texture-arrays/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default().failure(),
0,
0,
);
}
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
#[test]
fn texture_arrays_uniform() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/texture-arrays/screenshot.png"
),
1024,
768,
wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING | wgpu::Features::PUSH_CONSTANTS,
framework::test_common::TestParameters::default().failure(),
0,
0,
);
}
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
#[test]
fn texture_arrays_non_uniform() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/texture-arrays/screenshot.png"
),
1024,
768,
wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
framework::test_common::TestParameters::default().failure(),
0,
0,
);
}
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
#[test]
fn texture_arrays_unsized_non_uniform() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/texture-arrays/screenshot.png"
),
1024,
768,
wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING | wgpu::Features::UNSIZED_BINDING_ARRAY,
framework::test_common::TestParameters::default().failure(),
0,
0,
);
}

View File

@ -5,6 +5,7 @@ mod point_gen;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use cgmath::Point3; use cgmath::Point3;
use rand::SeedableRng;
use std::{borrow::Cow, iter, mem}; use std::{borrow::Cow, iter, mem};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
@ -279,7 +280,7 @@ impl framework::Example for Example {
let terrain_noise = noise::OpenSimplex::new(); let terrain_noise = noise::OpenSimplex::new();
// Random colouration // Random colouration
let mut terrain_random = rand::thread_rng(); let mut terrain_random = rand::rngs::StdRng::seed_from_u64(42);
// Generate terrain. The closure determines what each hexagon will look like. // Generate terrain. The closure determines what each hexagon will look like.
let terrain = let terrain =
@ -788,3 +789,19 @@ impl framework::Example for Example {
fn main() { fn main() {
framework::run::<Example>("water"); framework::run::<Example>("water");
} }
#[test]
fn shadow() {
framework::test::<Example>(
concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/water/screenshot.png"
),
1024,
768,
wgpu::Features::default(),
framework::test_common::TestParameters::default(),
2,
2,
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -100,7 +100,7 @@ pub fn compare_image_output(
.max() .max()
.unwrap(); .unwrap();
if outliers >= max_outliers { if outliers > max_outliers {
// Because the deta is mismatched, lets output the difference to a file. // Because the deta is mismatched, lets output the difference to a file.
let old_path = Path::new(&path); let old_path = Path::new(&path);
let difference_path = Path::new(&path).with_file_name( let difference_path = Path::new(&path).with_file_name(

View File

@ -46,18 +46,18 @@ pub fn lowest_reasonable_limits() -> Limits {
max_texture_dimension_2d: 1024, max_texture_dimension_2d: 1024,
max_texture_dimension_3d: 32, max_texture_dimension_3d: 32,
max_texture_array_layers: 32, max_texture_array_layers: 32,
max_bind_groups: 1, max_bind_groups: 2,
max_dynamic_uniform_buffers_per_pipeline_layout: 1, max_dynamic_uniform_buffers_per_pipeline_layout: 2,
max_dynamic_storage_buffers_per_pipeline_layout: 1, max_dynamic_storage_buffers_per_pipeline_layout: 2,
max_sampled_textures_per_shader_stage: 1, max_sampled_textures_per_shader_stage:2,
max_samplers_per_shader_stage: 1, max_samplers_per_shader_stage: 2,
max_storage_buffers_per_shader_stage: 1, max_storage_buffers_per_shader_stage: 2,
max_storage_textures_per_shader_stage: 1, max_storage_textures_per_shader_stage: 2,
max_uniform_buffers_per_shader_stage: 1, max_uniform_buffers_per_shader_stage: 2,
max_uniform_buffer_binding_size: 256, max_uniform_buffer_binding_size: 256,
max_storage_buffer_binding_size: 256, max_storage_buffer_binding_size: 1 << 16,
max_vertex_buffers: 1, max_vertex_buffers: 4,
max_vertex_attributes: 2, max_vertex_attributes: 4,
max_vertex_buffer_array_stride: 32, max_vertex_buffer_array_stride: 32,
max_push_constant_size: 0, max_push_constant_size: 0,
} }