use std::path::Path;
use std::sync::Arc;
use valo::{Color, Context, DisplayListBuilder, Matrix, Offscreen, Paint, Rect};
fn goldens_dir() -> &'static Path {
Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/goldens"))
}
fn board() -> Arc<valo::DisplayList> {
let mut b = DisplayListBuilder::new();
b.draw_rect(
Rect::new(0.0, 0.0, 220.0, 160.0),
&Paint::from_color(Color::rgb(0.13, 0.15, 0.2)),
);
for i in 0..20 {
let x = 10.0 + (i % 5) as f32 * 42.0;
let y = 12.0 + (i / 5) as f32 * 36.0;
b.draw_rect(
Rect::new(x, y, 34.0, 26.0),
&Paint::from_color(Color::rgba(
0.2 + (i as f32) * 0.03,
0.5,
1.0 - (i as f32) * 0.02,
0.85,
)),
);
}
Arc::new(b.build())
}
fn wrapper(board: &Arc<valo::DisplayList>, hinted: bool) -> valo::DisplayList {
let mut b = DisplayListBuilder::new();
b.draw_rect(
Rect::new(250.0, 20.0, 40.0, 40.0),
&Paint::from_color(Color::rgb(0.9, 0.6, 0.2)),
);
b.save();
b.translate(12.0, 14.0);
if hinted {
b.draw_display_list_cached(board);
} else {
b.draw_display_list(board);
}
b.restore();
b.build()
}
fn frame_arc(
ctx: &mut Context,
device: &wgpu::Device,
queue: &wgpu::Queue,
list: &Arc<valo::DisplayList>,
camera: Matrix,
) -> (Vec<u8>, valo::RenderStats) {
let size = [320, 200];
let offscreen = Offscreen::new(device, size);
let mut wrapped = DisplayListBuilder::new();
wrapped.save();
wrapped.concat(&camera);
wrapped.draw_display_list(list);
wrapped.restore();
let stats = ctx.render(
&wrapped.build(),
&offscreen.target(Some(Color::rgb(0.08, 0.08, 0.1))),
);
(
valo_harness::read_texture_rgba(device, queue, offscreen.texture(), size),
stats,
)
}
#[test]
fn cached_quad_is_byte_identical_and_lifecycle_holds() {
let Some((device, queue)) = valo_harness::headless_device() else {
eprintln!("SKIP: no GPU adapter");
return;
};
let mut ctx = Context::new(device.clone(), queue.clone());
let board = board();
let plain = Arc::new(wrapper(&board, false));
let (inline_pixels, s0) = frame_arc(&mut ctx, &device, &queue, &plain, Matrix::IDENTITY);
assert_eq!((s0.raster_quads, s0.raster_fills), (0, 0), "unhinted");
let scene = Arc::new(wrapper(&board, true));
let identity = Matrix::IDENTITY;
let (first_frame, s1) = frame_arc(&mut ctx, &device, &queue, &scene, identity);
assert_eq!(
(s1.raster_quads, s1.raster_fills),
(1, 1),
"first sight: fill + quad, one frame"
);
assert_eq!(first_frame, inline_pixels, "fill-frame quad == inline");
let (quad_frame, s2) = frame_arc(&mut ctx, &device, &queue, &scene, identity);
assert_eq!((s2.raster_quads, s2.raster_fills), (1, 0), "quad serves");
assert_eq!(quad_frame, inline_pixels, "cached quad == inline, exactly");
valo_harness::assert_golden(goldens_dir(), "raster_cache_quad", [320, 200], &quad_frame);
let out = zoom(0.6);
let (_, s4) = frame_arc(&mut ctx, &device, &queue, &scene, out);
assert_eq!((s4.raster_quads, s4.raster_fills), (1, 0), "band reuses");
ctx.set_raster_hold(true);
let deep = zoom(0.4);
let (_, s5) = frame_arc(&mut ctx, &device, &queue, &scene, deep);
assert_eq!((s5.raster_quads, s5.raster_fills), (1, 0), "hold reuses");
ctx.set_raster_hold(false);
let (_, s6) = frame_arc(&mut ctx, &device, &queue, &scene, deep);
assert_eq!(
(s6.raster_quads, s6.raster_fills),
(1, 1),
"settle refills past the band and quads immediately"
);
let (_, s7) = frame_arc(&mut ctx, &device, &queue, &scene, deep);
assert_eq!(
(s7.raster_quads, s7.raster_fills),
(1, 0),
"refilled quad serves"
);
let (_, s8) = frame_arc(&mut ctx, &device, &queue, &scene, zoom(1.5));
assert_eq!(
(s8.raster_quads, s8.raster_fills),
(1, 1),
"zoom-in refills denser"
);
}
fn zoom(scale: f32) -> Matrix {
Matrix::from_affine(scale, 0.0, 0.0, scale, 30.0, 20.0)
}
#[test]
fn unhinted_embeds_never_fill() {
let Some((device, queue)) = valo_harness::headless_device() else {
eprintln!("SKIP: no GPU adapter");
return;
};
let mut ctx = Context::new(device.clone(), queue.clone());
for _ in 0..3 {
let fresh = Arc::new(wrapper(&board(), false)); let (_, stats) = frame_arc(&mut ctx, &device, &queue, &fresh, Matrix::IDENTITY);
assert_eq!(
(stats.raster_quads, stats.raster_fills),
(0, 0),
"no hint, no cache"
);
}
}
#[test]
fn settle_refills_all_stale_boards_in_one_frame() {
let Some((device, queue)) = valo_harness::headless_device() else {
eprintln!("SKIP: no GPU adapter");
return;
};
let mut ctx = Context::new(device.clone(), queue.clone());
let (first, second) = (board(), board());
let scene = {
let mut b = DisplayListBuilder::new();
b.draw_display_list_cached(&first);
b.save();
b.translate(0.0, 170.0);
b.draw_display_list_cached(&second);
b.restore();
Arc::new(b.build())
};
let (_, warm) = frame_arc(&mut ctx, &device, &queue, &scene, Matrix::IDENTITY);
assert_eq!((warm.raster_quads, warm.raster_fills), (2, 2));
ctx.set_raster_hold(true);
let deep = zoom(0.3);
let (_, held) = frame_arc(&mut ctx, &device, &queue, &scene, deep);
assert_eq!(
(held.raster_quads, held.raster_fills),
(2, 0),
"hold reuses"
);
ctx.set_raster_hold(false);
let (_, settled) = frame_arc(&mut ctx, &device, &queue, &scene, deep);
assert_eq!(
(settled.raster_quads, settled.raster_fills),
(2, 2),
"the settle frame refills everything at once"
);
}
#[test]
fn an_unused_entry_dies_with_the_frame_that_dropped_it() {
let Some((device, queue)) = valo_harness::headless_device() else {
eprintln!("SKIP: no GPU adapter");
return;
};
let mut ctx = Context::new(device.clone(), queue.clone());
let board = board();
let with_board = Arc::new(wrapper(&board, true));
let without_board = Arc::new(wrapper(&self::board(), false));
let (_, warm) = frame_arc(&mut ctx, &device, &queue, &with_board, Matrix::IDENTITY);
assert_eq!((warm.raster_quads, warm.raster_fills), (1, 1));
frame_arc(&mut ctx, &device, &queue, &without_board, Matrix::IDENTITY);
let (_, back) = frame_arc(&mut ctx, &device, &queue, &with_board, Matrix::IDENTITY);
assert_eq!(
(back.raster_quads, back.raster_fills),
(1, 1),
"the comeback refills"
);
}