use super::{
DeviceRect, MAX_SURFACE_PIXELS, Rect, rendered_surface, surface_pixels, surface_within_budget,
};
fn rect(width: f32, height: f32) -> Rect {
Rect {
x: 0.0,
y: 0.0,
width,
height,
}
}
fn device(x: f32, y: f32, width: f32, height: f32) -> DeviceRect {
DeviceRect {
x,
y,
width,
height,
}
}
#[test]
fn a_promoted_control_renders_the_shadow_past_its_box() {
let page = device(0.0, 0.0, 1800.0, 1400.0);
let whole = device(1812.0, 1183.0, 368.0, 312.0);
assert_eq!(rendered_surface(whole, page, 9.0), whole);
}
#[test]
fn a_card_wider_than_the_page_costs_the_page_and_the_glass_reach() {
let page = device(0.0, 0.0, 1800.0, 1400.0);
let card = device(-400.0, 100.0, 3000.0, 400.0);
assert_eq!(
rendered_surface(card, page, 9.0),
device(-9.0, 100.0, 1818.0, 400.0)
);
}
#[test]
fn a_surface_inside_the_budget_keeps_every_pixel_its_content_draws() {
let content = rect(1446.0, 3157.6);
let own_box = rect(1412.0, 1480.0);
assert!(surface_pixels(content, 1.0) <= MAX_SURFACE_PIXELS);
assert_eq!(surface_within_budget(content, own_box, 1.0), content);
}
#[test]
fn content_past_the_budget_falls_back_to_the_layer_own_box() {
let content = rect(5403.0, 3314.4);
let own_box = rect(1412.0, 1480.0);
assert!(
surface_pixels(content, 1.0) > MAX_SURFACE_PIXELS,
"the LeetCodeDaily draft that blanked the window"
);
assert_eq!(surface_within_budget(content, own_box, 1.0), own_box);
assert!(surface_pixels(own_box, 1.0) <= MAX_SURFACE_PIXELS);
}
#[test]
fn the_scale_decides_the_budget_not_the_logical_size() {
let content = rect(3000.0, 2000.0);
let own_box = rect(1000.0, 800.0);
assert_eq!(surface_within_budget(content, own_box, 1.0), content);
assert_eq!(surface_within_budget(content, own_box, 3.0), own_box);
}
#[test]
fn a_box_no_smaller_than_its_content_is_not_worth_swapping_in() {
let content = rect(6000.0, 6000.0);
let own_box = rect(6000.0, 6000.0);
assert_eq!(surface_within_budget(content, own_box, 1.0), content);
}
#[test]
fn ensuring_z_order_sorts_changed_keys_and_preserves_ties() {
let mut values: Vec<_> = (0..96).map(|index| (index % 3, index)).collect();
let expected: Vec<_> = (0..3)
.flat_map(|z| (z..96).step_by(3).map(move |index| (z, index)))
.collect();
ensure_sorted_by_key(&mut values, |value| value.0);
assert_eq!(values, expected);
ensure_sorted_by_key(&mut values, |value| value.0);
assert_eq!(values, expected);
values[95].0 = 0;
ensure_sorted_by_key(&mut values, |value| value.0);
assert_eq!(values[32], (0, 95));
assert_eq!(&values[..32], &expected[..32]);
assert_eq!(&values[33..], &expected[32..95]);
values.clear();
ensure_sorted_by_key(&mut values, |value| value.0);
assert!(values.is_empty());
}
#[test]
fn restricting_stage_layout_preserves_substrate_order_and_independent_storage() {
let specs = [
SubstrateSpec::Average { block: 4 },
SubstrateSpec::Blur { radius_px: 7.0 },
SubstrateSpec::Average { block: 8 },
];
let mut layout = StageLayout {
atlas_sizes: vec![(256, 256)],
placements: vec![
Some(AtlasPlacement {
atlas: 0,
x: 0,
y: 0
});
3
],
substrates: (0..=specs.len() - 1)
.map(|member| {
specs[..=member]
.iter()
.enumerate()
.map(|(slot, spec)| PlannedSubstrate {
spec: *spec,
size: (16, 8),
work_size: (16, 8),
atlas_slot: Some((slot as u32 * 16, member as u32 * 8, 16, 8)),
})
.collect()
})
.collect(),
side_sizes: vec![(128, 128)],
side: (0..specs.len())
.map(|member| SideSlots {
blur: Some((0, member as u32 * 8, 16, 8)),
substrates: (0..=member)
.map(|slot| Some((slot as u32 * 16, member as u32 * 8, 16, 8)))
.collect(),
})
.collect(),
};
let selected = [2, 0, 1];
let restricted = layout.restrict(&selected);
for (index, original) in selected.into_iter().enumerate() {
assert_eq!(restricted.signature(index), layout.signature(original));
assert_eq!(restricted.substrates[index].len(), original + 1);
for (slot, planned) in restricted.substrates[index].iter().enumerate() {
assert_eq!(planned.spec, specs[slot]);
assert_eq!(planned.size, (16, 8));
assert_eq!(
planned.atlas_slot,
Some((slot as u32 * 16, original as u32 * 8, 16, 8))
);
}
assert_eq!(restricted.side[index].blur, layout.side[original].blur);
assert_eq!(
restricted.side[index].substrates,
layout.side[original].substrates
);
layout.substrates[original].clear();
layout.side[original].substrates.clear();
assert_eq!(restricted.substrates[index].len(), original + 1);
assert_eq!(restricted.side[index].substrates.len(), original + 1);
}
}
#[test]
fn a_backdrop_captures_no_further_than_the_clip_it_is_drawn_in() {
let mut shader = RuntimeShader::new("fn glass_fs() {}");
shader.set_input_padding(30.0);
let rect = Rect {
x: 20.0,
y: 96.0,
width: 160.0,
height: 52.0,
};
let list = Rect {
x: 20.0,
y: 96.0,
width: 160.0,
height: 300.0,
};
let target = DeviceRect {
x: 0.0,
y: 0.0,
width: 400.0,
height: 800.0,
};
let layer = BackdropLayer {
node_id: None,
rect,
clip: Some(rect),
reach: Some(list),
rounded_clip: None,
snap_anchor: None,
effect: RenderEffect::runtime_shader(shader),
z_index: 0,
};
let planned = plan_backdrop(&layer, 0, 2.0, target).expect("the backdrop is on the target");
assert_eq!(
planned.capture_rect,
DeviceRect::from_logical(
Rect {
x: 20.0,
y: 96.0,
width: 160.0,
height: 82.0,
},
2.0,
),
"the capture stops at the list's top and sides and reads the padding below, \
where the list goes on"
);
}
#[test]
fn a_backdrop_keeps_its_capture_and_records_the_part_of_it_inside_the_effects_output_support() {
let mut shader = RuntimeShader::new("fn glass_fs() {}");
shader.set_input_padding(2.0);
shader.set_output_padding(3.0);
let rect = Rect {
x: 10.0,
y: 20.0,
width: 100.0,
height: 50.0,
};
let target = DeviceRect {
x: 0.0,
y: 0.0,
width: 400.0,
height: 400.0,
};
let plan = |shader: RuntimeShader| {
let layer = BackdropLayer {
node_id: None,
rect,
clip: None,
reach: None,
rounded_clip: None,
snap_anchor: None,
effect: RenderEffect::runtime_shader(shader),
z_index: 0,
};
let planned = plan_backdrop(&layer, 0, 2.0, target).expect("the backdrop is on the target");
(planned.visible, planned.capture_rect, planned.support)
};
let (whole_visible, whole_capture, whole_support) = plan(shader.clone());
assert_eq!(whole_visible, DeviceRect::from_logical(rect, 2.0));
assert_eq!(whole_capture, whole_visible.expand(10.0).snap_out());
assert_eq!(whole_support, None);
shader.set_output_support(Some(Rect {
x: 30.0,
y: 5.0,
width: 20.0,
height: 10.0,
}));
let (visible, capture_rect, support) = plan(shader);
assert_eq!(visible, whole_visible);
assert_eq!(capture_rect, whole_capture);
assert_eq!(
support,
Some(DeviceRect::from_logical(
Rect {
x: 40.0,
y: 25.0,
width: 20.0,
height: 10.0,
},
2.0,
))
);
}
#[test]
fn a_gate_admits_a_key_that_held_for_more_than_its_patience() {
let key = gate_key(1);
let mut gate = AdmissionGate::copied(key);
assert!(!gate.admits(), "a key seen once is only remembered");
gate.observe(key);
assert!(gate.admits(), "the second frame of a key admits it");
gate.admitted();
gate.hit(key);
assert_eq!(patience(&gate), 1);
assert!(gate.end_frame(), "a gate seen this frame stays");
assert!(!gate.end_frame(), "a gate not seen since goes");
}
#[test]
fn a_cached_key_between_misses_breaks_the_other_keys_consecutive_run() {
let first = gate_key(1);
let other = gate_key(2);
let mut gate = AdmissionGate::copied(first);
gate.observe(first);
assert!(gate.admits());
gate.admitted();
gate.observe(other);
assert!(!gate.admits());
gate.observe(other);
assert!(!gate.admits());
gate.hit(first);
gate.observe(other);
assert!(
!gate.admits(),
"the other key has held for only one frame since the cache hit"
);
}
fn gate_frame(gate: &mut AdmissionGate, key: LayerRasterCacheKey) -> bool {
if gate.unread && gate.key == key {
gate.hit(key);
return false;
}
gate.observe(key);
if gate.admits() {
gate.admitted();
return true;
}
false
}
fn admissions_over(gate: &mut AdmissionGate, holds: impl IntoIterator<Item = u32>) -> u32 {
let mut admissions = 0;
for (step, hold) in holds.into_iter().enumerate() {
for _ in 0..hold {
admissions += u32::from(gate_frame(gate, gate_key(step as u64 + 1)));
}
}
admissions
}
#[test]
fn a_gate_waits_twice_as_long_after_an_admission_nothing_read_back() {
let mut gate = AdmissionGate::copied(gate_key(0));
assert_eq!(
admissions_over(&mut gate, std::iter::repeat_n(2, 40)),
1,
"a key that never holds a third frame is admitted once"
);
assert_eq!(patience(&gate), 2);
let mut gate = AdmissionGate::copied(gate_key(0));
assert_eq!(
admissions_over(&mut gate, std::iter::repeat_n(3, 12)),
12,
"a key that holds a third frame is read back once per admission"
);
assert_eq!(
patience(&gate),
1,
"an admission read back does not double the patience"
);
}
#[test]
fn a_pinned_gate_admits_every_uncached_frame_and_counts_the_hold() {
let mut gate = AdmissionGate::pinned(gate_key(0));
assert!(gate.admits(), "a pin costs no pass, so first sight admits");
assert_eq!(
admissions_over(&mut gate, std::iter::repeat_n(2, 40)),
40,
"every two-frame hold is pinned on its first frame and replayed on its second"
);
assert_eq!(
gate.run(),
2,
"the replay counted as a second frame of the hold"
);
let mut gate = AdmissionGate::pinned(gate_key(0));
assert_eq!(
admissions_over(&mut gate, std::iter::repeat_n(1, 40)),
40,
"an unread pin costs nothing to repeat, so a key changing every frame is pinned \
every frame"
);
assert_eq!(gate.run(), 1);
for _ in 0..4 {
gate.observe(gate_key(99));
}
assert_eq!(
gate.run(),
4,
"a held key's run is what the admission budget ranks by"
);
}
#[test]
fn a_pin_lives_exactly_as_long_as_its_key_and_a_copy_only_dies_unread() {
let mut gate = AdmissionGate::pinned(gate_key(1));
assert_eq!(
gate.dead_entry(),
None,
"nothing admitted, nothing to hand back"
);
gate.admitted();
assert_eq!(gate.dead_entry(), Some(gate_key(1)));
assert_eq!(
gate.observe(gate_key(1)),
None,
"the same key holds the pin"
);
assert_eq!(
gate.observe(gate_key(2)),
Some(gate_key(1)),
"a pin nothing read back dies with its key"
);
assert_eq!(gate.dead_entry(), None);
gate.admitted();
gate.hit(gate_key(2));
assert_eq!(
gate.observe(gate_key(3)),
Some(gate_key(2)),
"a pin that was read back dies with its key too: a re-pin costs nothing"
);
let mut gate = AdmissionGate::copied(gate_key(1));
gate.observe(gate_key(1));
gate.admitted();
gate.hit(gate_key(1));
assert_eq!(
gate.observe(gate_key(2)),
None,
"a copy that was read back stays for the cache to keep or evict"
);
gate.observe(gate_key(2));
gate.admitted();
assert_eq!(
gate.observe(gate_key(3)),
Some(gate_key(2)),
"a copy nothing read back is handed back"
);
}
fn patience(gate: &AdmissionGate) -> u32 {
match gate.cost {
AdmissionCost::Pin => 0,
AdmissionCost::Copy { patience, .. } => patience,
}
}
#[test]
fn a_rendered_gate_admits_a_first_sight_and_waits_after_an_unread_admission() {
let mut gate = AdmissionGate::rendered(gate_key(0));
assert!(
gate.admits(),
"a surface seen for the first time is kept, as still content reads it back next frame"
);
assert_eq!(
admissions_over(&mut gate, std::iter::repeat_n(1, 40)),
1,
"a surface that changes every frame is kept once, then drawn without being stored"
);
assert_eq!(patience(&gate), 1);
assert_eq!(
admissions_over(&mut gate, [3]),
1,
"a surface that settles is kept on its second frame"
);
assert_eq!(
patience(&gate),
0,
"a kept surface read back restores first-sight admission"
);
assert!(gate_frame(&mut gate, gate_key(100)));
}
#[test]
fn a_gate_never_waits_longer_than_the_cap() {
let mut gate = AdmissionGate::copied(gate_key(0));
let admissions = admissions_over(&mut gate, [2, 3, 5, 9, 17, 17, 17]);
assert_eq!(
admissions, 7,
"each hold one frame past the patience is admitted on its last frame"
);
assert_eq!(patience(&gate), MAX_ADMISSION_PATIENCE);
}
fn gate_key(content: u64) -> LayerRasterCacheKey {
LayerRasterCacheKey::backdrop_effect(
None,
content,
0,
Rect {
x: 0.0,
y: 0.0,
width: 1.0,
height: 1.0,
},
(1, 1),
RasterScale::from_scale(1.0),
)
}
use super::*;
use crate::scene::DrawOpKind;
fn rounded_child(transform: ProjectiveTransform, surface_scale: f32) -> ChildLayer {
let local_bounds = Rect {
x: 0.0,
y: 0.0,
width: 40.0,
height: 40.0,
};
ChildLayer {
z_index: 0,
node_id: None,
local_bounds,
transform,
clip: None,
rounded_clip: Some(LayerRoundedClip {
rect: local_bounds,
radii: [20.0; 4],
}),
alpha: 1.0,
blend_mode: BlendMode::SrcOver,
effect: None,
backdrop: None,
snap_anchor: None,
surface_scale,
content_hash: 0,
cache_policy: CachePolicy::None,
content: LayerScene {
scene: CompositorScene::new(),
children: Vec::new(),
},
}
}
#[test]
fn a_scaled_child_masks_its_rounded_clip_scaled_with_it() {
let scaled = rounded_child(
ProjectiveTransform::uniform_scale(1.5)
.then(ProjectiveTransform::translation(100.0, 200.0)),
1.5,
);
let mask = grid_rounded_mask(&scaled, Point::new(0.5, 0.0), 2.0)
.expect("a uniform scale keeps the clip axis-aligned");
assert_eq!(mask.rect, [201.0, 400.0, 120.0, 120.0]);
assert_eq!(mask.radii, [60.0; 4]);
let translated = rounded_child(ProjectiveTransform::translation(10.0, 20.0), 1.0);
let mask = grid_rounded_mask(&translated, Point::default(), 1.0)
.expect("a translation keeps the clip axis-aligned");
assert_eq!(mask.rect, [10.0, 20.0, 40.0, 40.0]);
assert_eq!(mask.radii, [20.0; 4]);
}
#[test]
fn a_rotated_child_has_no_axis_aligned_rounded_mask() {
let rotated = rounded_child(
ProjectiveTransform::from_rect_to_quad(
Rect {
x: 0.0,
y: 0.0,
width: 40.0,
height: 40.0,
},
[[20.0, 0.0], [40.0, 20.0], [20.0, 40.0], [0.0, 20.0]],
),
1.0,
);
assert!(grid_rounded_mask(&rotated, Point::default(), 1.0).is_none());
}
fn op(z_index: usize) -> DrawOp {
DrawOp {
z_index,
kind: DrawOpKind::Run(0),
}
}
#[test]
fn pending_draw_ops_keep_deferred_content_and_respect_capture_depth() {
let scene = [op(1), op(3), op(5), op(7)];
let deferred = [op(0), op(2), op(4), op(6)];
let depths = |ops: &[DrawOp]| ops.iter().map(|op| op.z_index).collect::<Vec<_>>();
let only_deferred = pending_draw_ops(&scene, 7, 6, &[], &deferred);
assert_eq!(depths(&only_deferred), [0, 2, 4]);
assert!(matches!(only_deferred, Cow::Borrowed(_)));
let only_scene = pending_draw_ops(&scene, 3, 6, &[], &[]);
assert_eq!(depths(&only_scene), [3, 5]);
assert!(matches!(only_scene, Cow::Borrowed(_)));
let mixed = pending_draw_ops(&scene, 3, 6, &[(5, 6)], &deferred);
assert_eq!(depths(&mixed), [0, 2, 3, 4]);
let excluded_scene = pending_draw_ops(&scene, 3, 6, &[(3, 6)], &deferred);
assert_eq!(depths(&excluded_scene), [0, 2, 4]);
assert!(matches!(excluded_scene, Cow::Borrowed(_)));
assert!(pending_draw_ops(&scene, 0, 0, &[], &deferred).is_empty());
assert_eq!(
depths(&pending_draw_ops(&scene, 0, 3, &[(0, 3)], &[])),
[0usize; 0]
);
}
#[test]
fn an_inverted_op_range_is_empty_even_when_an_op_sits_at_its_end() {
let ops = [op(1), op(3), op(3), op(5)];
assert!(filtered_ops_in_range(&ops, 4, 3, &[]).is_empty());
assert!(filtered_ops_in_range(&ops, 3, 3, &[]).is_empty());
assert_eq!(
filtered_ops_in_range(&ops, 3, 4, &[])
.iter()
.map(|op| op.z_index)
.collect::<Vec<_>>(),
[3, 3]
);
}
#[test]
fn reused_coverage_scratch_replaces_prior_clips_and_respects_draw_order() {
let rect = |x, width| DeviceRect {
x,
y: 0.0,
width,
height: 10.0,
};
let holes: Vec<_> = (0..8)
.map(|index| Blocker {
z: index,
rect: rect(index as f32 * 3.0, 2.0),
})
.collect();
let mut covered = Vec::new();
collect_covered_rects(&holes, 7, rect(0.0, 24.0), &mut covered);
assert_eq!(covered.len(), 7);
assert_eq!(covered.last(), Some(&rect(18.0, 2.0)));
collect_covered_rects(&holes, 3, rect(4.0, 4.0), &mut covered);
assert_eq!(covered, [rect(4.0, 1.0), rect(6.0, 2.0)]);
collect_covered_rects(&holes, 3, rect(12.0, 6.0), &mut covered);
assert!(covered.is_empty());
collect_covered_rects(&[], usize::MAX, rect(0.0, 24.0), &mut covered);
assert!(covered.is_empty());
}
#[test]
fn many_overlapping_holes_preserve_every_uncovered_pixel_once() {
let rect = DeviceRect {
x: 0.0,
y: 0.0,
width: 20.0,
height: 20.0,
};
let mut holes: Vec<_> = (1..=4)
.map(|index| DeviceRect {
x: (index * 4 - 2) as f32,
y: 2.0,
width: 1.0,
height: 16.0,
})
.collect();
holes.extend([
DeviceRect {
x: -2.0,
y: 8.0,
width: 14.0,
height: 2.0,
},
DeviceRect {
x: 6.0,
y: 8.0,
width: 20.0,
height: 2.0,
},
]);
let parts = rect.subtract_all(&holes);
assert!(parts.len() > 4);
for part in &parts {
assert_eq!(part.intersect(rect), Some(*part));
}
for y in 0..20 {
for x in 0..20 {
let pixel = DeviceRect {
x: x as f32,
y: y as f32,
width: 1.0,
height: 1.0,
};
let covered = holes.iter().any(|hole| hole.intersect(pixel).is_some());
let count = parts
.iter()
.filter(|part| part.intersect(pixel).is_some())
.count();
assert_eq!(count, usize::from(!covered), "pixel=({x}, {y})");
}
}
holes.push(rect);
assert!(rect.subtract_all(&holes).is_empty());
}
#[test]
fn subtracting_holes_partitions_a_rect_exactly() {
let rect = DeviceRect {
x: 0.0,
y: 0.0,
width: 10.0,
height: 10.0,
};
let holes = [
DeviceRect {
x: 2.0,
y: 2.0,
width: 3.0,
height: 3.0,
},
DeviceRect {
x: 6.0,
y: 6.0,
width: 10.0,
height: 10.0,
},
];
let parts = rect.subtract_all(&holes);
assert!(rect.subtract(rect).is_empty());
assert_eq!(
rect.subtract(rect.translated(Point { x: 10.0, y: 0.0 }))
.as_slice(),
&[rect]
);
let area: f32 = parts.iter().map(|part| part.width * part.height).sum();
assert_eq!(area, 100.0 - 9.0 - 16.0);
for (index, a) in parts.iter().enumerate() {
assert!(holes.iter().all(|hole| a.intersect(*hole).is_none()));
for b in &parts[index + 1..] {
assert!(a.intersect(*b).is_none(), "parts overlap: {a:?} {b:?}");
}
}
}