Skip to content

[PIX] Fix pixel-hit signature instrumentation - #8852

Open
Damyan Pepper (damyanp) wants to merge 1 commit into
users/damyanp/pix-fixes-10from
users/damyanp/pix-fixes-11
Open

[PIX] Fix pixel-hit signature instrumentation#8852
Damyan Pepper (damyanp) wants to merge 1 commit into
users/damyanp/pix-fixes-10from
users/damyanp/pix-fixes-11

Conversation

@damyanp

@damyanp Damyan Pepper (damyanp) commented Aug 27, 2026

Copy link
Copy Markdown
Member

Part 11 of 14 in the PIX instrumentation stack. It targets users/damyanp/pix-fixes-10. Its content depends on PR 2 for the shared helpers.

PIX must know which signature row carries SV_Position, so that it can match a pixel with its instrumentation record. The pass has one option for this row and no way to state whether the row is a requirement or a guess. An unverified row can evict a real interpolant.

Moving SV_Position makes the input signature larger, so the pass must repack the displaced elements. A repack that cannot complete leaves the signature partly rewritten. Signature growth also invalidates the ViewID state, which the pass keeps.

The pass scales the pixel-counter element offset to a byte offset and then limits it. An element index large enough to overflow the multiplication wraps before the limit applies, so an out-of-range pixel is attributed to byte 0, which is pixel 0.

A render-target width or pixel count that is zero, negative, or too large for 32-bit offset arithmetic produces a shader that wraps silently.

Two options carry the caller's intent. preferred-sv-position-row is a hint, and the pass uses the row only when the row is free. required-sv-position-row is a requirement, and the pass fails when it cannot honour the row, because a silent relocation would make PIX's correlation wrong without the caller knowing. The option upstream-sv-position-row stays accepted, because PIX builds older than the rename still send it. When a caller sends both hint spellings, preferred-sv-position-row wins. The camelCase options of the debug instrumentation pass do not change.

The pass raises E_FAIL for a width or a pixel count it cannot represent. A silent wrap gives the caller wrong data with no indication.

Assisted-by: Copilot

This changes only the PIX instrumentation, so it needs no release note.


Stack created with GitHub Stacks CLIGive Feedback 💬

PIX must know which signature row carries SV_Position, so that it can match a pixel with its instrumentation record. The pass has one option for this row and no way to state whether the row is a requirement or a guess. An unverified row can evict a real interpolant.

Moving SV_Position makes the input signature larger, so the pass must repack the displaced elements. A repack that cannot complete leaves the signature partly rewritten. Signature growth also invalidates the ViewID state, which the pass keeps.

The pass scales the pixel-counter element offset to a byte offset and then limits it. An element index large enough to overflow the multiplication wraps before the limit applies, so an out-of-range pixel is attributed to byte 0, which is pixel 0.

A render-target width or pixel count that is zero, negative, or too large for 32-bit offset arithmetic produces a shader that wraps silently.

Two options carry the caller's intent. preferred-sv-position-row is a hint, and the pass uses the row only when the row is free. required-sv-position-row is a requirement, and the pass fails when it cannot honour the row, because a silent relocation would make PIX's correlation wrong without the caller knowing. The option upstream-sv-position-row stays accepted, because PIX builds older than the rename still send it. When a caller sends both hint spellings, preferred-sv-position-row wins. The camelCase options of the debug instrumentation pass do not change.

The pass raises E_FAIL for a width or a pixel count it cannot represent. A silent wrap gives the caller wrong data with no indication.

