Fade the draft into the sharp frame when a drag settles

When a gesture stopped, the half-resolution draft was replaced by the
full-resolution frame in one step, a visible jump from soft to sharp.
FR-DSP-4 asks for a refinement that is smooth, not a jarring swap.

The canvas now keeps the last draft frame (`canvas-previous`) and draws
it over the sharp one, fading it out over 150 ms when the draft flag
clears. The fade costs no render: the draft is a refcount on the texture
it was drawn into, and the adjust pass ping-pongs between two output
targets, so the sharp frame is written into the other one. While a
gesture is drafting the layer is hidden and snapped opaque, so a new
drag shows its draft at once; past the fade it is hidden again, and a
settled canvas composites one image as before.
This commit is contained in:
2026-09-24 21:52:23 -04:00
parent 4642c77e18
commit ade627a5d0
4 changed files with 150 additions and 40 deletions
+14 -5
View File
@@ -2293,11 +2293,20 @@ fn build_render_now(
match rendered {
Ok(image) => {
// TRACES: FR-DSP-4
// **The draft flag goes past the render**, to the places
// that have to know which kind of frame is up: the canvas,
// and the histogram, which is measured on settled frames
// only and so describes an older frame while a draft is
// showing.
// **The draft flag goes past the render**, to the two
// places that have to know which kind of frame is up: the
// canvas, which crossfades a draft into the sharp frame
// that settles it, and the histogram, which is measured
// on settled frames only and so describes an older frame
// while a draft is showing.
//
// The draft is kept as the fade's starting picture. That
// is a refcount on the texture it was drawn into, not a
// copy or a render — see `canvas-previous` for why the
// sharp frame cannot overwrite it.
if draft {
window.set_canvas_previous(image.clone());
}
window.set_canvas(image);
window.set_canvas_draft(draft);
window.global::<Levels>().set_provisional(draft);