use crate::renderer::gpu::compute;
const SHADER_SRC: &str = include_str!("../shaders/self_determinism.wgsl");
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct Params {
num_pixels: u32,
num_samples: u32,
_pad0: u32,
_pad1: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct DeterminismMismatch {
pub pixel: u32,
pub run1: f32,
pub run2: f32,
}
#[derive(Debug, Clone)]
pub struct DeterminismCheckResult {
pub num_pixels: u32,
pub num_samples: u32,
pub mismatches: Vec<DeterminismMismatch>,
}
impl DeterminismCheckResult {
#[must_use]
pub const fn passed(&self) -> bool {
self.mismatches.is_empty()
}
}
fn run_once(ctx: &crate::renderer::gpu::GpuContext, num_pixels: u32, num_samples: u32) -> Vec<f32> {
let params = Params {
num_pixels,
num_samples,
_pad0: 0,
_pad1: 0,
};
let params_buf = compute::upload(
&ctx.device,
"self_determinism params",
std::slice::from_ref(¶ms),
wgpu::BufferUsages::UNIFORM,
);
let out_buf = compute::zeroed_buffer::<f32>(
&ctx.device,
"self_determinism output",
num_pixels as usize,
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC,
);
let pipeline =
compute::create_compute_pipeline(&ctx.device, "self_determinism", SHADER_SRC, "main");
let bind_group = compute::bind_buffers(
&ctx.device,
"self_determinism bind group",
&pipeline,
&[(0, ¶ms_buf), (1, &out_buf)],
);
let workgroups = num_pixels.div_ceil(64);
compute::dispatch_and_wait(
&ctx.device,
&ctx.queue,
&pipeline,
&bind_group,
(workgroups, 1, 1),
);
compute::readback(&ctx.device, &ctx.queue, &out_buf, num_pixels as usize)
}
#[must_use]
pub fn run(
ctx: &crate::renderer::gpu::GpuContext,
num_pixels: u32,
num_samples: u32,
) -> DeterminismCheckResult {
let run1 = run_once(ctx, num_pixels, num_samples);
let run2 = run_once(ctx, num_pixels, num_samples);
let mismatches = run1
.iter()
.zip(run2.iter())
.enumerate()
.filter_map(|(pixel, (&a, &b))| {
(a.to_bits() != b.to_bits()).then_some(DeterminismMismatch {
pixel: u32::try_from(pixel).expect("the pixel count is a u32"),
run1: a,
run2: b,
})
})
.take(64)
.collect();
DeterminismCheckResult {
num_pixels,
num_samples,
mismatches,
}
}