Repository navigation
[bug] agc_driver_dcc_keys_first_write fails on main on a real NVIDIA GPU #2188
Description
agc_driver_dcc_keys_first_write fails on main on a real GPU, and I could not find which change is responsible — reporting with the reproduction and with two suspects I was able to rule out.
Reproduction
On a clean upstream/main (d70b899), Linux, BUILD_TESTING=ON:
cmake --build build --target agc_driver_dcc_keys_first_write_tests --parallel 16
ctest --test-dir build -R ^agc_driver_dcc_keys_first_write$ --output-on-failure
1/1 Test #111: agc_driver_dcc_keys_first_write ...***Failed 0.44 sec
AGC graphics: an unchanged pending image was uploaded again
0% tests passed, 1 tests failed out of 1
naming the assertion an unchanged pending image was uploaded again. It fails with and without APS5_WRITE_WATCH_IMPORTS=watch, so the write-watch workaround from #1289 is not masking or causing it.
Environment
- Linux 7.2.9-1-cachyos, GCC 16.2.1, Release,
BUILD_TESTING=ON - NVIDIA GeForce RTX 3080 Ti, driver 615.71.09 (proprietary)
- The test's own log lines just before the failure:
[gpu] storage image 0x…: guest memory changed while GPU results were pending; keeping the CPU's blocks
Two suspects ruled out, by experiment
The test's introducing commit is b8d30603 ("fix(agc): store uncompressed DCC keys at the first write of a fast-cleared image", 2026-10-06), and the three most recent changes to that machinery are mine, so I tested them instead of leaving them as a suspicion:
- fix(agc): keep dma-buf import off the NVIDIA proprietary driver #1329 (dma-buf import gate on NVIDIA) — removing the
driverID != VK_DRIVER_ID_NVIDIA_PROPRIETARYclause fromVulkanDevice.cpp:878, i.e. restoring the pre-fix(agc): keep dma-buf import off the NVIDIA proprietary driver #1329 behaviour, still fails with the same message. - fix(agc): decide an edge unit's CPU keep from the pages the unit overlaps #1387 (per-page CPU-keep in
StoredOver) — neutralisingWriteTracker::noteCpuStoresendsStoredOverdown its own no-page-record fallback, which returns the pre-fix(agc): decide an edge unit's CPU keep from the pages the unit overlaps #1387 whole-block answer; still fails with the same message. - fix(relinker): bound the symbol and relocation table reads #1272 (unmerged) touches only
core/relinker/**, so it cannot be involved.
So the cause is somewhere between b8d30603 and main, and it is not the recently merged Dextroid17 PRs.
Why it may be going unnoticed
The linux CI job installs lavapipe and runs the execution tests on it. If this failure needs a real NVIDIA GPU — which the "guest memory changed while GPU results were pending" line suggests, since import watching behaves differently on that driver — then a green CI run would not contradict this report.
What I did not do
A bisect. Reverting the two files wholesale to their pre-merge state does not compile against current main (the interfaces moved), and I stopped there rather than rebuilding an older tree and guessing. If it would help, I can run one from any commit you point at.
Written with AI assistance.
Activity
Dextroid17 commentedon Oct 9, 2026
Confirmed device-specific, as the body suspected. On lavapipe — the same software device the linux CI job installs, Mesa 26.2.4 / LLVM 23.1.1 / 256 bits — the test passes; on the RTX 3080 Ti it fails with the same message. So the lavapipe job cannot see this.
To re-check on a machine with both: install or extract
vulkan-swrast, thenThat reproduces the CI device on a workstation without touching the NVIDIA install.
Written with AI assistance.
Dextroid17 commentedon Oct 9, 2026
Closing this myself, because by this project's own ground rules it should not have been filed: the failure reproduces only on the NVIDIA proprietary driver, that path is not expected to work on Linux yet, and the same test passes on lavapipe, which is the device CI actually runs. My framing above — a CI blind spot — was wrong; this is an unsupported device, not a defect.
Leaving it visible rather than deleting it, since the lavapipe half is the useful part: on the CI device the test passes, so nothing is hidden from CI.
Written with AI assistance.
SleglJan commentedon Oct 9, 2026
The bisect the report left open.
git bisect runbetween f145139 (the base of #1979, assumed good; the assertion does not exist there) and d70b899, 95 commits, 9 steps, 7 of them built and tested once each on an RTX 3080 (615.71.09, Linux, CachyOS kernel 7.2.9, GCC 16.2.1, Release) and 2 skipped because they do not build (6cc0503, 0ab2a04): the first bad commit is 0e1d25a ("fix(agc): avoid redundant transfers for untracked imported textures", merged through #2096), the commit that added the assertionan unchanged pending image was uploaded againtoDccKeysFirstWrite.cpp. Tested directly with the same build and GPU, its parent a8b032b passes 3 of 3 and 0e1d25a fails. At d70b899 the test fails 3 of 3 runs on the RTX 3080 and passes 3 of 3 on RADV (Mesa 26.2.4, Ryzen 7950X3D iGPU) on the same machine. On Windows, popcoder565's run on #2096 (RTX 3060 Laptop, 616.92, head 3ed0d03) hasagc_driver_dcc_keys_first_writepassing 30 of 30, and #2155 attributes thestorageRefreshTestsfailure ofagc_driver_recorder_testson that machine to the same commit.AI-assisted: yes (Claude Code).
fma-rc commentedon Oct 10, 2026
This reproduces on
main0c0dc1e with an RTX 5080 (615.71.09, Linux 7.2.9, GCC 16.2.1, Release), and the trigger is not the NVIDIA driver as such: it is host imports staying write-watched.mainmain+ patch belowAPS5_WRITE_WATCH_IMPORTS=watchAPS5_WRITE_WATCH_IMPORTS=unwatchAPS5_WRITE_WATCH_IMPORTS=watchThe probe reports
0 of 4 scratch pages written after a GPU read ... imported ranges stay watchedon NVIDIA and4 of 4 ... imported ranges are comparedon RADV.In the code:
GuestMemory::ImportWatchedstamps the blocks withStampKind::ImportWindow, whichChangedBlocksreports asBlockMaybeWritten.StorageTexture::Refreshtreats any non-zero stamp as changed (Texture.cppL1289), a changed pending unit blocks theequalsOriginal()rescue (L1326), and it is not droppable because it is notBlockWritten(L1388). So the unit is written back and the image uploaded again. The unwatched path instead compares againstoriginal(L1271).Candidate (7 lines, in
scanBlocks): for a tracked block unit stampedBlockMaybeWritten, compare it againstoriginalwithcompareUntrackedand mark it unchanged when equal.With it, on the RTX 5080 the full ctest goes from 564 of 565 to 565 of 565; on RADV
ctest -R ^agc_is 266 of 266 before and after.tools/check_conventions.pypasses.Retested on
mainee50132: same results in the table; full ctest on the RTX 5080 583 of 584 → 584 of 584, RADVctest -R ^agc_269 of 269 before and after.Not established: any effect on a title; the non-block-unit branch (L1298–1305); Windows. The RADV forced-
watchrow still fails with the patch, at a later assertion.compareUntrackedcallsFlushGpuWrites, which this adds to the tracked path.Patch against main 0c0dc1e
AI-assisted: yes.