?/TD>
Microsoft DirectX 9.0

Shader Debugger


Microsoft?Visual Studio?.NET supports debugging assembly level and high-level language vertex and pixel shaders.

DirectX Extensions for Visual Studio .NET

The debugger works with the debug version of the runtime, as well as with certain device types. Any vertex or pixel shader can be debugged when using a reference device. Vertex shaders can be debugged, providing they are running on a hardware abstraction layer (HAL) device created for software vertex processing. No debugging support is provided for hardware vertex processing or "pure" HAL devices. For more information about device types, see D3DDEVTYPE.

Building with Debug Information

To do source-level debugging of a shader, the shader must be built with debug information and it must have an on-disk source file associated with it. You can create such a shader in the following two ways.

Starting the Debugger

To debug an application, the application must be using the debug version of the Microsoft Direct3D?runtime and must have shader debugging enabled. You can configure these options through the Direct3D tab in the Microsoft DirectX?control panel applet. The DirectX debug service must also be running on the target computer. This service is installed automatically when you install the DirectX extensions for Visual Studio .NET.

There are two ways to start the debugger:

  1. Clicking Debug, Direct3D, Start D3D (CTRL+ALT+F5) will start the debugger.
  2. You can "attach" to an already running Direct3D process. The easiest way to do this from Visual Studio .NET is as follows:
    • On the Debug menu, start your application with the Start Without Debugging command.
    • On the Debug menu, choose Processes to open the Processes window.
    • Choose your application from the process list and press the Attach button.
    • In the Attach to Process dialog box, select Native to debug your C++ code, and select Direct3D to debug your Direct3D code. You can debug both C++ and Direct3D code simultaneously (see Debugging C++ Code and Direct3D Code Simultaneously near the bottom of this topic).

Visual Studio .NET also supports remote debugging of Direct3D applications. To attach to a Direct3D process on a remote computer, in the Processes dialog box, enter the name of the remote computer in the Name box and then attach to the process the same as for a local process.

Breakpoints

The module window can be used to view all shaders that are currently loaded. When debugging native code, right-click on the window and choose Show Modules for All Programs to view the shaders that are loaded.

File/Line Breakpoints

To set a breakpoint in a vertex or pixel shader source file, the shader must have debug information present (see Building with Debug Information). You can set a source code breakpoint in a shader the same ways you would set a source code breakpoint in C++ source code, that is:

Function Breakpoints

Type the case-sensitive name of the shader function as the name, and set the language to D3D Shader. The function name is the name of the shader function stored in the debug information, the name of the file containing the shader, or the shader handle number preceded by the shader type (for example, VS1). The module window lists all currently loaded shaders and their names. IDirect3DDevice9::BeginScene and IDirect3DDevice9::EndScene breakpoints work as before.

Conditional Breakpoints

Any of the following types of breakpoints can have a condition, as long as the breakpoint is set to fire when the condition is true (as opposed to when the condition changes):

The expression must evaluate to a single-element bool result.

Memory Breakpoints

A memory breakpoint triggers at the first instruction of any pixel shader that is about to modify a pixel within a given rectangle. Set a memory breakpoint by going to the Memory tab in the Breakpoint dialog, selecting D3D Shader as the language, and entering a region in one of the following formats:

Assembly Code (Address) Breakpoints

Setting a breakpoint on a specific instruction of a shader does not require debug information. You can set an address breakpoint in the following ways.

BeginScene or EndScene Breakpoints

To set a breakpoint when the application you are debugging reaches IDirect3DDevice9::BeginScene or IDirect3DDevice9::EndScene, select the New Breakpoint command (CTRL+B by default), select the Function tab, select Direct3D Shader from the Language combo box, and type either BeginScene or EndScene as the name of the function.

Stepping

You can step through shader code using the Debug menu's Step Over command (F10 by default). Stepping in Direct3D code will cause the application you are debugging to stop at the next vertex or pixel shader instruction it runs.

Expression Evaluation

When the application you are debugging is stopped in a vertex or pixel shader, or at a BeginScene or EndScene breakpoint, you can use the Watch window to inspect the state of the application you are debugging. You can also quickly view the contents of a register by briefly resting the mouse pointer on the register in the Disassembly window or in your shader source code.

The expression syntax supports register names, swizzles, and the following operators, which all operate per component.

+ - * / == != < <= > >= [] ! || &&

In addition, the following two intrinsic functions are supported.

All types must match exactly. Floating-point literals must have a decimal point; otherwise, they are treated as integers.

Examples

This expression returns true if all of the first three components of r0 are less than the corresponding components of c4.

all( r0.xyz < c4.xyz )

Constant register are indexed by one plus the x-component of a0.

c[a0.x+1]

Viewing Register Contents

To view the contents of a register in the watch window, use the following expression syntax.

registerName[.swizzle][,format][,w]

Where:

Viewing Device State

To view the current values of render states and texture stage states on the device, enter $DeviceState in the Watch window.

Viewing the Current Pixel Position

The coordinates of the pixel currently being rendered by a pixel shader are contained in register vPos.

Viewing Surface Contents

Viewing the render target - To view the contents of the current render target surface, open the Render Target window by selecting the Debug menu's Direct3D, Render Target menu options. This window will be updated with the current contents of the render target whenever the application you are debugging enters "break" mode.

Viewing textures - To view the contents of the texture currently selected into a texture stage, open a Texture window by selecting the appropriate texture stage from the Debug menu's Direct3D, Textures menu. The texture windows will be updated with the current contents of the corresponding texture stage whenever the application you are debugging enters "break" mode.

If the contents of a surface (either the render target or a texture) are not available, the surface's window will show the text as "Unavailable." Possible reasons for a surface being unavailable include:

Debugging C++ Code and Direct3D Code Simultaneously

The Visual Studio .NET debugger supports debugging of multiple program types at the same time. Typical C++ debugging uses the "Native" program type. Direct3D debugging uses the "Direct3D" program type. When the application you are debugging stops in C++ code, the current program will be set to Native, and the call stack, watch window, and other debug windows will reflect the state of the Native program. Similarly, when the application you are debugging stops in shader code, the current program will be set to Direct3D, and the debug windows will reflect the state of the Direct3D program. To switch between program types, use the Program combo box on the Debug Location toolbar. Note that when the application you are debugging is stopped in Native code, most of the state of the Direct3D program will be unavailable. The reverse is not true, however. If you stop at a breakpoint in a shader, for example, you can switch to the Native program and see the C++ call stack that caused your shader to be invoked.

For more information about debugging multiple program types simultaneously, see "Debugging Multiple Programs" in the Visual Studio .NET documentation.

Debugging Without Debug Information

If possible, build your shaders with debug information enabled (see Building with Debug Information). In cases where building with debug information is not feasible, such as for shaders that are built up "on the fly," debugging is possible but is much more difficult. Source code is not available, so source code breakpoints don't work. One approach to debugging without debug information is to set a BeginScene breakpoint, and when that breakpoint is reached, step into the shader code of the first shader run by pressing F10. Once you're stepping through disassembly code, you can set breakpoints in the Disassembly window. You can also use the Modules window to view the names of all shaders currently loaded and selectively set breakpoints on them as needed.

Another approach is to set a breakpoint in your C++ code immediately before calling IDirect3DDevice9::DrawPrimitive or IDirect3DDevice9::DrawIndexedPrimitive. When this breakpoint is reached, you can then set an address breakpoint using the current shader handle and then run until that breakpoint is reached.



© 2002 Microsoft Corporation. All rights reserved.