diff --git a/core/dr-gpu/tests/local_contrast.rs b/core/dr-gpu/tests/local_contrast.rs index b78e049..5b36bee 100644 --- a/core/dr-gpu/tests/local_contrast.rs +++ b/core/dr-gpu/tests/local_contrast.rs @@ -562,28 +562,38 @@ fn texture_contributes_nothing_where_its_scale_does_not_exist() { let mut graph = graph_with(TEXTURE, 100.0); // Asserted on the composed chain rather than on a dispatch counter, - // because texture *alone* at this size is a configuration the stage as a - // whole cannot currently render, and that is a gap in the seam rather than - // in this operation. + // because what is interesting here is not how many dispatches ran but + // that texture contributed no *kernel* to them. // - // `compose_full` decides whether the fused pass should hand on linear - // working values from `is_active()`, which has no `RenderScale` to consult; - // `compose_detail` decides what to dispatch from the kernel it can actually - // draw at this scale. Almost always the two agree. They disagree exactly - // when a detail operation is active and its kernel rounds away, and then - // `render_detailed` finds an empty chain, falls through to `render_masked`, - // and is rejected for handing a linear-working shader to the plain path. + // This assertion used to require an empty chain, and recorded the empty + // chain as a gap in the seam: `compose_full` decides whether the fused + // pass hands on linear working values from `is_active()`, which has no + // `RenderScale` to consult, while `compose_detail` decides what to + // dispatch from the kernel it can actually draw at this scale. When a + // detail operation was active and its kernel rounded away, the two + // disagreed, `render_detailed` found nothing to run, fell through to + // `render_masked`, and was rejected for handing a linear-working shader + // to the plain path — so texture alone on a thumbnail did not render. // - // Pre-existing, and not something clarity and texture introduce: - // `DetailStage::passes` documents the empty return as *the honest answer - // for an acutance operation on a heavy proxy*, so capture sharpening and - // noise reduction reach it by the same road. Fixing it means composing - // both halves of a render together, so the fused half can know whether a - // detail half survived the scale — a change at the composition boundary, - // not in this file. + // The seam was closed where that note said it would have to be, at the + // composition boundary: `compose_detail` now emits a bodyless + // `detail/resolve` pass in exactly this case, which reads only the pixel + // it writes and performs the output transform the fused pass declined to + // do. So the chain is no longer empty — it carries precisely the one pass + // that finishes the render and no kernel at all, which is the honest + // description of "a two-pixel surface structure is not present in a + // 128-pixel rendering". let scale = graph.render_scale(source.size(), (128, 128)); - assert!( - graph.compose_detail_for(scale, ColourSpace::Srgb).is_empty(), + let composed = graph.compose_detail_for(scale, ColourSpace::Srgb); + assert_eq!( + composed.len(), + 1, + "the chain must carry the resolve pass and nothing else" + ); + assert_eq!(composed.passes[0].label, "detail/resolve"); + assert_eq!( + composed.radius(), + 0, "texture claimed a kernel it cannot draw" );