Assisted-by: Copilot

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
if (RequiredRow != PIXPassHelpers::kUnknownSVPositionRow) {
m_upstreamSVPositionRow = RequiredRow;
m_svPositionRowAuthority =
PIXPassHelpers::SVPositionRowAuthority::Authoritative;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like copilot changed the command line param names but not the code variables?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes PIX pixel-hit and debug instrumentation to safely handle SV_Position placement, signature growth, counter arithmetic, and saturated vertex signatures.

Changes:

  • Adds hint versus authoritative SV_Position row options with legacy compatibility.
  • Repackages displaced signature elements and invalidates stale ViewID state.
  • Adds dimension validation, safer counter indexing, and extensive PIX tests.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
utils/hct/hctdb.py Registers new and legacy row options.
tools/clang/unittests/HLSL/PixTest.cpp Adds instrumentation and validation tests.
tools/clang/test/HLSLFileCheck/pix/pixelCounterRelocationRepacksIntoSharedRow.hlsl Tests compact repacking.
tools/clang/test/HLSLFileCheck/pix/pixelCounterRelocationAtSignatureLimit.hlsl Tests relocation at the register limit.
tools/clang/test/HLSLFileCheck/pix/pixelCounterPreferredRowWinsOverLegacyRow.hlsl Tests option precedence.
tools/clang/test/HLSLFileCheck/pix/pixelCounterPreferredRowOptionIsAHint.hlsl Tests preferred-row hint behavior.
tools/clang/test/HLSLFileCheck/pix/pixelCounterLegacyRowOptionIsAHint.hlsl Tests legacy hint behavior.
tools/clang/test/HLSLFileCheck/pix/MeshShaderSignatureIsNotRelocated.hlsl Covers mesh-signature preservation.
tools/clang/test/HLSLFileCheck/pix/GeometryShaderMultiStreamSignatureIsNotRelocated.hlsl Covers multi-stream GS preservation.
tools/clang/test/HLSLFileCheck/pix/DebugVSParameters.hlsl Updates VS interpolation expectations.
tools/clang/test/HLSLFileCheck/pix/DebugVertexShaderInputSignatureFull.hlsl Tests fully occupied VS signatures.
tools/clang/test/HLSLFileCheck/pix/DebugEmitCorrectViewIdStatePS.hlsl Updates ViewID state expectations.
tools/clang/test/HLSLFileCheck/pix/DebugDenseVertexShaderInput.hlsl Tests partially available VS identity.
tools/clang/test/HLSLFileCheck/pix/DebugBasic.hlsl Updates SV_Position interpolation metadata.
tools/clang/test/HLSLFileCheck/pix/DebugAuthoritativeSVPositionRow.hlsl Tests authoritative debug placement.
lib/DxilPIXPasses/PixPassHelpers.h Defines shared row authority and ViewID helpers.
lib/DxilPIXPasses/PixPassHelpers.cpp Implements placement, repacking, rollback, and state clearing.
lib/DxilPIXPasses/DxilDebugInstrumentation.cpp Handles row authority and saturated VS signatures.
lib/DxilPIXPasses/DxilAddPixelHitInstrumentation.cpp Updates validation, return scanning, and offset arithmetic.
Suppressed comments (1)

lib/DxilPIXPasses/DxilAddPixelHitInstrumentation.cpp:213

  • The new clamp still occurs after two unchecked 32-bit operations. For accepted inputs RTWidth = 0x40000000, X = 0, and Y = 4, Y * RTWidth wraps to zero before UMin, so this out-of-range pixel is still attributed to pixel 0. Compute the linear index with overflow-safe/saturating arithmetic (or in a wider type) before clamping and truncating.
          auto YOffset = Builder.CreateMul(YAsInt, RTWidthArg, "YOffset");
          auto Elementoffset =
              Builder.CreateAdd(XAsInt, YOffset, "ElementOffset");

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 55 to 56
GetPassOptionInt(O, "rt-width", &RTWidth, 0);
GetPassOptionInt(O, "num-pixels", &NumPixels, 0);
Comment on lines +692 to 693
if (Existing_SV_Position != InputElements.end())
return Existing_SV_Position->get()->GetID();
Comment on lines +715 to +725
unsigned int TargetRow = kUnknownSVPositionRow;
if (UpStreamSVPosRow < hlsl::DXIL::kMaxSignatureTotalVectors) {
bool const RowIsOccupied =
!FindElementsOccupyingSignatureRow(InputElements, UpStreamSVPosRow)
.empty();
bool const MayDisplaceOccupants =
RowAuthority == SVPositionRowAuthority::Authoritative &&
ShaderKind == hlsl::DXIL::ShaderKind::Pixel;
if (!RowIsOccupied || MayDisplaceOccupants)
TargetRow = UpStreamSVPosRow;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

3 participants