Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
5238ee0
[PIX] Add validation support to PIX pass tests
damyanp Aug 24, 2026
0e1a374
[PIX] Fix shared instrumentation resource handling
damyanp Aug 25, 2026
9976585
[PIX] Skip NURI handles with no instruction number
damyanp Aug 25, 2026
d6de1e3
[PIX] Fix DXR invocation log bounds
damyanp Aug 25, 2026
fc840ef
[PIX] Recompute shader flags after NURI instrumentation
damyanp Aug 25, 2026
3a1095e
[PIX] Record only real resource accesses, including samplers
damyanp Aug 25, 2026
60e6902
[PIX] Fix dynamic bind-point identity and range bounds
damyanp Aug 25, 2026
3b7c9fe
[PIX] Attribute library accesses to reaching entry points
damyanp Aug 25, 2026
b8ea3e5
[PIX] Fix render-state visualization passes
damyanp Aug 24, 2026
8658126
[PIX] Fix debug variable storage layout
damyanp Aug 25, 2026
cf36a3e
[PIX] Fix pixel-hit signature instrumentation
damyanp Aug 25, 2026
fac85e1
[PIX] Allow only known PIX metadata before validation
damyanp Sep 2, 2026
6613667
[PIX] Spell explicit types in L1 validation tests
damyanp Sep 3, 2026
fda0a59
[PIX] Remove metadata counts from comments
damyanp Sep 3, 2026
f80826f
[PIX] Format L1 validation changes
damyanp Sep 3, 2026
8c15684
Merge final approved clean L1 into original L2
damyanp Sep 3, 2026
c3bc465
[PIX] Set the root descriptor flags only on append
damyanp Sep 2, 2026
27008ea
[NFC] Spell out L2 local types
damyanp Sep 3, 2026
e6e17f3
[PIX] Follow LLVM naming conventions
damyanp Sep 3, 2026
ca7cc66
[PIX] Use lower camel case for helper functions
damyanp Sep 3, 2026
eae636f
Merge final L1 naming tip into published L2
damyanp Sep 3, 2026
d1257a5
[PIX] Apply LLVM naming to L2 additions
damyanp Sep 3, 2026
ad56207
[PIX] Name the root signature parameter
damyanp Sep 3, 2026
a1fd011
[PIX] Validate known metadata before stripping
damyanp Sep 3, 2026
eb33d12
Merge final L1 metadata validation into L2
damyanp Sep 3, 2026
1ccbb12
[PIX] Report declaration cleanup mutations
damyanp Sep 17, 2026
947c113
[PIX] Remove unused mesh index declaration
damyanp Sep 17, 2026
3fd13a2
[PIX] Collect final NURI shader flags
damyanp Sep 17, 2026
8aa777f
Merge upstream main into PIX validation L1
damyanp Sep 17, 2026
cecb393
Merge current-main L1 into published L2
damyanp Sep 17, 2026
29e29d2
[PIX] Preserve root signature source text
damyanp Sep 18, 2026
42b7d4f
Merge main after PIX validation squash
damyanp Sep 22, 2026
eb5d769
Merge latest main into PIX direct-feedback L2
damyanp Sep 28, 2026
f0c9fd1
[NFC] Omit braces for single-statement PIX conditions
damyanp Sep 28, 2026
94d963f
Merge commit 'f0c9fd1c8807711ddabbde5d656aebed35ff1386' into users/da…
damyanp Sep 29, 2026
b03077d
Merge updated L3 into L4
damyanp Sep 29, 2026
e8a7ca9
[PIX] Preserve L3 helper naming after merge
damyanp Sep 29, 2026
d979879
Merge updated L4 into L5
damyanp Sep 29, 2026
f545a76
Merge updated L5 into L6
damyanp Sep 29, 2026
319a7c0
Merge L6 (users/damyanp/pix-fixes-06) into L7
damyanp Sep 29, 2026
7dba5a8
Merge updated PIX L7 into L8
Copilot Sep 29, 2026
1219df0
[PIX] Merge updated L8 into L9
damyanp Sep 29, 2026
d0dee21
Merge commit '1219df0c324c0bb935b63cf775a3ecc28be66c91' into users/da…
damyanp Sep 29, 2026
2344b47
Merge updated PIX L10 into pixel-hit instrumentation
damyanp Sep 29, 2026
fddd3bd
[PIX] Apply clang-format to PixTest.cpp
damyanp Sep 29, 2026
a007d4b
Merge updated L5 into L6
damyanp Sep 29, 2026
f04769b
Merge updated L6 into L7
damyanp Sep 29, 2026
0d49ad1
Merge updated L7 into L8
damyanp Sep 29, 2026
a8edc79
Merge updated L8 into L9
damyanp Sep 29, 2026
24f82d6
Merge updated L9 into L10
damyanp Sep 29, 2026
0af3d6d
Merge updated L10 into L11
damyanp Sep 29, 2026
683dcf7
[PIX] Guard winerror.h include in pixel-hit instrumentation for non-W…
damyanp Sep 29, 2026
7032f2e
[PIX] Link DxilPIXPasses against HLSL for DxilSignatureAllocator
damyanp Sep 29, 2026
0a691ff
[PIX] Don't leak a pass whose applyOptions throws
damyanp Sep 29, 2026
00edebe
[PIX] Address review feedback: explicit DebugBreak tracking, typo, te…
damyanp Sep 29, 2026
a2a3261
Merge updated L2 into L3
damyanp Sep 29, 2026
1575de6
Merge updated L3 into L4
damyanp Sep 30, 2026
409fa0e
Merge updated L4 into L5
damyanp Sep 30, 2026
80a9c34
Merge updated L5 into L6
damyanp Sep 30, 2026
7de0421
Merge updated L6 into L7
damyanp Sep 30, 2026
9370fe9
Merge updated L7 into L8
damyanp Sep 30, 2026
95eca4e
Merge updated L8 into L9
damyanp Sep 30, 2026
4c8dd48
Merge updated L9 into L10
damyanp Sep 30, 2026
a08dbca
Merge updated L10 into L11
damyanp Sep 30, 2026
e76a6d7
[PIX] Recompute shader flags after NURI instrumentation
damyanp Oct 1, 2026
79770f0
[PIX] Record only real resource accesses, including samplers
damyanp Oct 1, 2026
d7808b1
[PIX] Fix dynamic bind-point identity and range bounds
damyanp Oct 1, 2026
7acdd2b
[PIX] Attribute library accesses to reaching entry points
damyanp Oct 1, 2026
ddc1237
[PIX] Fix render-state visualization passes
damyanp Oct 1, 2026
2dbfd94
[PIX] Fix debug variable storage layout
damyanp Oct 1, 2026
0da2ac2
Merge restacked L10 into L11
damyanp Oct 1, 2026
e0180a5
Merge restacked L10 into L11
damyanp Oct 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 112 additions & 25 deletions lib/DxilPIXPasses/DxilAddPixelHitInstrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@

