diff --git a/crates/ui-egui/src/frames.rs b/crates/ui-egui/src/frames.rs index 55c75f0b..33fd676d 100644 --- a/crates/ui-egui/src/frames.rs +++ b/crates/ui-egui/src/frames.rs @@ -280,8 +280,11 @@ fn comp_content_with(project: &Project, comp: ItemId, addr: impl Fn(ItemId, &Arc h.finish() } -/// Hash of render options (part of [`FrameKey`] and of the disk key). +/// Hash of render options (part of [`FrameKey`] and of the disk key). The scale counts as the +/// key's thousandths ([`FrameKey::scale`]): a series rebuilt from the key (the cache bars) has +/// the same options as the frames rendered at 1/3 = 0.333… (#595). pub fn opts_hash(o: &RenderOpts) -> u64 { + let o = RenderOpts { scale: (o.scale * 1000.0).round() / 1000.0, ..*o }; let mut h = disk_cache::Hash128::default(); h.write(format!("{o:?}").as_bytes()); h.finish() as u64 diff --git a/crates/ui-egui/tests/ui_ram_preview.rs b/crates/ui-egui/tests/ui_ram_preview.rs index 84610b7c..5459be8c 100644 --- a/crates/ui-egui/tests/ui_ram_preview.rs +++ b/crates/ui-egui/tests/ui_ram_preview.rs @@ -125,3 +125,23 @@ fn prefetch_waits_while_edits_keep_coming() { let series = h.state().shown_series(ItemId(c)); assert!(h.state().frames.cached_frames(&series).len() > 1, "prefetch resumed"); } + +/// #595: at Third (and other resolutions that aren't a whole number of thousandths) the cache +/// bars find the rendered frames. The series they count was rebuilt from the frame key's scale +/// (333 → 0.333), whose render options hashed apart from the frames rendered at 0.3333…. +#[test] +fn cached_frames_are_counted_at_one_third_resolution() { + use effectcraft_ui_egui::state::Resolution; + for res in [Resolution::Third, Resolution::Custom(7)] { + let mut s = Session::default(); + let c = s.execute("comp.new", json!({"name": "Third", "width": 64, "height": 36, "duration": 1})).unwrap()["comp"].as_u64().unwrap(); + s.execute("layer.newSolid", json!({"color": "#3080ff"})).unwrap(); + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(|_| EffectcraftApp::new(s)); + h.state_mut().ui.viewer.res = res; + settle(&mut h); + let series = h.state().shown_series(ItemId(c)); + assert_eq!(series.scale, (res.scale(1.0, 1.0) * 1000.0).round() as u32, "{res:?}"); + assert!(shown_cached(&h, c), "{res:?}: the shown frame counts as cached"); + assert!(!h.state().frames.cached_frames(&series).is_empty(), "{res:?}"); + } +}