HLSL Debugging

The HLSL debugger, which is one of the Graphics Diagnostics tools in Visual Studio, can help you understand how your HLSL shader code operates with graphics data that was recorded during a Graphics Diagnostics capture session.

This is the HLSL Debugger:

Debugging HLSL using watch and call stack windows.

Understanding the HLSL Debugger

The HLSL Debugger can help you understand problems that arise in your shader code. Debugging HLSL code in Visual Studio resembles debugging code written in other languages—for example, C++, C#, or Visual Basic. You can inspect the contents of variables, set break points, step through code, and walk up the call-stack, just like you can when you debug other languages.

However, because CPU hardware and software (app code) is so different from GPU hardware and software (shader code), a CPU-like debugging experience is not possible on a GPU unless the GPU debugger works in a fundamentally different way. The fundamental difference between the kinds of work that GPUs and CPUs do is that GPUs spread the work across hundreds of relatively slow, simple processors that are optimized for graphics operations to handle very large data sets, but CPUs use a handful of relatively fast, complicated processors that can handle smaller, general-purpose workloads. Also, because a GPU is essentially an independent computer that manages its own internal workings and only infrequently shares information with the CPU, it's very difficult for a debugger that's running on the CPU to know what's happening on the GPU at any given time. Even if a CPU could keep up, GPU code just uses too many threads and generates too much data for a developer to sift through.

To work around these difficulties, the HLSL Debugger recreates captured frames by using information that was recorded in a graphics log, rather than attempting to monitor a GPU in real time as it runs shader code. Because a graphics log contains enough information to recreate any part of the output, and because Graphics Diagnostics provides tools that can help you pinpoint the exact pixel and event where an error occurs, the HLSL Debugger only has to simulate the exact shader thread that you are interested in. This means that the work of the shader can be simulated on the CPU, where its inner workings are in full view. This is what gives the HLSL Debugger a CPU-like debugging experience.

However, the HLSL debugger is currently limited in the following ways:

  • The HLSL Debugger doesn't support edit-and-continue.

  • It's not possible to debug an app and its shader code at the same time. However, you can alternate between them.

  • You can add variables and registers to the Watch window, but expressions are not supported.

  • Compute shaders are not supported.

Nevertheless, the HLSL Debugger provides a better, more CPU-like debugging experience than would be possible otherwise.

Debugging HLSL code

The HLSL debugger can be accessed from the Graphics Pipeline Stages window or Graphics Pixel History.

To start the HLSL debugger from the Graphics Pipeline Stages window

  1. In the Graphics Pipeline Stages window, locate the pipeline stage that's associated with the shader that you want to debug.

  2. Below the title of the pipeline stage, choose Start Debugging, which appears as a small green arrow.

    Note

    This entry point into the HLSL debugger debugs only the first shader thread for the corresponding stagethat is, the first vertex, primitive, or pixel that is processed. Other threads of these shader stages can be accessed by using the Graphics Pixel History.

To start the HLSL debugger from the Graphics Pixel History

  1. In the Graphics Pixel History, locate the draw call that's associated with the shader that you want to debug and expand it so that its details are displayed. Each draw call can correspond to multiple primitives.

  2. In the draw call details, locate a primitive whose resulting color contribution suggests a bug in its shader code and expand it so that its details are displayed. If multiple primitives suggest a bug, choose the first primitive that suggests it in order to avoid an accumulation of errors that can make diagnosis of the problem more difficult.

  3. In the primitive details, choose whether to debug the Vertex Shader or Pixel Shader. Debug the vertex shader when you suspect that the pixel shader is correct, but is generating an incorrect color contribution as a result of incorrect constants passed to it by the vertex shader. Otherwise, debug the pixel shader.

    To the right of the chosen shader, choose Start Debugging, which appears as a small green arrow.

    Note

    This entry point into the HLSL debugger debugs either the pixel shader thread that corresponds to the chosen draw call, primitive, and pixel that you have chosen, or to the vertex shader threads whose results are interpolated by the draw call, primitive, and pixel that you have chosen. In the case of vertex shaders, you can further refine the entry point to a specific vertex by expanding the vertex shader details.

For complete examples on how to debug shader errors by using the HLSL Debugger, see Graphics Diagnostics Examples or the walkthroughs linked in the See Also section below.

See Also

Tasks

Walkthrough: Missing Objects Due to Vertex Shading

Walkthrough: Debugging Rendering Errors Due to Shading