You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The PIX passes change DXIL after the compiler completes. A pass can add a resource, change a root signature, insert an operation, and remove a declaration. The result can be a module that the validator refuses. The tests only examine the disassembly, so they cannot find this type of defect.
The new helpers run the DXIL validator on the output of a pass. They also separate the diagnostics that PIX instrumentation is permitted to cause from the diagnostics that are defects. The set of permitted diagnostics decides what every later layer can ignore, so it is the part to examine with care.
There is no change to the compiler.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
More than one PIX pass can run on the same module. Each pass adds its own tools UAV, so a pipeline with two passes makes two resources at the same register and space.
The code that adds this UAV to a root signature has three unsafe paths. Root signature serialization can fail and give a null blob, which the code then reads. An empty result can replace a correct root signature. Only the first global root-signature subobject gets the new parameter, so a state object that declares more than one is left in a mixed state.
The tools UAV is a raw buffer, so it changes the shader flags of the module. The code does not compute the flags again. Some passes make a dx.op overload declaration and then find no callers for it. They leave the declaration in the module, and the validator refuses a module that has an unused declaration.
When serialization fails, the helpers keep the original root signature. A valid signature is better than an empty one.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
The non-uniform resource index pass writes each diagnostic bit at an address that it computes from the PIX instruction number of the handle. If a handle has no instruction number, the value stays at 0. A debug build stops at an assertion. A release build writes the bit for instruction 0 and gives the diagnostic to an unrelated instruction. Library helper functions are the usual source of these handles.
The pass ignores such a handle instead of guessing. An absent record is correct. A record at instruction 0 is wrong. The report NuriNotInstrumentedMissingInstructionNumber tells the caller that the data is not complete.
The pass reads the instruction number before it makes the UAV. A module whose dynamic handles all lack an instruction number therefore gets no UAV that it cannot use.
A PIX build that does not read the new report keeps its current behavior.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
Each DXR invocation takes one slot in the log with an atomic increment on the counter UAV. If the slot number is too large, the pass limits it to the last slot. Every invocation that overflows therefore writes over the last correct record. PIX sees a full log with a plausible final entry and cannot detect the truncation.
A capacity of zero makes that clamp wrap to a very large value, so a log with no slots accepts writes.
An out-of-range slot must produce no write. The correct records then stay unchanged, and the overflow stays visible, because the claimed count is larger than the capacity.
An invocation that overflows contributes no record. A tool that treats a full log as a complete log must compare the claimed count with the capacity.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
The non-uniform resource index pass inserts WaveActiveAllEqual to test whether a dynamic index is uniform. It inserts these calls after the compiler computed the shader flags. The module can therefore declare no wave operations and still contain them, and the validator refuses that module.
The pass computes the flags again, but only when it changed the module.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
The shader access tracking pass records an access for each DXIL operation that takes a resource handle. Two of these operations are not accesses. annotateHandle attaches type information to a handle. barrierByMemoryHandle puts accesses in order. The pass therefore reports a read or a write at a point where the shader touches no memory.
The pass also matches a library handle against the UAVs, the SRVs, and the constant buffers, but not against the samplers. A sampler access in a library shader gets no record, so the sampler binding looks unused.
An access that consumes an annotated handle keeps its record. The pass still looks through the annotation to reach the resource.
PIX receives fewer incorrect records and more sampler records. A tool that counts records will see different totals.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
RSRegisterIdentifier::operator< combines its three fields with &&. This is not a strict weak ordering. Two distinct ranges can compare as neither less than the other, so the map treats them as one key and gives their slot assignments to one of them. Accesses to one range are then reported against the other.
RegisterID comes from the position of the resource in the module's resource list. PIX needs the register that the binding occupies.
The range check for a constant index is off by one, so the pass accepts an index that addresses the slot after the range.
An index outside the range is still recorded at slot zero.
The meaning of RegisterID changes. A tool that resolved the old value against the module's resource list must resolve the new value against the root signature.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
The pass either skips a helper function in a library or gives its access the Library shader kind. Library is the kind of the module. It does not identify the pipeline stage that reaches the access. PIX cannot tell whether a record comes from a ray generation, closest-hit, or miss shader.
The access record holds the instruction number in a field of 24 bits. A larger number overflows into the adjacent fields of the record.
PIX receives records for helper functions, and each record carries a pipeline stage. A tool that filtered out records with the Library kind will see more data.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
dx.op.storeOutput has four legal overloads: f16, f32, i16, and i32. DxilOutputColorBecomesConstant looks only for f32 and i32. A shader that writes SV_Target0 as min16float, min16int, half, or int16_t gets no constant-color instrumentation. The pass then asserts that the outputs are not mixed, and that assertion cannot tell "both types present" from "neither type recognised".
The pass builds a constant buffer for the colour, but it does not give that buffer a layout ValidateCBuffer can reach. The validator therefore refuses the instrumented module.
DxilReduceMSAAToSingleSample does not look through annotateHandle, and it does not accept a 16-bit texture load.
Only one overload can write SV_Target0, so there is no mixed case to resolve. PIX always uploads four 32-bit components, so the shader narrows them when the output is 16 bits. The upload format does not change.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
The debug passes tell PIX where each variable lives in the shadow storage. Four defects make that information disagree with the shader.
The offset calculation ignores the full extent of an array, the padding in an aggregate, the position of a bitfield, and the layout of a matrix. An offset can therefore point into the storage of another variable.
A dynamically indexed write to an alloca takes its register span from the length of the array. DxilAnnotateWithVirtualRegister records the true span in !pix-alloca-reg-write. The two values disagree for an array of aggregates, so a dynamic index can be limited against the wrong bound.
IsAllocaRegisterWrite examines only one level of the ancestor GEP chain. A value three or more aggregates deep receives no metadata, so the debugger shows a stale value or no value. The function also uses a member index without a bound check and without a safe cast.
The pass finds the storage of an embedded array by the name of the debug variable. DXC can flatten a multi-dimensional array and rename the module global. The debug variable keeps its name, so the lookup misses the global and every shadow store for that array is dropped.
Two decisions are worth attention. IsAllocaRegisterWrite returns false for a member index that is not constant or is out of range, because a guess would attach metadata the debug record cannot honour. A backward move of the layout writes a message and continues, and a debug build does not stop the process.
Assisted-by: Copilot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
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
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");
Virtual-register annotation attaches metadata that DXIL does not
consume, so validation of an instrumented module always reported a
generic "unused metadata" diagnostic even when the module was otherwise
correct. The prior handling matched that diagnostic by substring, which
would also swallow a genuinely unrelated unused-metadata defect.
Replace it with a structural check: on direct validation failure, clone
the module, strip only the four known PIX virtual-register metadata
kinds, and revalidate. Accept only if the stripped clone validates,
proving PIX metadata was the sole cause.
Rework Validation_ControlInvalidModuleFails so the corrupted container
itself proves both facts independently: direct validation's diagnostic
confirms the permitted PIX metadata is present and unused, and the
harness's rejection confirms a real, non-boilerplate defect remains.
Replace Validation_ControlBoilerplateOnlyFailureIsRejected, which
exercised the removed string classifier, with
Validation_ControlNonPixUnusedMetadataIsRejected: a foreign metadata
kind alongside the module's own PIX metadata must still be rejected
after the four-kind strip.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Apply the repository's almost-never-auto convention to every remaining auto introduced by the L1 original and direct-feedback commits. Use the declared Compile and RunSinglePass result types and std::string::size_type for the find result. No behavior changes.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bring the final approved L1 tip, including its formatting follow-up, into this layer while preserving the original L2 commit as the first parent.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
ExtendRootSig returns early, without appending a parameter, when a
version 1.1 root signature already holds the requested tools UAV. The
caller still unconditionally cleared Descriptor.Flags on the last
parameter in that case, which may be an unrelated, pre-existing
parameter whose flags the caller must not disturb.
Have ExtendRootSig report whether it actually appended a parameter, and
only clear flags on that path.
Add a regression test: a v1.1 root signature with the tools UAV already
present as parameter 0 and an unrelated root descriptor as parameter 1
with DataVolatile flags. Re-requesting the same register leaves
parameter 1's flags untouched; appending a genuinely new register still
leaves parameter 1 untouched and gives the new parameter None flags.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the stable, nameable auto-deduced types introduced by L2. Retain only the two DxilSubobjects MapVector ranges whose underlying pair type is implementation-dependent and obscures the loop.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use Capitalized names for the parameters and local variables added by the PIX validation harness. Remove Hungarian prefixes without changing older code in PixTest.cpp.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 819bcd16-83fc-4619-ac1a-b12ee50a2fe8
Rename the PIX validation helpers to verb phrases that start with a lowercase letter, as required by the LLVM coding standards.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 819bcd16-83fc-4619-ac1a-b12ee50a2fe8
Bring the approved L1 naming sequence forward without rewriting published L2. Resolve the single helper conflict by retaining L2's dxilemit option while using L1's renamed parameter.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rename only the C++ declarations introduced by L2 and their required references. Preserve framework test names, established LLVM abbreviations, pre-existing identifiers, and embedded HLSL fixture content.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Please use the explicit unsigned int return type here. FindOrAddSV_Position declares this short, stable type in PixPassHelpers.h:107, so auto does not meet the repository's explicit-type convention.
…st helper
- DxilDebugBreakInstrumentation: introduce an explicit FoundDebugBreak flag
instead of using the UAV resource pointer as a proxy for whether a
DebugBreak call was found. Only call ReEmitDxilResources and emit the
FoundDebugBreak marker when a DebugBreak was actually instrumented,
independent of whether unused op declarations were also erased.
- PixPassHelpers: fix typo AddUAVParamterToRootSignature ->
AddUAVParameterToRootSignature (definition and call sites).
- PixTest: refactor rootSignatureHasToolsUAV to share a single generic
lambda between the 1.0 and 1.1 root signature versions, using a named
ToolsRegisterSpace constant instead of a magic number.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The non-uniform resource index pass inserts WaveActiveAllEqual after the shader flags were computed, so the module could contain wave operations it does not declare and fail validation. Recompute the flags when the pass changes the module.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
Shader access tracking no longer records annotateHandle or barrierByMemoryHandle as accesses, still looks through annotated handles to the resource, and matches library handles against samplers so sampler accesses are recorded.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
Make RSRegisterIdentifier a strict weak ordering, report the register a binding occupies rather than its resource-list position, and fix the off-by-one range check for constant indices.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
Attribute accesses in library helper functions to the pipeline stage of the entry points that reach them instead of the Library kind, and keep instruction numbers from overflowing the 24-bit record field.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
DxilOutputColorBecomesConstant handles all storeOutput overloads (including 16-bit), gives its constant buffer a layout the validator accepts, and DxilReduceMSAAToSingleSample looks through annotateHandle and accepts 16-bit texture loads.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
Correct shadow-storage offsets for arrays, aggregate padding, bitfields and matrices; use the true span for dynamically indexed alloca writes; handle deep GEP chains safely in IsAllocaRegisterWrite; and find embedded-array storage even when DXC renames the flattened global.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Stack created with GitHub Stacks CLI • Give Feedback 💬