GPU profiling for WebGPU workloads on Windows with Chrome
Update (2026-05-26): The
d3d12_webgpu_shimrepository has been updated. The old method of placingd3d12.dlldirectly in Chrome’s application folder is now deprecated, as Chrome has restricted custom DLL loading. The recommended approach now uses a launcher executable (webgpu_profiling_launcher.exe) that injects the hook DLL at runtime. The instructions below have been updated accordingly.
Fast Forward
If you’d like to see native GPU profiler support in Chrome, consider upvoting the following Chromium issue.
If you’ve read the article already and/or want to jump straight to profiling, go to the TL;DR section.
Context
WebGPU is not a native graphics API, as in no hardware vendor provides specific drivers for their GPUs targeting this API. Instead, WebGPU runtimes like web browsers must implement backends for WebGPU using modern native APIs such as DirectX12, Vulkan or Metal. Those APIs are widely used, in particular for video games, and hardware vendors have developed great profiling tools for them.
Sadly those GPU profilers don’t work out of the box with WebGPU workloads executed by Chrome. The main reason for this is that while Chrome does execute such workloads using the aformentioned graphics APIs, it doesn’t present the rendered content on screen using those APIs. There are good reasons for this and the technical details are not important here, the point is GPU profilers wouldn’t work and it made me sad.
The good news is I found a way to work around that limitation! It’s a terrible hack but in practice it works well. All you need to do is download a DLL I wrote and put it in the correct location to get both AMD’s Radeon GPU Profiler and Nvidia’s Nsight to work! See the details in the next section. Also, while this only works on Windows I have seen this gist floating around for Apple, but I have nothing for Linux :/.
If you are interested in what was missing, how I fixed it and what this mysterious DLL is doing, please read the following companion blog post Shimming d3d12.dll for fun and profit. I would also like to thank Marco Castorina and Ray Dey without whom this hack probably wouldn’t exist :).
How to use
⚠ Before anything else, please remember that this is a hacky solution and that you should not browse the open web with these tools attached. They should only be used for a GPU profiling session.
Getting the tools
Go to the following repository and download webgpu_profiling_launcher.exe and d3d12_webgpu_hook.dll from the release section, or clone the repository and build it yourself:
git clone https://github.com/frguthmann/d3d12_webgpu_shim.git
cd d3d12_webgpu_shim
cmake -S . -B build
cmake --build build --config RelWithDebInfo
Outputs will appear in build\RelWithDebInfo\. Unlike the old approach, you no longer need to place any DLL inside Chrome’s installation folder.
Chrome command line arguments
The way you should launch Chrome depends on the profiler you will be using. However, the command line arguments required are mostly the same as the ones used to capture a frame with PIX as described in Tojiro’s blog.
For reference, here are the arguments I use:
--disable-gpu-sandbox --disable-gpu-watchdog--enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming--no-sandbox--disable-direct-composition--do-not-de-elevate
The first arguments are the minimum required to capture a frame. The second ones are convenience arguments that let you inspect shader source with the original variable names. The third one is required by Nvidia Nsight to function properly, I have no idea why. The last argument used to be required to capture Chrome with PIX so I keep it around just in case.
Enabling debug markers
To enable debug markers, we’ll again refer to Tojiro’s blog. The gist of it is to copy WinPixEventRuntime.dll from https://www.nuget.org/packages/WinPixEventRuntime into <Chrome Dir>\<Version Number>.
Unfortunately, the Radeon tools don’t support PIX markers out of the box. No problem, I wrote a modified version of WinPixEventRuntime.dll that is supported by the Radeon tools. This DLL is hardware vendor agnostic and will only enhance the PIX markers on AMD hardware. The process to get it is exactly the same as getting the modified d3d12.dll. Simply go the following repository and either download WinPixEventRuntime.dll from the release section or clone the repository and build it yourself.
Capturing a frame with RDP
To profile with AMD’s Radeong GPU Profiler, you need to download the Radeon Developer Tool Suite from GPUOpen. Download the package and unzip it at any location you see fit, all the apps are portable.
Double-click on the Radeon Developer Panel’s exe to start it. If this is the first time you’re using it, you will likely need to select a feature you would like to use from the top left corner. In our case, we would like to profile the GPU so we will select Profiling.
Please note the green dot on left of the connection tab. If that dot is red, you might need to go to that tab and hit the connect button in the bottom right corner but normally it should connect automatically.
When the Radeon Developer Panel is open, connected and has the Profiling feature selected, any DirectX12, Vulkan, OpenCL or HIP application that you launch from now on will be automatically detected and attached to. This means we are now ready to launch Chrome.
Since RDP doesn’t need to launch the app itself, you have two options here.
Option A: Launcher (start Chrome with the hook already active)
- Launch RDP and make sure it’s connected and in
Profilingmode. - Launch Chrome via the launcher with the profiling flags:
webgpu_profiling_launcher.exe "C:\Program Files\Google\Chrome\Application\chrome.exe" --no-sandbox --disable-gpu-sandbox --disable-gpu-watchdog --disable-direct-composition --enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming - Open your WebGPU app in a tab. No reload needed, the hook is active from the start.
Option B: Injector (attach to a running Chrome)
- Launch RDP and make sure it’s connected and in
Profilingmode. - Launch Chrome with the profiling flags:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --no-sandbox --disable-gpu-sandbox --disable-gpu-watchdog --disable-direct-composition --enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming - Inject the hook into the running Chrome process. Run the following from the folder containing
d3d12_webgpu_hook.dll:
webgpu_injector.exe chrome.exe - Reload the WebGPU tab. This is required because the hook’s
CreateProcessWdetour only catches GPU child processes spawned after injection. Reloading forces Chrome to re-create the GPU process with the hook already active.
Once the tab is open you should see RDP’s Profiling tab change from Status: Offline to Status: Ready.
You can now hit the Capture profile button or use the configurable hot key Ctrl+Alt+C to capture your WebGPU app. The profile should appear on the right side of the app under Recently collected profiles.
Simply double-click any of the files to open the Radeon GPU profiler. If that doesn’t work, you might need to configure that path manually by hitting the cog-wheel in the top right hand corner of your screen.
And voila, you are ready to explore the performance of your app using RGP. How to use RGP itself is outside the scope of this post but another one might follow ;). In the meantime, feel free to explore the following resources.
- RGP Documentation
- GDC 2024 - Game Optimization with the Radeon™ Developer Tool Suite (YT video)
- GDC 2024 - Game Optimization with the Radeon™ Developer Tool Suite (slides)
- Occupancy Explained (shameless plug)
Capturing a frame with Nsight
To profile with Nvidia hardware, first download and install Nsight Graphics. Much like PIX, Nsight must launch an app itself to be able to profile it. So open Nsight, click the connect button in the top left corner and select GPU Trace Profiler from the Activity tab.
Select your Chrome executable in the Application Executable field, the path should look something like C:\Program Files\Google\Chrome\Application\chrome.exe. Don’t forget to fill the Command Line Arguments field with the relevant arguments. Note the addition of --do-not-de-elevate: Nsight runs as administrator, and without this flag Chrome will de-elevate itself on launch, which breaks injection. The field should look something like:
--no-sandbox --disable-gpu-sandbox --disable-gpu-watchdog --disable-direct-composition --enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming --do-not-de-elevate
Once those fields are filled, hit the Launch GPU Trace button in the bottom right corner and watch Chrome start. Then, inject the hook into the running Chrome process. Run the following from the folder containing d3d12_webgpu_hook.dll:
webgpu_injector.exe chrome.exe
Now open a tab with a WebGPU workload and reload it so the hook’s CreateProcessW detour can catch the GPU child process. Nsight should connect automatically and a new Collect GPU Trace button should appear.
Once you’ve hit that button, a message box should inform you that the capture succeeded. Just press the Open button to access the capture.
You should now see the following view and should be able to explore the performance of your app.
How to use Nsight itself is outside the scope of this post but feel free to explore the following resources.
- Nsight Documentation
- Powerful Shader Insights: Using Shader Debug Info with NVIDIA Nsight Graphics
- Identifying Shader Limiters with the Shader Profiler in NVIDIA Nsight Graphics
- Optimizing VK/VKR and DX12/DXR Applications Using Nsight Graphics: GPU Trace Advanced Mode Metrics
Closing Remarks
The solution provided here is a terrible hack that happens to trigger both RDP and Nsight at the time of writing this article. It’s entirely possible that this breaks tomorrow and there isn’t much I can do about it.
That being said, at this time it is also the only available option to properly profile the GPU for WebGPU on Windows / Chrome. This was my biggest pain point when working daily with WebGL, along with the lack of a proper graphics debugger. Now WebGPU has both through PIX and RGP/Nsight. To me that makes it a much more viable option for serious graphics programming. Performance doesn’t have to be about mythical knowledge and voodoo optimizing blindfolded with both hands tied in the back anymore. Fire up that profiler and look at some actual metrics!
TL;DR
⚠ Before anything else, please remember that this is a hacky solution and that you should not browse the open web with these tools attached. They should only be used for a GPU profiling session.
Launcher workflow (AMD RDP)
- Download
webgpu_profiling_launcher.exeandd3d12_webgpu_hook.dllfrom the release section of this repository. - Download
WinPixEventRuntime.dllfrom the release section of that repository.- Place it into the
\Google\Chrome\Application\<Version Number>folder.
- Place it into the
- When launching Chrome, use the launcher with the following command line arguments:
webgpu_profiling_launcher.exe "C:\Program Files\Google\Chrome\Application\chrome.exe" --no-sandbox --disable-gpu-sandbox --disable-gpu-watchdog --disable-direct-composition --enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming
- Use the GPU profiler as usual.
Injector workflow (AMD RDP and Nvidia Nsight)
- Download
webgpu_injector.exeandd3d12_webgpu_hook.dllfrom the release section of this repository. - On AMD, download
WinPixEventRuntime.dllfrom the release section of that repository.- Place it into the
\Google\Chrome\Application\<Version Number>folder.
- Place it into the
- Launch Chrome (or have Nsight launch it). Include
--do-not-de-elevatein the flags when using Nsight:--no-sandbox --disable-gpu-sandbox --disable-gpu-watchdog --disable-direct-composition --enable-dawn-features=emit_hlsl_debug_symbols,disable_symbol_renaming --do-not-de-elevate
- Run
webgpu_injector.exe chrome.exefrom the folder containingd3d12_webgpu_hook.dll. - Reload the WebGPU tab.
- Use your favorite GPU profiler as usual.