Skip to main content

write-gpu-probe

Turn a GPU symptom into a small deterministic test program (a probe) for the VirtIO GPU stack — D3D11/D3D12 for Windows guests, Vulkan for Linux guests — that renders offscreen, reads pixels back against a sentinel, isolates one GPU access path at a time, and gives a pass/fail verdict usable as a regression test and as a commit's proof. Use when a bug needs a minimal repro, when a fix needs fail-before/pass-after evidence, or when asked to "write a test program", "make a repro" or "build the probes".

Source facts

Repository
utmapp/utmapp-bot
Last source activity
November 1, 2026 at 00:17
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
write-gpu-probe
description
Turn a GPU symptom into a small deterministic test program (a probe) for the VirtIO GPU stack — D3D11/D3D12 for Windows guests, Vulkan for Linux guests — that renders offscreen, reads pixels back against a sentinel, isolates one GPU access path at a time, and gives a pass/fail verdict usable as a regression test and as a commit's proof. Use when a bug needs a minimal repro, when a fix needs fail-before/pass-after evidence, or when asked to "write a test program", "make a repro" or "build the probes".
argument-hint
<symptom to reproduce>
# Write a GPU probe Symptom: `$ARGUMENTS` A 30-second deterministic probe beats any amount of reasoning about a game that fails after 20 minutes. It also proves a fix: the probe fails before the change and passes after it. ## Start from the templates `${CLAUDE_PLUGIN_ROOT}/probes/`: | Probe | What it shows | |---|---| | `adaptercheck.c` | Lists DXGI adapters; creates D3D11 and D3D12 on the VirtIO adapter at each feature level. `ADAPTERCHECK PASS` = D3D reaches our driver. | | `readback11.c` | D3D11, one check per access path: clear, CPU upload, draw (VB + CB + PS), dynamic `Map(WRITE_DISCARD)` renaming, compute UAV write. | | `readback12.c` | D3D12: clear, upload-heap copy; with barriers and a fence. | | `presentloop.c` | Windowed or fullscreen present loop: fps per 5 s window, worst frame gap, `--rtv-per-frame`; verdict `STEADY` / `DECAY` / `HITCH`. | | `vkreadback.c` | Vulkan (Linux, Venus): clear, buffer-to-image copy. | | `fglock.c`, `fgforce.c` | Foreground helpers the harness uses for fullscreen workloads. | Copy the closest one, keep its skeleton, and replace one path's body with the smallest sequence that shows the bug. ## Principles - **Pick the VirtIO adapter explicitly** (`probe_find_adapter` in `common.h`: vendor `0x1af4`, `D3D_DRIVER_TYPE_UNKNOWN`). A default hardware device can silently be WARP. - **Read back, do not look.** Render into a texture and copy it into a CPU-readable resource that you **filled with a sentinel first**. Compare every texel. The sentinel separates "the GPU wrote the wrong value" from "the write or copy never happened". One bug was mis-attributed to compute for hours because the readback copy, not the dispatch, was dropped. - **One access path per check.** Clear, upload, copy, vertex/constant buffer, dynamic map, UAV, sampling and present map to different host mechanisms and fail independently. Find the first one that fails. - **Exact expected values.** Pick colors that are exact in the format, e.g. 0.6 or 0.2 for UNORM8, not 0.5, which rounds either way. Print expected and actual in hex. - **Small, fixed sizes, no timing dependence,** unless timing is the bug (`presentloop`). - **Report a single verdict line** (`<NAME> PASS|FAIL`), exit 0 on pass, and keep the details above it. - **Check device removal at the end** (`GetDeviceRemovedReason`). A probe that passes on a removed device proves nothing. - **Native vs emulated.** Build ARM64 for the driver's native path, and x64 for what x64 apps see (they run emulated and use the driver's ARM64EC half). An x64 probe cannot load a native arm64 DLL directly; that error is the caller's architecture, not the driver. - **Do not commit diagnostics into the driver to make the probe work.** The probe stands alone and goes into the regression set. ## Build and run **Windows, MSVC on the dev VM** (both architectures, into `~/.utmapp-bot/probes/{ARM64,x64}/`, where the harness finds them): ```sh bash ${CLAUDE_PLUGIN_ROOT}/scripts/build-probes.sh <[user@]dev-vm-ip> ``` It builds every `.c` in `probes/`. To add your probe, put it there (or in a copy of the directory) and rerun. **Without a dev VM**, mingw-w64 builds the x64 versions on the Mac (`brew install mingw-w64`): ```sh x86_64-w64-mingw32-gcc -std=c11 -O1 -I${CLAUDE_PLUGIN_ROOT}/probes -o readback11.exe readback11.c -ld3d11 -ldxgi -ldxguid -luser32 ``` **Run** in the console session, never over SSH: ```sh python3 ${CLAUDE_PLUGIN_ROOT}/scripts/utmbot test ~/.utmapp-bot/probes/ARM64/readback11.exe ``` **Linux guest:** ```sh UB="python3 ${CLAUDE_PLUGIN_ROOT}/scripts/utmbot" $UB put ${CLAUDE_PLUGIN_ROOT}/probes/vkreadback.c '~/utmbot/' $UB test 'cc -O2 -o ~/utmbot/vkreadback ~/utmbot/vkreadback.c -lvulkan && ~/utmbot/vkreadback' ``` For a Windows exe under Wine/FEX in the Linux guest, build it as x86_64. ## Use it as proof Run the probe on the build before the fix (FAIL) and after it (PASS), in the same session, and put both verdicts in the commit message or PR. Keep it next to the regression tests of the layer that was fixed.
View on GitHub