wgpu/documentation/debugging/
debugging_applications.rs

1/*!
2# Debugging wgpu Applications
3
4This page describes the tricks and tools aimed at investigating issues
5related to `wgpu`.
6
7## Native API validation
8
9`wgpu`'s goal is to guarantee that only valid workloads reach the low-level
10APIs under the hood. If anything is not correct, we are going to complain
11about it. You should never need to listen to the low-level API's complaints.
12
13This is a big [work-in-progress](https://github.com/gfx-rs/wgpu/labels/area%3A%20validation),
14however. So in the meantime, it's useful to hear what the low-level
15validation has to say.
16
17### Vulkan and OpenGL
18
19On Khronos APIs we redirect all the validation output to the console. You
20will see it as long as:
21
221. you run a debug build,
232. you have the validation layers installed (i.e. the LunarG SDK), and
243. you capture logging (with something like
25   [`env_logger`](https://crates.io/crates/env_logger)).
26
27To enable the validation layers in non-debug builds, manually turn on
28validation in the [`InstanceDescriptor`] with [`InstanceFlags::VALIDATION`].
29See also [Enabling Vulkan Validation Layers](crate::documentation::debugging::vulkan_validation_layers).
30
31### D3D
32
33#### COM
34
35The refcount of a COM object is 9 32-bit words behind the pointer's
36destination and is 4 bytes. As such, subtract 36 from the pointer's address
37to get a pointer to that object's refcount. This allows you to use data
38breakpoints to see all changes to the object's refcount, useful for
39detecting leaks and other such things.
40
41### Metal
42
43You can either set `METAL_DEVICE_WRAPPER_TYPE=1` in the environment, or
44launch from Xcode, where validation options are configurable in the project
45menus (and enabled by default). To launch from Xcode, you can create a
46project of "External Build System" type, picking `cargo` or any other
47command as the build system. Then you'd need to edit the target
48configuration and select the executable.
49
50A full guide that explains how to launch from Xcode is available in
51[Debugging with Xcode](crate::documentation::debugging::xcode).
52
53#### Mac leaks
54
55To look for leaks using "Instruments", you need to add a special entitlement
56to your executable's signature. Write the following to `entitle.xml`:
57
58```xml
59<?xml version="1.0" encoding="UTF-8"?>
60<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
61<plist version="1.0">
62    <dict>
63        <key>com.apple.security.get-task-allow</key>
64        <true/>
65    </dict>
66</plist>
67```
68
69Then run `codesign -s - -v -f --entitlements=entitle.xml /path/to/my/app`.
70
71([Source](https://stackoverflow.com/questions/74262518/why-required-kernel-recording-resources-are-in-use-by-another-document-error-i).)
72
73## GPU debugging
74
75If the validation is clean, and you are getting incorrect rendering or
76computing, it's time to dive into GPU debugging. Many tools exist today:
77
78- RenderDoc can be used on Windows and Linux to capture Vulkan, D3D, and
79  OpenGL.
80  - If RenderDoc is used with a compute shader without any normal rendering
81    components, wrap the work in [`Device::start_graphics_debugger_capture`]
82    and [`Device::stop_graphics_debugger_capture`] so RenderDoc picks up the
83    pipeline.
84  - Vulkan initialization may fail in RenderDoc under Wayland (see
85    [issue 3889](https://github.com/gfx-rs/wgpu/issues/3889)). To work around
86    it, force winit to use X11 by setting the `WAYLAND_DISPLAY` environment
87    variable to an empty string for winit versions `0.28.2` and onward, or
88    the `WINIT_UNIX_BACKEND` environment variable to `"x11"` for winit
89    versions up to `0.29.1`. When in doubt, do both.
90- PIX can be used on Windows to capture D3D12.
91- Xcode has powerful Metal GPU capture support with full shader debugging.
92
93In order to run your application from Xcode, you can create an empty project,
94select your executable binary, and provide the command-line parameters in
95the project settings.
96
97### Capturing WebGPU in Chrome with PIX
98
99<https://gist.github.com/Popov72/41f71cbf8d55f2cb8cae93f439eee347>
100
101### Capturing WebGPU in Chrome with Xcode
102
103<https://ced.quest/chromium-metal-debugger.html>
104
105## CPU debugging
106
107As `wgpu` is a Rust project, all the regular methods of debugging work. It's
108convenient to launch an application from Xcode (e.g. as an "External Build
109System" type project), or Visual Studio (just go to "Open Project" and
110select the executable, adjusting the path and parameters).
111
112When looking at a crash/panic, the first step is typically enabling
113`RUST_BACKTRACE=1` in the environment. This will spew out the stack trace,
114which helps you locate the problem.
115
116## Rubber-duck debugging
117
118Hop on to [`#wgpu:matrix.org`](https://matrix.to/#/#wgpu:matrix.org) and try
119to explain what happens and why. Maybe we listen. Maybe you'll figure out
120the answer by then ;)
121
122## Tracing infrastructure
123
124API tracing is built into `wgpu-core` under the `trace` feature. To record a
125trace, first make sure this feature is enabled, then set the `trace` field
126of the [`DeviceDescriptor`] to [`Trace::Directory`](crate::Trace) with an existing folder
127path when calling [`Adapter::request_device`]. The device will then record a
128trace of everything that's going on to that folder.
129
130Once the trace is recorded, you can zip the folder and attach it to an
131issue. This should allow anyone, including the developers, to reproduce the
132issue on their machines, using the `player`:
133
134```bash
135cd player
136cargo run --features winit -- <trace_folder_path>
137```
138
139If the program crashed or was interrupted in the midst of recording, you may
140need to edit the trace folder's `trace.ron` file and add a closing `]`
141bracket to the end. When that bracket is missing, the player exits with a
142message like:
143
144```text
145thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:
146Error { code: Eof, position: Position { line: 96233, col: 1 } }', player/src/bin/play.rs:28:70
147```
148
149### Running in Gecko
150
151If you encounter a problem with something that runs fine outside of Gecko
152but fails to run in Gecko, there is a way to trace the API use by the
153browser. Simply run Firefox Nightly (with prefs enabled for WebGPU,
154obviously) under `WGPU_TRACE` pointing to a writable folder, and it will
155record the API trace. Setting `MOZ_DISABLE_GPU_SANDBOX=1` might also be
156required if the GPU process is sandboxed by default. This trace can be
157replayed as usual, or even compared to a trace you get by running the same
158application natively, to find out what the browser doesn't do right.
159
160To replay a capture from Firefox and inspect it in RenderDoc or similar
161tools, it is best not to build the player with the `winit` cargo feature.
162
163When Firefox renders a WebGPU canvas, the result is done in a texture rather
164than a window's swapchain, and that texture is then shared and put onto the
165screen via other means that aren't part of the `wgpu` trace. Since there is
166no window swapchain involved, RenderDoc can't guess when a frame starts and
167ends, so it has to be helped by manually inserting begin/end capture
168markers. When built without the `winit` feature, the player replays the
169commands without rendering them into a window, and adds these markers at the
170beginning and end of the trace; it doesn't when the `winit` feature is
171enabled, since it then assumes the trace will eventually render into the
172winit window's swapchain.
173
174This applies to Firefox as well as any other software using `wgpu` to render
175content into a texture but not to present that texture into a window.
176*/
177
178use crate::{Adapter, Device, DeviceDescriptor, InstanceDescriptor, InstanceFlags, Trace};