Skip to content

Add 'IsDebuggerPresent' and detail DebugBreak more#752

Merged
JoeCitizen merged 3 commits into
microsoft:mainfrom
JoeCitizen:user/jackell/debug-break
Jan 6, 2026
Merged

Add 'IsDebuggerPresent' and detail DebugBreak more#752
JoeCitizen merged 3 commits into
microsoft:mainfrom
JoeCitizen:user/jackell/debug-break

Conversation

@JoeCitizen
Copy link
Copy Markdown
Collaborator

@JoeCitizen JoeCitizen commented Dec 4, 2025

HLSL Debugging Intrinsics

  • Broadened Proposal Scope: The proposal now covers two new debugging intrinsics:

    • DebugBreak(): Triggers a breakpoint when a debugger is attached.
    • dx::IsDebuggerPresent(): Returns whether a graphics debugger is currently attached (DirectX only).
  • Motivation Expanded: Highlights the need for conditional debug checks and selective breakpoints, allowing shader authors to perform expensive debugging operations only when needed.

  • Detailed API & Usage Examples:

    • Provides updated HLSL signatures and usage snippets for both intrinsics.
    • Demonstrates conditional execution of validation code based on debugger presence.
  • Implementation Details Added:

    • Specifies DXIL lowering for both intrinsics (dx.op.debugBreak, dx.op.isDebuggerPresent).
    • Clarifies convergence requirements to prevent optimizations that might move breakpoints.
    • Notes that both intrinsics are only valid in Shader Model 6.10+.
    • Explains runtime and driver behavior.
  • SPIR-V Targeting:

    • Outlines use of NonSemantic.DebugBreak for DebugBreak() in SPIR-V.
    • Specifies that dx::IsDebuggerPresent() has no SPIR-V equivalent.
  • Testing Section: Introduces compiler, validation, and execution testing requirements to ensure correct integration and behavior.

Copy link
Copy Markdown
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

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

I think we need to work on the abort semantics (comment inline).

Comment thread proposals/0039-debugbreak.md Outdated
- Trigger a debugger break before termination (implementation-defined)

The exact behavior is implementation-defined, but the shader must not continue
execution past this point. This matches the semantics of C's `abort()` function.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think that a proper abort should force termination of the thread immediately, and should be specified to terminate all threads in a dispatch "eventually". The tricky thing about "eventually" being that it would be legal to terminate the thread that calls abort and allow all other threads to terminate naturally by completing execution.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

At the language level terminating the thread (wave?) is about all we can do right? What happens after that is a runtime issue? i.e. if it should always result in a TDR for example.

Comment thread proposals/0039-debugbreak.md Outdated

```hlsl
void DebugBreak(); // Trigger a breakpoint if debugger attached
void Abort(); // Terminate execution abnormally
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

While most HLSL functions are CamelCase the ones that have direct C equivalents (like the math functions) we tend to match the C spellings. So I think abort() would be preferable.

@tex3d thoughts?

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.

FastFail might be alternative as well. I don't think that the actual semantics we'll end up with will really exactly match those of C's abort().

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It would be nice if we can repurpose the existing FXC abort since it matches the C function in name at least

Comment thread proposals/0039-debugbreak.md Outdated
4. **Per-Pipeline Control**: Enable assertions only for specific shaders that
are suspected of containing bugs, minimizing performance impact.

#### Backend Compiler Optimization
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this should ever be allowed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For some more context, we've gotten feedback from game developers that it'll be nice to have a way to enable and disable asserts/aborts at PSO creation time so that they can enable validation without needing to recompile all their shaders. That way, they can ship with aborts in their shader disabled by default, and if they see a spike in GPU crashes they can temporarily enable the aborts for a small percentage of users and trigger a dump or additional logging for offline analysis

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure that complexity is warranted at the DXIL level. A root constant could be used to enable or disable custom assert macros if a specific software vendor needs such a case. Ideally this is a use case for specialization constants, but since we don't have those in DXIL it isn't really viable, but increasing the complexity and testing matrix for a DXIL operation by allowing it to behave differently under different runtime state is sub-optimal and should be avoided.

There are additional reasons why I'm opposed to this which cannot be discussed publicly at this time, but I'm happy to discuss privately.

Comment thread proposals/0039-debugbreak.md Outdated
### D3D12 Runtime Behavior for Abort

The SPIRV usage will utilize the following instructions:
#### Default Behavior: Abort as No-Op
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Per my other comment, I'm pretty strongly opposed to this being allowed.

@JoeCitizen JoeCitizen changed the title Add 'Abort' and 'IsDebuggerPresent' to Debug Break proposal Add 'IsDebuggerPresent' and D3D12 Pipeline flags to Debug Break proposal Dec 15, 2025
Comment thread proposals/0039-debugbreak.md Outdated
The value returned is uniform across all threads in a dispatch/draw and remains
constant for the duration of shader execution.

#### Enabling Semi-Optimized Development Builds
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't know that this section really needs to be here. HLSL specs aren't user documentation, they're for compiler authors to implement language features.

Comment thread proposals/0039-debugbreak.md Outdated
#### `IsDebuggerPresent()`

```hlsl
bool IsDebuggerPresent();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This will need to be in the dx namespace as there is no Vulkan equivalent that we can lower to for SPIRV generation.

Comment thread proposals/0039-debugbreak.md Outdated
no debugger is present, they are required supported features and do not require
capability bits.

### D3D12 Runtime Behavior for DebugBreak
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would prefer to remove D3D-focused language from the HLSL specifications. This isn't where we want users looking for documentation.

Comment thread proposals/0039-debugbreak.md Outdated
- Lower to a specialization constant that can be set by the debugger
- Use a vendor-specific extension
- Return a conservative value (e.g., always `false` in release, always `true`
in debug builds)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I commented this above, but it seems more appropriate that we put this function in the dx namespace and make it unavailable to Vulkan targets if it has no lowering. There is no vendor extension equivalent that I'm aware of, and using a specialization constant isn't really something the compiler can just do it would require user involvement.

Comment thread proposals/0039-debugbreak.md Outdated
By default, when no debugger is attached, `DebugBreak()` is treated as a no-op
i.e the `dx.op.debugBreak` operation has no effect at runtime.

The allows for driver back end compilers to optimize away these instructions
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The D3D spec currently has the default as no-op such that the backend compiler can optimize away instructions that lead up to the debug break and even if a debugger was attached after PSO creation the debugbreak would still be a no-op, we still want the three debugbreak configuration options (no-op, debugbreak if debugger else no-op, and abort/trigger TDR), is that right?

@JoeCitizen JoeCitizen changed the title Add 'IsDebuggerPresent' and D3D12 Pipeline flags to Debug Break proposal Add 'IsDebuggerPresent' and detail DebugBreak more Jan 6, 2026
@JoeCitizen JoeCitizen merged commit e0faf63 into microsoft:main Jan 6, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this to Triaged in HLSL Triage Jan 6, 2026
void main(uint GI : SV_GroupIndex) {
assert(GI < 8);
// Conditional expensive debug checks
if (dx::IsDebuggerPresent()) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit:

Suggested change
if (dx::IsDebuggerPresent()) {
if (dx::IsDebuggerPresent()) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Triaged

Development

Successfully merging this pull request may close these issues.

5 participants