Skip to main content

attribute-to-layer

Decide which layer of the VirtIO GPU stack owns a bug before fixing it — the guest driver (UMD/KMD), the virtio transport and virglrenderer, the d3dmetal-native or DXMT backend shim, Apple's D3DMetal itself, Wine/CrossOver behavior, or UTM's display path — by swapping backends, pinning D3DMetal versions, comparing against CrossOver correctly, and running one probe through every layer. Use when a bug might not be ours, when a result differs between backends or from CrossOver, or before investing in a fix.

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
attribute-to-layer
description
Decide which layer of the VirtIO GPU stack owns a bug before fixing it — the guest driver (UMD/KMD), the virtio transport and virglrenderer, the d3dmetal-native or DXMT backend shim, Apple's D3DMetal itself, Wine/CrossOver behavior, or UTM's display path — by swapping backends, pinning D3DMetal versions, comparing against CrossOver correctly, and running one probe through every layer. Use when a bug might not be ours, when a result differs between backends or from CrossOver, or before investing in a fix.
argument-hint
<bug or failing test>
# Attribute a bug to a layer Bug: `$ARGUMENTS` The same symptom can come from six layers. A fix in the wrong one either does nothing or masks the real bug. Attribute first. ``` guest app -> D3D runtime -> UMD/KMD (guest) -> virtio-gpu (QEMU) -> virglrenderer -> backend shim (d3dmetal-native | DXMT) -> D3DMetal (Apple) -> Metal display: guest present -> scanout -> QEMU SPICE GL -> UTM window ``` ## Steps 1. **Swap the backend.** Run the repro under both backends: `utmbot vm up --backend d3dmetal` and `--backend dxmt`, and prove each with `utmbot backend`. - Fails on one backend only: that backend's shim or D3DMetal/DXMT itself, or a translation our layer applies only for it. - Fails on both: our guest driver, the transport or virglrenderer, the display path, or the app. - Compare at equal frame rates: anything rate-dependent (tearing, flashes) looks backend-specific when it is not. 2. **Pin the D3DMetal version.** Record the version that ran next to every result (`utmbot backend` prints it). Different D3DMetal releases fix and break different things. - Point `D3DMETAL_FRAMEWORK_PATH` at another D3DMetal build (`vm up --env …`) to test a version theory. - Before calling something a regression, check which D3DMetal the "passing" run used. A known-good result once came from a different D3DMetal that had drifted in. 3. **Compare with CrossOver,** which runs the same D3DMetal/DXMT on the host without our guest layers. If it works under CrossOver and fails in the VM, the difference is ours: guest driver, transport, shim usage or caps. Rules: - **Verify the backend CrossOver really used from inside the app**, e.g. the adapter name or vendor ID it reports. A bottle setting or environment override is not proof. - **Make CrossOver look like the VM, never the reverse.** Use the same executable name, the same reported vendor and device IDs, the same feature level and memory size. D3DMetal and some engines switch behavior on the executable name or GPU vendor. *Example: an engine enabled shared video surfaces only for some GPU vendor IDs: video was black in the VM, fine in CrossOver, and nothing was wrong in the driver.* - **CrossOver's capability answers are not ground truth.** Its backends answer some queries with placeholders. Parity means the same behavior, not the same numbers. - **A CrossOver "timeout" is often a crash** waiting on a debugger dialog. Run CrossOver only while the VM is down: they share the GPU. 4. **One probe through every layer** (`/utmapp-bot:write-gpu-probe`). Run the same minimal repro: 1. against the backend directly on the host (a small program that loads D3DMetal or DXMT the way the shim does); 2. through the shim (d3dmetal-native/DXMT native API); 3. under CrossOver/Wine as a Windows exe; 4. in the Neptune guest. The first layer where the verdict flips owns the bug. 5. **The display path is its own suspect.** If offscreen readback in the guest is right but the window is wrong, it is scanout, SPICE GL or UTM. Frames going backwards can only be the display path (triage skill, black-screen-and-pacing.md). ## Decide - **Ours:** fix it in our layer, generically (`/utmapp-bot:land-stack-change`). - **A backend defect** (fails raw on the host, or under CrossOver with identical failure text): record it with the probe that shows it, and work around it in the shim only when the workaround is correct for every legal input. Fix our own bugs first. A test counts as a backend defect only when CrossOver fails it with the *same* failure; a different failure text is two bugs. - **App behavior** (vendor checks, executable-name profiles): document it. Change the driver only if the API contract says we are wrong. ## Conformance-scale parity (optional) When a whole test suite differs between CrossOver and the VM, compare per test case, not by totals. The directx-cts harness (`https://github.com/osy/directx-cts`) runs Microsoft's HLK D3D conformance content under both and diffs the results per case. A sampled run hides crashes, so run the full plan of the area you changed. Every test that passes on CrossOver must pass in the VM; anything only the VM fails is ours until shown otherwise.
View on GitHub