Skip to content

Commit 1ea4365

Browse files
Spruill-1Copilot
andcommitted
CustomPixelShaderEffect: honor queried output sub-rect
Previous impl always returned m_lastOutputRect (the FULL output rect) from MapOutputRectToInputRects regardless of which sub-rect D2D asked for. That was the safe-with-TRIVIAL_SAMPLING fix from the Split atlas debugging, but it also blocks D2Ds lazy-evaluation propagation: a downstream consumer requesting only a sub-rect of our output cant cascade that demand upstream because we keep reporting full-rect input demand at every CustomPixelShaderEffect node in the chain. Pass the queried output sub-rect through as the input demand. With TRIVIAL_SAMPLING, our shaders read input pixel (x,y) for output pixel (x,y) -- so the input rect needed is exactly the output rect being requested. Effects that need full output dimensions for math (Split Comparisons center-of-image pivot, etc.) read them from host-injected OutputW/ OutputH cbuffer fields, not from the per-dispatch rect, so this change is transparent to them. Verified Split pivot still lands at y=1080 of 2160 on the multi-branch reproducer that originally surfaced the bug. Foundation step for upcoming preview-resolution scaling and per-input- rect routing optimizations. 154/154 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c88e778 commit 1ea4365

1 file changed

Lines changed: 19 additions & 4 deletions

File tree

Effects/CustomPixelShaderEffect.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,27 @@ namespace ShaderLab::Effects
256256
D2D1_RECT_L* inputRects,
257257
UINT32 inputRectCount) const
258258
{
259-
// Return the FULL clamped output rect (not the clipped viewport).
260-
// This ensures the intermediate textures match the output rect,
261-
// so TEXCOORD maps 1:1 with GetDimensions() normalization.
259+
// Pass the queried output sub-rect through as the input demand. With
260+
// D2D1_PIXEL_OPTIONS_TRIVIAL_SAMPLING set, our shaders read input
261+
// pixel (x,y) for output pixel (x,y) -- so the input rect needed is
262+
// exactly the output rect being requested.
263+
//
264+
// Honoring the sub-rect (rather than returning m_lastOutputRect for
265+
// every input) is the linchpin of D2Ds lazy-evaluation propagation:
266+
// if a downstream consumer (e.g. the swap-chain present at a small
267+
// canvas size) requests only a sub-rect of our output, that demand
268+
// cascades upward and every upstream effect renders only what's
269+
// actually needed. For preview-resolution scaling on heavy 4K HDR
270+
// graphs this can reduce upstream pixel-shader work by 4x or more.
271+
//
272+
// Split Comparison and other effects that need the full output rect
273+
// for math (pivot recentering, etc.) read the full dimensions from
274+
// host-injected OutputW/OutputH cbuffer fields, not from the per-
275+
// dispatch rect -- so this change is transparent to them.
276+
const D2D1_RECT_L safe = outputRect ? *outputRect : m_lastOutputRect;
262277
for (UINT32 i = 0; i < inputRectCount; ++i)
263278
{
264-
inputRects[i] = m_lastOutputRect;
279+
inputRects[i] = safe;
265280
}
266281
return S_OK;
267282
}

0 commit comments

Comments
 (0)