1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
<!-- markdownlint-disable MD041 -->
<!-- Copyright 2020-2025 LunarG, Inc. -->
<!-- Copyright 2020-2025 Valve Corporation -->
[![Khronos Vulkan][1]][2]
[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
[2]: https://www.khronos.org/vulkan/
# Using Debug Printf
## Introduction
Debugging Vulkan shaders, especially compute shaders, can be very difficult to do even with the aid
of a powerful debugging tool like RenderDoc. Debug Printf is a recent Vulkan feature that allows
developers to debug their shaders by inserting Debug Print statements. This feature is now
supported within RenderDoc in a way that allows for per-invocation inspection of values in a shader.
This article describes how to instrument your GLSL or HLSL shaders with Debug Printf and how to
inspect and debug with them in RenderDoc, using vkconfig, or with environment variables.
## Turning on Debug Printf in Validation Layer
We suggest to use Vulkan Configurator (`VkConfig`) to enable Debug Printf
For those who "just need to quick use it" there is a `VK_LAYER_PRINTF_ONLY_PRESET` environment variable that will turn on Debug Printf and turn off all of the other validation logic.
```bash
# Windows
set VK_LAYER_PRINTF_ONLY_PRESET=1
# Linux
export VK_LAYER_PRINTF_ONLY_PRESET=1
# Android
adb setprop debug.vulkan.khronos_validation.printf_only_preset=1
```
## Settings
The following are the various Debug Printf settings (listed as environment variables, but work like all other settings).
> All settings also found in `VkConfig`
- `VK_LAYER_PRINTF_ENABLE` will turn on Debug Printf alongside the other validation
- `VK_LAYER_PRINTF_ENABLE=1` turn on
- `VK_LAYER_PRINTF_TO_STDOUT` will print to `stdout` **instead** of the normal Debug Callback
- `VK_LAYER_PRINTF_TO_STDOUT=1` turn on
- `VK_LAYER_PRINTF_VERBOSE` will print extra information (pipeline, shader, command, etc)
- `VK_LAYER_PRINTF_VERBOSE=1` turn on
- `VK_LAYER_PRINTF_BUFFER_SIZE` size of the buffer used to store Printf messages (buffer is shared across all calls in a single `vkQueueSubmit`).
- Default: 1024 bytes
- `set VK_LAYER_PRINTF_BUFFER_SIZE=4096` (example of making it larger)
## Using Debug Printf in GLSL Shaders
To use Debug Printf in GLSL shaders, you need to enable the `GL_EXT_debug_printf` extension.
Then add `debugPrintfEXT()` calls at the locations in your shader where you want to print
messages and/or values
Here is a very simple example ([Try Online](https://godbolt.org/z/MnYGj8azM)):
```glsl
#version 450
#extension GL_EXT_debug_printf : enable
void main() {
float myfloat = 3.1415f;
debugPrintfEXT("My float is %f", myfloat);
}
```
`glslang` will automatically add the Debug Printf instructions
## Using Debug Printf in HLSL and Slang Shaders
In HLSL and Slang, Debug Printf can be invoked as follows ([Try Online](https://godbolt.org/z/3ThznsdK8)):
```glsl
void main() {
float myfloat = 3.1415;
printf("My float is %f", myfloat);
}
```
Both `dxc` and `slangc` will automatically add the Debug Printf instructions
## Recommendations
If you print every time a shader is executed you can easily get millions of things trying to print. It is recommended to use built-ins to limit what is printed
```glsl
// Vertex Shader
if (gl_VertexIndex == 0) {
debugPrintfEXT("Only print for a single vertex shader invocation\n");
}
// Fragment Shader
if (gl_FragCoord.x > 0.0 && gl_FragCoord.x < 0.1 &&
gl_FragCoord.y > 0.0 && gl_FragCoord.y < 0.1) {
debugPrintfEXT("Only print for a few fragment shader invocation\n");
}
// Compute Shader
if (gl_LocalInvocationIndex == 0) {
debugPrintfEXT("Only print for a single compute invocation\n");
}
```
## Debug Printf Output
Debug Printf error message are returned as `VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT`
For your custom callback, you can look for `0x4fe1fef9` in `VkDebugUtilsMessengerCallbackDataEXT::messageIdNumber` as the magic hash if it is a Debug Printf message
The Validation Layers will try to turn on `info` level messages when using Debug Printf so the message is found
The `VkDebugUtilsMessengerCallbackDataEXT::pMessage` will contain the location and on a newline print out the error message such as:
> vkQueueSubmit(): pSubmits[0] Debug Printf:
>
> x == 100
### Debug Printf Format String
The format string for this implementation of debug printf is more restricted than the traditional printf format string.
Format for specifier is "%"*precision* <d, i, o, u, x, X, a, A, e, E, f, F, g, G, ul, lu, or lx>
Format for vector specifier is "%"*precision*"v" [2, 3, or 4] [specifiers list above]
Format for pointers (`PhysicalStorageBuffer`) is "%p"
- The vector value separator is ", "
- "%%" will print as "%"
- No length modifiers. Everything except ul, lu, and lx is 32 bits, and ul and lx values are printed in hex
- No strings or characters allowed
- No flags or width specifications allowed
- No error checking for invalid format strings is done.
For example:
```
float myfloat = 3.1415f;
vec4 floatvec = vec4(1.2f, 2.2f, 3.2f, 4.2f);
uint64_t bigvar = 0x2000000000000001ul;
```
`debugPrintfEXT("Here's a float value to 2 decimals %1.2f", myfloat);`
Would print **"Here's a float value to 2 decimals 3.14"**
`debugPrintfEXT("Here's a vector of floats %1.2v4f", floatvec);`
Would print **"Here's a vector of floats 1.20, 2.20, 3.20, 4.20"**
`debugPrintfEXT("Unsigned long as decimal %lu and as hex 0x%lx", bigvar, bigvar);`
Would print **"Unsigned long as decimal 2305843009213693953 and as hex 0x2000000000000001"**
## Debug Printf messages in RenderDoc
As of RenderDoc release 1.14, Debug Printf statements can be added to shaders, and debug
printf messages will be received and logged in the Event Browser window.
Using the debugmarker sample from Sascha Willems' Vulkan samples repository:
1. Capture a frame:

2. Edit the shader:
- Add `#extension GL_EXT_debug_printf : enable` to beginning of shader
- Add `debugPrintfEXT("Position = %v4f", pos);` to shader after pos definition
- Hit Refresh

The vkCmdDrawIndexed in question now has 51 messages.
3. Click on msg(s) to see Debug Printf output per draw:

## Using Debug Printf in SPIR-V Shaders
Normally, developers will use a high-level language like HLSL or GLSL to generate SPIR-V.
However, in some cases, developers may wish to insert Debug Printfs directly into SPIR-V
To execute Debug Printf in a SPIR-V shader, a developer will need the following two
instructions specified:
```
OpExtension "SPV_KHR_non_semantic_info"
%N0 = OpExtInstImport NonSemantic.DebugPrintf
```
Debug Printf operations can then be specified in any function with the following instruction:
`%NN = OpExtInst %void %N0 1 %N1 %N2 %N3` ...
where:
* `N0` is the result id of the `OpExtInstImport NonSemantic.DebugPrintf`
* `1` is the opcode of the Debug Printf instruction in `NonSemantic.DebugPrintf`
* `N1` is the result of an OpString containing the format for the Debug Printf
* `N2`, `N3`, ... are result ids of scalar and vector values to be printed
* `NN` is the result id of the Debug Printf operation. This value is undefined.
> `OpExtInstImport` of any `NonSemantic*` is properly supported with the `VK_KHR_shader_non_semantic_info` device extension. Some older compiler stacks might not handle these unknown instructions well, some will ignore it as desired.
## Debug Printf messages from Validation Layers via VkConfig (Vulkan Configurator)
Here's an example of adding a Debug Printf statement to the shader in the `vkcube` demo (from
the `Vulkan-Tools` repository), and then using `VkConfig` to enable Debug Printf, launch vkcube,
and see the Debug Printf output.
1. Add Debug Printf to the vkcube demo:
- Add `VK_KHR_shader_non_semantic_info` to cube's `CreateDevice` function
- Add extension and `debugPrintfEXT` call to the shader
- Use `glslangvalidator` to compile the new shader
- (Offscreen) Rebuild vkcube

2. Configure `VkConfig` to enable Debug Printf
- Set Shader Printf Preset
- Set the executable path to the vkcube demo and add --c 1 to the command line to render one frame
- Click the "Launch" button

3. See the Debug Printf output in Launcher window:

### Limitations
* Debug Printf consumes a descriptor set. If your application uses every last
descriptor set on the GPU, Debug Printf will not work.
* Debug Printf consumes device memory on the GPU. Large or numerous Debug Printf
messages can exhaust device memory. See settings above to control
buffer size.
* Can be controlled with `VK_LAYER_PRINTF_BUFFER_SIZE`
* Validation Layers version: `1.2.135.0` or later is required
* Vulkan API version 1.1 or greater is required
* When using Validation Layers, the `fragmentStoresAndAtomics`, `vertexPipelineStoresAndAtomics`, and `timelineSemaphore` features are required
* The `VK_KHR_shader_non_semantic_info` extension must be supported and enabled
* If using the Validation Layers, we attempt to strip it out to allow wider range of users to still use Debug Printf
* RenderDoc release 1.14 or later
* When using Debug Printf with a debug callback, it is recommended to disable validation,
as the debug level of INFO or DEBUG causes the validation layers to produce many messages
unrelated to Debug Printf, making it difficult to find the desired output.
### Other References
Documentation for the GL_EXT_debug_printf extension can be found
[here](https://github.com/KhronosGroup/GLSL/blob/main/extensions/ext/GLSL_EXT_debug_printf.txt)
There are many validation layer tests that demonstrates the simple and programmatic use of Debug
Printf. See `tests/unit/debug_printf.cpp` in the Vulkan-ValidationLayers repository.
Earlier implementations implicitly included stage specific built-in variables such as `gl_InvocationID`, `gl_VertexID` and `gl_FragCoord` in Debug Printf messages. This functionality has been removed because it made Debug Printf unusable in shader modules that defined entry points for multiple pipeline stages. If necessary, you can add these values to your printf statements explicitly. However, you must then make sure that the printf statement can only be executed from a pipeline stage where the built-in variable is available.
|