#include "PixPassHelpers.h"

#include "dxc/Support/Global.h"
#ifdef _WIN32
#include <winerror.h>
#endif

using namespace llvm;
using namespace hlsl;

Expand All @@ -41,16 +46,60 @@ class DxilAddPixelHitInstrumentation : public ModulePass {
}
void applyOptions(PassOptions O) override;
bool runOnModule(Module &M) override;
unsigned m_upstreamSVPositionRow;
unsigned m_upstreamSVPositionRow = PIXPassHelpers::kUnknownSVPositionRow;
PIXPassHelpers::SVPositionRowAuthority m_svPositionRowAuthority =
PIXPassHelpers::SVPositionRowAuthority::Hint;
};

void DxilAddPixelHitInstrumentation::applyOptions(PassOptions O) {
GetPassOptionBool(O, "force-early-z", &ForceEarlyZ, false);
GetPassOptionBool(O, "add-pixel-cost", &AddPixelCost, false);
GetPassOptionInt(O, "rt-width", &RTWidth, 0);
GetPassOptionInt(O, "num-pixels", &NumPixels, 0);
Comment on lines 57 to 58
GetPassOptionUnsigned(O, "upstream-sv-position-row", &m_upstreamSVPositionRow,
0);

// RTWidth and NumPixels size the counter UAV and convert SV_Position to a
// byte offset into it. Reject a width or pixel count this pass cannot
// represent -- zero, negative, or large enough that the pixel-cost half's
// high water mark (NumPixels * 2 * 4 bytes) does not fit in 32 bits --
// instead of emitting a shader whose offset arithmetic silently wraps.
if (RTWidth <= 0 || NumPixels <= 0 ||
static_cast<uint64_t>(NumPixels) * 2 * 4 > UINT32_MAX) {
throw ::hlsl::Exception(
E_FAIL, "PIX: the pixel-hit instrumentation was given a render "
"target width or pixel count it cannot represent.");
}

// This option always sets a hint, never a required row: treating an
// unverified row as required could evict a real interpolant based on a
// guess.
//
// GetPassOptionUnsigned leaves the value untouched when the option is
// present but unparseable, so seed the member before the call rather than
// rely on the default argument.
//
// "upstream-sv-position-row" is the pre-rename spelling: old PIX versions
// predate this rename and still send it, so it is kept as an accepted
// alias indefinitely rather than only for a deprecation window. New
// callers should prefer "preferred-sv-position-row"; if both are
// supplied, the preferred spelling wins.
m_upstreamSVPositionRow = PIXPassHelpers::kUnknownSVPositionRow;
if (!GetPassOptionUnsigned(O, "preferred-sv-position-row",
&m_upstreamSVPositionRow,
PIXPassHelpers::kUnknownSVPositionRow)) {
GetPassOptionUnsigned(O, "upstream-sv-position-row",
&m_upstreamSVPositionRow,
PIXPassHelpers::kUnknownSVPositionRow);
}
m_svPositionRowAuthority = PIXPassHelpers::SVPositionRowAuthority::Hint;

unsigned RequiredRow = PIXPassHelpers::kUnknownSVPositionRow;
GetPassOptionUnsigned(O, "required-sv-position-row", &RequiredRow,
PIXPassHelpers::kUnknownSVPositionRow);
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?

}
Comment on lines +95 to +102
}

bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
Expand All @@ -66,13 +115,11 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
DM.m_ShaderFlags.SetForceEarlyDepthStencil(true);
}

auto SV_Position_ID =
PIXPassHelpers::FindOrAddSV_Position(DM, m_upstreamSVPositionRow);
auto SV_Position_ID = PIXPassHelpers::FindOrAddSV_Position(
DM, m_upstreamSVPositionRow, m_svPositionRowAuthority);

auto EntryPointFunction = PIXPassHelpers::GetEntryFunction(DM);

auto &EntryBlock = EntryPointFunction->getEntryBlock();

CallInst *HandleForUAV;
{
IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(
Expand All @@ -83,18 +130,32 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {

DM.ReEmitDxilResources();
}
// todo: is it a reasonable assumption that there will be a "Ret" in the entry
// block, and that these are the only points from which the shader can exit
// (except for a pixel-kill?)
auto &Instructions = EntryBlock.getInstList();
auto It = Instructions.begin();
while (It != Instructions.end()) {
auto ThisInstruction = It++;
// Every point where the shader completes must bump the counter. A
// straight-line shader keeps its Ret in the entry block, but a shader with
// a loop or branch ends the entry block early, so every basic block is
// scanned for a Ret.
llvm::SmallVector<llvm::Instruction *, 4> ReturnInstructions;
bool FunctionHasWork = false;
for (auto &ThisBlock : EntryPointFunction->getBasicBlockList()) {
for (auto &ThisInstruction : ThisBlock) {
LlvmInst_Ret Ret(&ThisInstruction);
if (Ret) {
ReturnInstructions.push_back(&ThisInstruction);
} else if (!llvm::isa<llvm::TerminatorInst>(&ThisInstruction)) {
FunctionHasWork = true;
}
}
}

bool Modified = false;

for (auto ThisInstruction : ReturnInstructions) {
LlvmInst_Ret Ret(ThisInstruction);
if (Ret) {
// Check that there is at least one instruction preceding the Ret (no need
// to instrument it if there isn't)
if (ThisInstruction->getPrevNode() != nullptr) {
// A function that contains nothing but terminators has no pixel work
// worth counting.
if (FunctionHasWork) {
Modified = true;

// Start adding instructions right before the Ret:
IRBuilder<> Builder(ThisInstruction);
Expand All @@ -110,7 +171,13 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
Constant *One32Arg = HlslOP->GetU32Const(1);
Constant *One8Arg = HlslOP->GetI8Const(1);
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(Ctx));
Constant *NumPixelsByteOffsetArg = HlslOP->GetU32Const(NumPixels * 4);
// Compute as uint32_t, not NumPixels' own int: applyOptions
// guarantees NumPixels * 2 * 4 fits in 32 bits only for unsigned
// arithmetic. The signed multiply would overflow int32 for a
// NumPixels this pass accepts, which is undefined behavior on the
// host, not just a wrapped value in the shader.
Constant *NumPixelsByteOffsetArg =
HlslOP->GetU32Const(static_cast<uint32_t>(NumPixels) * 4u);

// Step 1: Convert SV_POSITION to UINT
Value *XAsInt;
Expand Down Expand Up @@ -141,12 +208,31 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
// Step 2: Calculate pixel index
Value *Index;
{
Constant *RTWidthArg = HlslOP->GetI32Const(RTWidth);
Constant *RTWidthArg =
HlslOP->GetU32Const(static_cast<uint32_t>(RTWidth));
auto YOffset = Builder.CreateMul(YAsInt, RTWidthArg, "YOffset");
auto Elementoffset =
Builder.CreateAdd(XAsInt, YOffset, "ElementOffset");
Comment on lines 213 to 215
Index = Builder.CreateMul(Elementoffset, HlslOP->GetU32Const(4),
"ByteIndex");

// The viewport can be offset from the render target's origin, or
// smaller than the counter buffer PIX sized for it, so
// SV_Position's X and Y can land ElementOffset past the last valid
// element. Clamp the element count before scaling to a byte
// offset: applyOptions guarantees (NumPixels-1)*4 fits in uint32,
// so the clamped multiply cannot wrap. Clamping after scaling
// would let an oversized ElementOffset overflow the multiply
// first.
Function *UMinOpFunc =
HlslOP->GetOpFunc(OP::OpCode::UMin, Type::getInt32Ty(Ctx));
Constant *UMinOpcode =
HlslOP->GetU32Const((unsigned)OP::OpCode::UMin);
Constant *LastElementArg =
HlslOP->GetU32Const(static_cast<uint32_t>(NumPixels) - 1);
auto ClampedElementOffset = Builder.CreateCall(
UMinOpFunc, {UMinOpcode, Elementoffset, LastElementArg},
"ClampedElementOffset");
Index = Builder.CreateMul(ClampedElementOffset,
HlslOP->GetU32Const(4), "ByteIndex");
}

// Insert the UAV increment instruction:
Expand Down Expand Up @@ -188,7 +274,8 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
Type::getInt32Ty(Ctx));
Constant *LoadWeightOpcode =
HlslOP->GetU32Const((unsigned)DXIL::OpCode::BufferLoad);
Constant *OffsetIntoUAV = HlslOP->GetU32Const(NumPixels * 2 * 4);
Constant *OffsetIntoUAV =
HlslOP->GetU32Const(static_cast<uint32_t>(NumPixels) * 2u * 4u);
auto WeightStruct = Builder.CreateCall(
LoadWeight,
{
Expand All @@ -202,7 +289,9 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
WeightStruct, static_cast<uint64_t>(0LL), "Weight");
}

// Step 2: Update write position ("Index") to second half of the UAV
// Step 2: Update write position ("Index") to second half of the UAV.
// Index is already clamped to the first half, so this can only land
// in the second half without a clamp of its own.
auto OffsetIndex = Builder.CreateAdd(Index, NumPixelsByteOffsetArg,
"OffsetByteIndex");

Expand All @@ -225,8 +314,6 @@ bool DxilAddPixelHitInstrumentation::runOnModule(Module &M) {
}
}

bool Modified = false;

return Modified;
}

Expand Down
Loading
Loading