use std::time::Instant;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct CameraKeyframe {
pub time: f32,
pub position: [f32; 3],
pub yaw: f32,
pub pitch: f32,
}
#[allow(dead_code)]
pub fn default_camera_path() -> Vec<CameraKeyframe> {
let mut path = Vec::with_capacity(120);
let duration = 10.0_f32; let frames = 120;
let radius = 18.0_f32;
let height = 5.0_f32;
for i in 0..frames {
let t = i as f32 / frames as f32 * duration;
let angle = t / duration * std::f32::consts::TAU;
path.push(CameraKeyframe {
time: t,
position: [angle.cos() * radius, height, angle.sin() * radius],
yaw: -angle - std::f32::consts::FRAC_PI_2,
pitch: -0.14,
});
}
path
}
pub const CHECKPOINTS: &[u32] = &[
64, 128, 256, 512, 1024, 2048, 4096, 8192,
16384, 32768, 65536, 131072, 262144, 524288, 1048576,
];
pub const FRAMES_PER_CHECKPOINT: u32 = 120;
pub const CUBES_PER_SPAWN: u32 = 16;
pub const PLATFORM_SIZE: f32 = 20.0;
pub const PLATFORM_HEIGHT: f32 = 0.5;
pub const PORTAL_HEIGHT: f32 = 15.0;
pub fn spawn_radius(count: u32) -> f32 {
2.0 + (count as f32).sqrt() * 0.05
}
#[derive(Debug, Clone)]
pub struct CheckpointResult {
pub dreamlet_count: u32,
pub avg_fps: f32,
pub avg_frame_ms: f32,
pub p50_ms: f32,
pub p95_ms: f32,
pub p99_ms: f32,
pub min_ms: f32,
pub max_ms: f32,
pub p1_low_ms: f32,
#[allow(dead_code)]
pub p01_low_ms: f32,
#[allow(dead_code)]
pub pipeline: String,
pub passed: bool,
pub vram_dreamlets_bytes: u64,
pub vram_total_bytes: u64,
pub bytes_per_dreamlet: u32,
pub rt_gi_enabled: bool,
pub rt_shadows_enabled: bool,
}
#[derive(Debug)]
pub struct SpawnTestResults {
pub pipeline: String,
pub adapter: String,
pub checkpoints: Vec<CheckpointResult>,
pub max_sustained: u32,
pub detected_max_buffer_bytes: u64,
pub vram_budget_bytes: u64,
pub vram_fixed_overhead_bytes: u64,
pub ray_tracing: bool,
}
fn fmt_bytes(b: u64) -> String {
if b >= 1024 * 1024 * 1024 {
format!("{:.2} GB", b as f64 / (1024.0 * 1024.0 * 1024.0))
} else if b >= 1024 * 1024 {
format!("{:.1} MB", b as f64 / (1024.0 * 1024.0))
} else if b >= 1024 {
format!("{:.1} KB", b as f64 / 1024.0)
} else {
format!("{} B", b)
}
}
fn fmt_count(n: u32) -> String {
if n >= 1_000_000 {
format!("{}M", n / 1_000_000)
} else if n >= 1_000 {
format!("{}K", n / 1_000)
} else {
format!("{}", n)
}
}
fn fmt_latency(ms: f32) -> String {
if ms < 0.01 {
format!("{:.0} us", ms * 1000.0)
} else if ms < 1.0 {
format!("{:.2} ms", ms)
} else {
format!("{:.1} ms", ms)
}
}
fn fmt_vram_ratio(bytes: u64, max_gb: f64) -> String {
format!("{} / {:.0} GB", fmt_bytes(bytes), max_gb)
}
impl SpawnTestResults {
pub fn print(&self) {
println!();
println!("=== Dreamlet Spawn Test Results ===");
println!("Pipeline: {}", self.pipeline);
println!("Adapter: {}", self.adapter);
println!("Ray Tracing: {}", if self.ray_tracing { "On" } else { "Off" });
println!("VRAM budget: {}", fmt_bytes(self.vram_budget_bytes));
println!("Max buffer: {}", fmt_bytes(self.detected_max_buffer_bytes));
println!("Fixed overhead: {}", fmt_bytes(self.vram_fixed_overhead_bytes));
println!();
println!("{:>10} {:>8} {:>10} {:>8} {:>8} {:>8} {:>12} {:>12} {:>6}",
"Dreamlets", "FPS", "Frame(ms)", "p50", "p95", "1%low", "VRAM(dream)", "VRAM(total)", "Pass");
println!("{}", "-".repeat(98));
for cp in &self.checkpoints {
println!("{:>10} {:>8.0} {:>10.2} {:>8.2} {:>8.2} {:>8.2} {:>12} {:>12} {:>6}",
cp.dreamlet_count, cp.avg_fps, cp.avg_frame_ms,
cp.p50_ms, cp.p95_ms, cp.p1_low_ms,
fmt_bytes(cp.vram_dreamlets_bytes), fmt_bytes(cp.vram_total_bytes),
if cp.passed { "OK" } else { "FAIL" });
}
println!();
println!("Max sustained (>30 FPS): {} dreamlets", self.max_sustained);
let storage_bytes = if self.checkpoints.first().map_or(164, |c| c.bytes_per_dreamlet) == 84 { 64 } else { 144 };
let total_bytes = storage_bytes + 20;
println!("Per-unit cost: {} bytes ({}B storage + 20B indirect)", total_bytes, storage_bytes);
println!("==================================");
println!();
self.print_markdown();
}
pub fn print_markdown(&self) {
let max_vram_gb = self.vram_budget_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
let rt_label = if self.ray_tracing { "On" } else { "Off" };
println!("### {} (Ray Tracing: {})", self.pipeline, rt_label);
println!();
println!("| Checkpoint | FPS | Latency | VRAM |");
println!("|------------|-----|---------|------|");
for cp in &self.checkpoints {
let count_label = fmt_count(cp.dreamlet_count);
let latency = fmt_latency(cp.p50_ms);
let vram = fmt_vram_ratio(cp.vram_total_bytes, max_vram_gb);
let pass = if cp.passed { "" } else { " FAIL" };
println!("| {} | {:.0}{} | {} | {} |",
count_label, cp.avg_fps, pass, latency, vram);
}
println!();
}
pub fn export_csv(&self, path: &str) -> Result<(), std::io::Error> {
use std::io::Write;
let mut file = std::fs::File::create(path)?;
writeln!(file, "pipeline,adapter,ray_tracing,vram_budget_gb,max_buffer_gb,dreamlet_count,avg_fps,avg_frame_ms,p50_ms,p95_ms,p99_ms,min_ms,max_ms,vram_dreamlets_mb,vram_total_mb,bytes_per_dreamlet,passed,rt_gi,rt_shadows")?;
let budget_gb = self.vram_budget_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
let max_buf_gb = self.detected_max_buffer_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
for cp in &self.checkpoints {
writeln!(file, "{},{},{},{:.2},{:.2},{},{:.1},{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},{:.1},{:.1},{},{},{},{}",
self.pipeline, self.adapter, self.ray_tracing, budget_gb, max_buf_gb,
cp.dreamlet_count,
cp.avg_fps, cp.avg_frame_ms,
cp.p50_ms, cp.p95_ms, cp.p99_ms, cp.min_ms, cp.max_ms,
cp.vram_dreamlets_bytes as f64 / (1024.0 * 1024.0),
cp.vram_total_bytes as f64 / (1024.0 * 1024.0),
cp.bytes_per_dreamlet,
cp.passed,
cp.rt_gi_enabled,
cp.rt_shadows_enabled)?;
}
Ok(())
}
}
pub struct SpawnTestState {
pub target_count: u32,
pub current_count: u32,
pub checkpoint_idx: usize,
pub frames_at_checkpoint: u32,
pub frame_times: Vec<f32>,
pub results: SpawnTestResults,
pub max_dreamlets: u32,
pub complete: bool,
pub measuring: bool,
pub bytes_per_unit: u32,
frame_timer: Instant,
}
impl SpawnTestState {
pub fn new(
pipeline_name: &str,
adapter_name: &str,
max_dreamlets: u32,
detected_max_buffer: u64,
vram_budget: u64,
vram_fixed_overhead: u64,
ray_tracing: bool,
) -> Self {
Self::with_unit_size(pipeline_name, adapter_name, max_dreamlets,
detected_max_buffer, vram_budget, vram_fixed_overhead, 164, ray_tracing)
}
pub fn with_unit_size(
pipeline_name: &str,
adapter_name: &str,
max_dreamlets: u32,
detected_max_buffer: u64,
vram_budget: u64,
vram_fixed_overhead: u64,
bytes_per_unit: u32,
ray_tracing: bool,
) -> Self {
let max = max_dreamlets.min(*CHECKPOINTS.last().unwrap_or(&1048576));
Self {
target_count: CHECKPOINTS[0],
current_count: 0,
checkpoint_idx: 0,
frames_at_checkpoint: 0,
frame_times: Vec::with_capacity(FRAMES_PER_CHECKPOINT as usize),
results: SpawnTestResults {
pipeline: pipeline_name.to_string(),
adapter: adapter_name.to_string(),
checkpoints: Vec::new(),
max_sustained: 0,
detected_max_buffer_bytes: detected_max_buffer,
vram_budget_bytes: vram_budget,
vram_fixed_overhead_bytes: vram_fixed_overhead,
ray_tracing,
},
max_dreamlets: max,
complete: false,
measuring: false,
bytes_per_unit,
frame_timer: Instant::now(),
}
}
pub fn tick(&mut self) -> u32 {
if self.complete { return 0; }
let dt = self.frame_timer.elapsed().as_secs_f32();
self.frame_timer = Instant::now();
if self.current_count < self.target_count {
let to_spawn = CUBES_PER_SPAWN.min(self.target_count - self.current_count);
self.current_count += to_spawn;
if self.current_count >= self.target_count {
self.measuring = true;
self.frames_at_checkpoint = 0;
self.frame_times.clear();
log::info!("Checkpoint {}: {} dreamlets — measuring {} frames",
self.checkpoint_idx, self.target_count, FRAMES_PER_CHECKPOINT);
}
return to_spawn;
}
if self.measuring {
let ms = dt * 1000.0;
self.frame_times.push(ms);
self.frames_at_checkpoint += 1;
if self.frames_at_checkpoint >= FRAMES_PER_CHECKPOINT {
let result = self.compute_checkpoint();
let passed = result.passed;
log::info!(" Result: {:.0} FPS, p95={:.2}ms, {}",
result.avg_fps, result.p95_ms, if passed { "PASS" } else { "FAIL" });
self.results.checkpoints.push(result);
if passed {
self.results.max_sustained = self.target_count;
}
self.checkpoint_idx += 1;
self.measuring = false;
if self.checkpoint_idx >= CHECKPOINTS.len()
|| CHECKPOINTS[self.checkpoint_idx] > self.max_dreamlets
|| !passed
{
self.complete = true;
return 0;
}
self.target_count = CHECKPOINTS[self.checkpoint_idx];
}
}
0
}
fn compute_checkpoint(&self) -> CheckpointResult {
let mut sorted = self.frame_times.clone();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let avg_ms = if sorted.is_empty() { 0.0 }
else { sorted.iter().sum::<f32>() / sorted.len() as f32 };
let avg_fps = if avg_ms > 0.0 { 1000.0 / avg_ms } else { 0.0 };
let percentile = |p: f32| -> f32 {
if sorted.is_empty() { return 0.0; }
if sorted.len() == 1 { return sorted[0]; }
let rank = (p / 100.0) * (sorted.len() - 1) as f32;
let lower = rank.floor() as usize;
let upper = rank.ceil().min((sorted.len() - 1) as f32) as usize;
let frac = rank - lower as f32;
sorted[lower] * (1.0 - frac) + sorted[upper] * frac
};
let min = sorted.first().copied().unwrap_or(0.0);
let max = sorted.last().copied().unwrap_or(0.0);
let bytes_per = self.bytes_per_unit;
let dreamlet_vram = self.target_count as u64 * bytes_per as u64;
let total_vram = dreamlet_vram + self.results.vram_fixed_overhead_bytes;
CheckpointResult {
dreamlet_count: self.target_count,
avg_fps,
avg_frame_ms: avg_ms,
p50_ms: percentile(50.0),
p95_ms: percentile(95.0),
p99_ms: percentile(99.0),
min_ms: min,
max_ms: max,
p1_low_ms: percentile(99.0),
p01_low_ms: percentile(99.9),
pipeline: self.results.pipeline.clone(),
passed: avg_fps >= 30.0,
vram_dreamlets_bytes: dreamlet_vram,
vram_total_bytes: total_vram,
bytes_per_dreamlet: bytes_per,
rt_gi_enabled: self.results.ray_tracing,
rt_shadows_enabled: self.results.ray_tracing,
}
}
#[allow(dead_code)]
pub fn current_checkpoint_label(&self) -> String {
if self.complete {
"Complete".to_string()
} else if self.measuring {
format!("Measuring {} ({}/{})",
self.target_count, self.frames_at_checkpoint, FRAMES_PER_CHECKPOINT)
} else {
format!("Spawning → {}", self.target_count)
}
}
}
pub fn generate_dreamlet_batch(
old_count: u32,
new_count: u32,
) -> Vec<dreamwell_gpu::dreamlet_catalog::GpuDreamlet> {
use dreamwell_gpu::dreamlet_catalog::*;
use dreamwell_gpu::gpu_driven::MergedMeshBuffer;
use dreamwell_engine::game_object::PrimitiveKind;
let cube_mesh_id = MergedMeshBuffer::mesh_id_lod0(PrimitiveKind::Cube);
let total = new_count;
let mut batch = Vec::with_capacity((new_count - old_count) as usize);
for i in old_count..new_count {
let golden = 0.618033988749895_f32;
let angle = (i as f32) * golden * std::f32::consts::TAU;
let r = spawn_radius(total) * ((i as f32) / total.max(1) as f32).sqrt();
let x = angle.cos() * r;
let z = angle.sin() * r;
let y = PORTAL_HEIGHT + (i as f32) * 0.15;
let hue = (i as f32 * golden) % 1.0;
let (cr, cg, cb) = hsv_rgb(hue, 0.6, 0.9);
let cube_scale = 0.3 + (i as f32 * 0.137).sin().abs() * 0.2;
batch.push(GpuDreamlet {
position: [x, y, z],
scale: cube_scale,
velocity: [0.0, -2.0 - (i as f32 * 0.03).sin() * 3.0, 0.0],
angular_velocity: (i as f32 * 0.7).sin() * 2.0,
rotation: [0.0, 0.0, 0.0, 1.0],
base_color: [cr, cg, cb, 1.0],
roughness: 0.3 + (i as f32 * 0.31).sin().abs() * 0.5,
metallic: if i % 7 == 0 { 0.8 } else { 0.1 },
mass: 1.0,
restitution: 0.4,
state: DREAMLET_STATE_PARTICLE,
mesh_id: cube_mesh_id,
parent_id: 0,
flags: DREAMLET_FLAG_ACTIVE | DREAMLET_FLAG_PHYSICS,
age: 0.0,
lifetime: 30.0,
_pad_target: [0.0; 2],
target_position: [x, PLATFORM_HEIGHT + cube_scale, z],
deconstruct_level: 0,
bounding_radius: cube_scale,
skeleton_index: 0,
_pad_struct: [0.0; 2],
});
}
batch
}
pub fn generate_spawn_dreamlets(
count: u32,
) -> Vec<dreamwell_gpu::dreamlet_catalog::GpuDreamlet> {
use dreamwell_gpu::dreamlet_catalog::*;
use dreamwell_gpu::gpu_driven::MergedMeshBuffer;
use dreamwell_engine::game_object::PrimitiveKind;
let cube_mesh_id = MergedMeshBuffer::mesh_id_lod0(PrimitiveKind::Cube);
let plane_mesh_id = MergedMeshBuffer::mesh_id_lod0(PrimitiveKind::Plane);
let mut dreamlets = Vec::with_capacity(count as usize + 1);
dreamlets.push(GpuDreamlet {
position: [0.0, 0.0, 0.0],
scale: PLATFORM_SIZE,
velocity: [0.0; 3],
angular_velocity: 0.0,
rotation: [0.0, 0.0, 0.0, 1.0],
base_color: [0.3, 0.3, 0.35, 1.0],
roughness: 0.8,
metallic: 0.1,
mass: 0.0,
restitution: 0.3,
state: DREAMLET_STATE_STATIC,
mesh_id: plane_mesh_id,
parent_id: 0,
flags: DREAMLET_FLAG_ACTIVE,
age: 0.0,
lifetime: 0.0,
_pad_target: [0.0; 2],
target_position: [0.0; 3],
deconstruct_level: 0,
bounding_radius: PLATFORM_SIZE,
skeleton_index: 0,
_pad_struct: [0.0; 2],
});
let radius = spawn_radius(count);
for i in 0..count {
let golden = 0.618033988749895_f32;
let angle = (i as f32) * golden * std::f32::consts::TAU;
let r = radius * ((i as f32) / count.max(1) as f32).sqrt();
let x = angle.cos() * r;
let z = angle.sin() * r;
let y = PORTAL_HEIGHT + (i as f32) * 0.15;
let hue = (i as f32 * golden) % 1.0;
let (cr, cg, cb) = hsv_rgb(hue, 0.6, 0.9);
let cube_scale = 0.3 + (i as f32 * 0.137).sin().abs() * 0.2;
let is_emissive = i % 64 == 0;
let color = if is_emissive { [cr * 3.0, cg * 3.0, cb * 3.0, 1.0] } else { [cr, cg, cb, 1.0] };
dreamlets.push(GpuDreamlet {
position: [x, y, z],
scale: cube_scale,
velocity: [0.0, -2.0 - (i as f32 * 0.03).sin() * 3.0, 0.0],
angular_velocity: (i as f32 * 0.7).sin() * 2.0,
rotation: [0.0, 0.0, 0.0, 1.0],
base_color: color,
roughness: 0.3 + (i as f32 * 0.31).sin().abs() * 0.5,
metallic: if i % 7 == 0 { 0.8 } else { 0.1 },
mass: 1.0,
restitution: 0.4,
state: DREAMLET_STATE_PARTICLE, mesh_id: cube_mesh_id,
parent_id: 0,
flags: DREAMLET_FLAG_ACTIVE | DREAMLET_FLAG_PHYSICS
| if is_emissive { dreamwell_gpu::dreamlet_catalog::DREAMLET_FLAG_EMISSIVE } else { 0 },
age: 0.0,
lifetime: 30.0, _pad_target: [0.0; 2],
target_position: [x, PLATFORM_HEIGHT + cube_scale, z], deconstruct_level: 0,
bounding_radius: cube_scale,
skeleton_index: 0,
_pad_struct: [0.0; 2],
});
}
dreamlets
}
pub fn generate_micro_batch(
old_count: u32,
new_count: u32,
) -> Vec<dreamwell_gpu::micro_dreamlet::MicroDreamlet> {
use dreamwell_gpu::micro_dreamlet::MicroDreamlet;
use dreamwell_gpu::gpu_driven::MergedMeshBuffer;
use dreamwell_engine::game_object::PrimitiveKind;
let cube_mesh_id = MergedMeshBuffer::mesh_id_lod0(PrimitiveKind::Cube);
let total = new_count;
let mut batch = Vec::with_capacity((new_count - old_count) as usize);
for i in old_count..new_count {
let golden = 0.618033988749895_f32;
let angle = (i as f32) * golden * std::f32::consts::TAU;
let r = spawn_radius(total) * ((i as f32) / total.max(1) as f32).sqrt();
let x = angle.cos() * r;
let z = angle.sin() * r;
let y = PORTAL_HEIGHT + (i as f32) * 0.08; let hue = (i as f32 * golden) % 1.0;
let (cr, cg, cb) = hsv_rgb(hue, 0.6, 0.9);
let cube_scale = 0.15 + (i as f32 * 0.137).sin().abs() * 0.1;
batch.push(MicroDreamlet {
position: [x, y, z],
scale: cube_scale,
rotation: [0.0, 0.0, 0.0, 1.0],
base_color: [cr, cg, cb, 1.0],
roughness: 0.4,
metallic: if i % 7 == 0 { 0.8 } else { 0.1 },
mesh_id: cube_mesh_id,
bounding_radius: cube_scale,
});
}
batch
}
#[allow(dead_code)]
pub fn extract_positions(dreamlets: &[dreamwell_gpu::micro_dreamlet::MicroDreamlet]) -> (Vec<[f32; 3]>, Vec<f32>) {
let positions: Vec<[f32; 3]> = dreamlets.iter().map(|d| d.position).collect();
let radii: Vec<f32> = dreamlets.iter().map(|d| d.bounding_radius).collect();
(positions, radii)
}
fn hsv_rgb(h: f32, s: f32, v: f32) -> (f32, f32, f32) {
let c = v * s;
let h2 = h * 6.0;
let x = c * (1.0 - ((h2 % 2.0) - 1.0).abs());
let m = v - c;
let (r, g, b) = if h2 < 1.0 { (c, x, 0.0) }
else if h2 < 2.0 { (x, c, 0.0) }
else if h2 < 3.0 { (0.0, c, x) }
else if h2 < 4.0 { (0.0, x, c) }
else if h2 < 5.0 { (x, 0.0, c) }
else { (c, 0.0, x) };
(r + m, g + m, b + m)
}
#[cfg(test)]
mod tests {
use super::*;
use dreamwell_gpu::dreamlet_catalog::DREAMLET_STATE_STATIC;
#[test]
fn checkpoints_are_powers_of_two() {
for &cp in CHECKPOINTS {
assert!(cp.is_power_of_two(), "{cp} is not a power of 2");
}
}
#[test]
fn checkpoints_monotonically_increasing() {
for i in 1..CHECKPOINTS.len() {
assert!(CHECKPOINTS[i] > CHECKPOINTS[i - 1]);
}
}
#[test]
fn checkpoint_ends_at_1m() {
assert_eq!(*CHECKPOINTS.last().unwrap(), 1048576);
}
#[test]
fn spawn_radius_grows() {
assert!(spawn_radius(1000) > spawn_radius(100));
assert!(spawn_radius(100000) > spawn_radius(1000));
}
#[test]
fn generate_spawn_includes_platform() {
let dreamlets = generate_spawn_dreamlets(10);
assert_eq!(dreamlets.len(), 11); assert_eq!(dreamlets[0].state, DREAMLET_STATE_STATIC); }
#[test]
fn spawn_test_state_machine() {
let mut state = SpawnTestState::new("test", "test_gpu", 256, 128 * 1024 * 1024, 8 * 1024 * 1024 * 1024, 32 * 1024 * 1024, false);
assert!(!state.complete);
assert_eq!(state.target_count, 64);
assert_eq!(state.bytes_per_unit, 164);
for _ in 0..100 {
state.tick();
}
assert!(state.current_count > 0);
}
#[test]
fn micro_test_state_machine() {
let state = SpawnTestState::with_unit_size(
"micro", "test_gpu", 256, 128 * 1024 * 1024,
8 * 1024 * 1024 * 1024, 32 * 1024 * 1024, 84, false,
);
assert!(!state.complete);
assert_eq!(state.bytes_per_unit, 84); }
#[test]
fn generate_micro_batch_produces_correct_count() {
let batch = generate_micro_batch(0, 100);
assert_eq!(batch.len(), 100);
assert_eq!(std::mem::size_of_val(&batch[0]), 64);
}
}