Skip to content

Debugging wgpu Applications

gmorenz edited this page Apr 4, 2022 · 23 revisions

This page describes all the tricks and tools aimed at investigating issues related to wgpu.

Native API Validation

wgpu's goal is to guarantee that only valid workloads reach the low-level APIs under the hood. If anything is not correct, we are going to complain about it. You should never need to listen to the low-level API complains.

This is a big work-in-progress, however. So in the meantime, it's useful to hear what the low-level validation has to say.

Vulkan and OpenGL

On Khronos APIs we redirect all the validation output to the console. You will see it as long as:

  1. you run a debug build
  2. you have the validation layers installed (i.e. LunarG SDK)
  3. you capture logging (with something like env_logger)

D3D

See https://github.com/gfx-rs/gfx/wiki/Debugging-D3D

Metal

You can either set METAL_DEVICE_WRAPPER_TYPE=1 in the environment, or launch from XCode, where validation options are configurable in project menus (and enabled by default). To launch from XCode, you can create a project of "External Build System" type, picking cargo or any other command as the build system. Then you'd need to edit the target configuration and select the executable.

A full guide that explains how to launch from Xcode is available in Debugging with Xcode.

GPU Debugging

If the validation is clean, and you are getting incorrect rendering or computing, it's time to dive into GPU debugging. Many tools exist today:

  • RenderDoc can be used on Windows and Linux to capture Vulkan, D3D, and OpenGL.
  • PIX can be used on Windows to capture D3D12
  • XCode has powerful Metal GPU capture support with full shader debugging.

In order to run your application from XCode, you can create an empty project, select your executable binary, and provide the command line parameters in the project settings.

CPU Debugging

As wgpu is a Rust project, all the regular methods of debugging would work. It's convenient to launch an application from XCode (e.g. as an "External build system" type project), or Visual Studio (just go to "Open Project" and select the executable, adjust the path and parameters).

When looking at a crash/panic, first step is typically enabling RUST_BACKTRACE=1 in the environment. This will spew out the stack trace, which helps you to locate the problem.

Rubber Duck Debugging

Hop on to "#wgpu:matrix.org" and try to explain what happens and why. Maybe we listen. Maybe you'll figure out the answer by then ;)

Tracing Infrastructure

API tracing is built into wgpu-core under the "trace" feature. To record a trace through wgpu-rs, first make sure this feature is enabled (in wgpu-rs).

There is a trace_path optional parameter in wgpu::Adapter::request_device (code). When it's set to an existing folder path, the device will be recording a trace of everything that's going on, to this folder.

Once the trace is recorded, you can zip the folder and attach it to an issue. This should allow anyone, including the developers, to reproduce the issue on their machines, using the player:

cd player
cargo run --features winit -- <trace_folder_path>

Read more at initial PR.

Running in Gecko

If you encounter a problem with something that runs fine outside of Gecko but fails to run in Gecko, there is a way to trace the API use by the browser. Simply run Firefox Nightly (with prefs enabled for WebGPU, obviously) under WGPU_TRACE environment pointing to a writable folder, and it will record the API trace. This trace can be replayed as usual, or even compared to a trace you can get by running the same application natively, to find out what the browser doesn't do right.

To replay a capture from Firefox and inspect it in renderdoc or similar tools, it is best not to build the player with the "winit" cargo feature.

When Firefox renders a WebGPU canvas, the result is done in a texture rather than a window's swap chain, and that texture is then shared and put into the screen via other means that aren't part of the wgpu trace. Since there is no window swap chain involved, renderdoc can't guess when a frame starts and ends, so it has to be helped by manually inserting begin/end capture markers. When built without the winit feature, the player replays the commands without rendering them into window, the player adds these markers at the begining and end of the trace whereas it doesn't when the winit feature is enabled since it assumes the trace will eventually render into the winit window's swapchain.

This applies to Firefox as well as any other software using wgpu to render content into a texture but not to present that texture into a window.