use glam::Vec3;
use crate::renderer::{
env_map_gpu::HdrEnvGpuData,
gpu::{
compute,
transport_check::{SHADER_SRC, UlpAccumulator, UlpCheckResult},
},
};
use super::synthetic_test_map;
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Dist2dPdfCase {
dir: [f32; 3],
_pad0: f32,
}
const _: () = assert!(size_of::<Dist2dPdfCase>() == 16);
const DIST2D_PDF_ULP_BUDGET: u32 = 32;
const DIST2D_PDF_ABS_FLOOR: f32 = 1e-5;
fn build_dist2d_pdf_cases() -> Vec<Dist2dPdfCase> {
let mut cases = Vec::new();
let hand_picked = [
Vec3::Y,
Vec3::NEG_Y,
Vec3::new(0.007, 0.9999, 0.01).normalize(),
Vec3::new(0.007, -0.9999, 0.01).normalize(),
Vec3::new(0.3, 0.4, 0.5).normalize(),
Vec3::new(-1.0, 2.0, -0.5).normalize(),
Vec3::new(0.9, -0.1, -0.2).normalize(),
Vec3::new(-0.2, -0.7, 0.6).normalize(),
];
for &d in &hand_picked {
cases.push(Dist2dPdfCase {
dir: d.to_array(),
_pad0: 0.0,
});
}
for theta_i in 0..10 {
let theta = (theta_i as f32 + 0.37) * std::f32::consts::PI / 10.0;
let (sin_t, cos_t) = theta.sin_cos();
for phi_i in 0..16 {
let phi = (phi_i as f32 + 0.29) * 2.0 * std::f32::consts::PI / 16.0;
let (sin_p, cos_p) = phi.sin_cos();
let d = Vec3::new(sin_t * sin_p, cos_t, sin_t * cos_p);
cases.push(Dist2dPdfCase {
dir: d.to_array(),
_pad0: 0.0,
});
}
}
cases
}
#[must_use]
pub fn run_dist2d_pdf(ctx: &crate::renderer::gpu::GpuContext) -> UlpCheckResult<Dist2dPdfCase> {
let map = synthetic_test_map();
let gpu_data = HdrEnvGpuData::upload(&ctx.device, &map);
let cases = build_dist2d_pdf_cases();
let total = cases.len();
let in_buf = compute::upload(
&ctx.device,
"dist2d pdf in",
&cases,
wgpu::BufferUsages::STORAGE,
);
let out_buf = compute::zeroed_buffer::<f32>(
&ctx.device,
"dist2d pdf out",
total,
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC,
);
let pipeline = compute::create_compute_pipeline(
&ctx.device,
"dist2d_pdf_main",
SHADER_SRC,
"dist2d_pdf_main",
);
let bind_group = compute::bind_buffers(
&ctx.device,
"dist2d pdf bind group",
&pipeline,
&[
(62, &gpu_data.dist_func),
(64, &gpu_data.dist_dims),
(71, &in_buf),
(72, &out_buf),
],
);
let workgroups = u32::try_from(total)
.expect("the case count fits u32")
.div_ceil(64);
compute::dispatch_and_wait(
&ctx.device,
&ctx.queue,
&pipeline,
&bind_group,
(workgroups, 1, 1),
);
let gpu_out: Vec<f32> = compute::readback(&ctx.device, &ctx.queue, &out_buf, total);
let mut acc = UlpAccumulator::new("dist2d_pdf", DIST2D_PDF_ULP_BUDGET, DIST2D_PDF_ABS_FLOOR);
for (idx, case) in cases.iter().enumerate() {
let cpu = map.pdf(Vec3::from_array(case.dir));
acc.record(case, "pdf", cpu, gpu_out[idx]);
}
acc.finish()
}