AMD laptops: pick the GPU’s own (newer) driver; evict only textures unused for 60 frames #341

Merged
ZurielAtr merged 2 commits from amd/laptop-gpu-and-eviction into main 2026-11-07 23:46:13 +00:00
ZurielAtr commented 2026-11-07 21:46:53 +00:00 (Migrated from github.com)

Two fixes found on an AMD laptop (Ryzen 7 7735HS + Radeon RX 7700S 8 GB, 165 Hz panel, Windows 11, Adrenalin 26.10.1). Both were tested in game on that machine on foliage-linux-updater (the same code with the renderer rebuilt with RX_VK_ONLY=1); this branch is the same change on top of main, where it builds and the source regressions pass.

  1. The same GPU listed twice: the one with the newer driver (vk_main.cpp)
    With AMD graphics in the processor and an AMD card, Windows has two AMD drivers installed, one per adapter, and each one's Vulkan driver lists every AMD GPU, so the card shows up twice. pick_device() took the first one, which on this laptop came through the processor graphics' driver. Updating the card's driver leaves that one as it was:

vk: device 0: AMD Radeon RX 7700S, Vulkan 1.3, driver 0x800136, type 2 <- the iGPU's older driver
vk: device 1: AMD Radeon RX 7700S, Vulkan 1.4, driver 0x8001a0, type 2 <- the card's own driver
vk: device 2: AMD Radeon(TM) Graphics, Vulkan 1.3, driver 0x800136, type 1
The game kept running on amdvlk64.dll 32.0.11036.4002 (January 2025) after the card was updated to 32.0.32015.7029, and that compiler crashed (0xc0000409 in amdvlk64.dll, Windows Error Reporting) on compute pipeline b612216258832b9c while a save loaded. RX_VK_NOOPT=1 got past it, slowly. With the card's own driver it builds and the save loads.

Now every device is logged, and of two of the same kind the one with the newer driverVersion is picked. RX_VK_DEVICE= picks one by its index in that list.

  1. Over the VRAM budget, evict what has gone unused for 60 frames, not 8 (vk_texture.cpp)
    On this 8 GB card the VRAM sits at the driver's limit in Kokiri Forest (7313 MB used of 7313 MB allowed), the budget shrinks and eviction runs every 10 frames over whatever the last 8 frames did not use. The game samples many textures less often than that. Measured with the new RX_VK_LOG_REMADE=1:

in a few minutes, ~300 textures were evicted and made again, every one within 60 frames (~200 within 10), each uploaded and decoded again;
a 260 x 260 texture the GPU renders and the game samples every 40 frames came back each time over storage the GPU had rendered, so it was not uploaded and was sampled empty, 22 times. The result was the lit scene black for a frame every 10-20 frames, plus a dark tiled pattern over the ground.
min. unused 8 (before) 60 (this PR)
textures sampled empty after eviction 22 2
one-frame black flashes caught by RX_VK_FLASH=1 13 0
ground pattern visible gone
What is really done with still goes, 52 frames later. RX_VK_EVICT_MIN_UNUSED= sets the minimum. RX_VK_LOG_REMADE=1 logs the textures evicted and made again within 600 frames, and those of them sampled empty (off by default).

Not in this PR, for reference
Another ground artifact (a dark tiled pattern in other places of Kokiri Forest) is a separate problem. The game renders into a 64 x 64 BC4 texture (0x1133ccb000, 16 layers) through an R16G16B16A16_UINT view as a colour attachment. BC images are made without COLOR_ATTACHMENT, so the view is never made (view of texture ... (vk 139) as vk 95 ... not made (for a render target; the image's usage 0xf, the view's 0x10)) and the texture is never written. It probably needs a render-into-uncompressed-then-copy path (as vkd3d-proton does), and the image has 1 layer where the game renders 16. I can look into it if it is not already known.

Tested
In game on the RX 7700S (on foliage-linux-updater, renderer rebuilt with these changes and EvilOOT's flicker fix): the save loads without RX_VK_NOOPT, and the ground and flash numbers are in the table above.
main: RX_VK_ONLY=1 python -I nx2/build.py --standalone builds. The source regressions pass with clang++. nx2/test_nup_paths.py and tests/test_rumble_refresh.py fail on Windows on main without these changes as well.
🤖 Generated with Claude Code

Two fixes found on an AMD laptop (Ryzen 7 7735HS + Radeon RX 7700S 8 GB, 165 Hz panel, Windows 11, Adrenalin 26.10.1). Both were tested in game on that machine on foliage-linux-updater (the same code with the renderer rebuilt with RX_VK_ONLY=1); this branch is the same change on top of main, where it builds and the source regressions pass. 1. The same GPU listed twice: the one with the newer driver (vk_main.cpp) With AMD graphics in the processor and an AMD card, Windows has two AMD drivers installed, one per adapter, and each one's Vulkan driver lists every AMD GPU, so the card shows up twice. pick_device() took the first one, which on this laptop came through the processor graphics' driver. Updating the card's driver leaves that one as it was: vk: device 0: AMD Radeon RX 7700S, Vulkan 1.3, driver 0x800136, type 2 <- the iGPU's older driver vk: device 1: AMD Radeon RX 7700S, Vulkan 1.4, driver 0x8001a0, type 2 <- the card's own driver vk: device 2: AMD Radeon(TM) Graphics, Vulkan 1.3, driver 0x800136, type 1 The game kept running on amdvlk64.dll 32.0.11036.4002 (January 2025) after the card was updated to 32.0.32015.7029, and that compiler crashed (0xc0000409 in amdvlk64.dll, Windows Error Reporting) on compute pipeline b612216258832b9c while a save loaded. RX_VK_NOOPT=1 got past it, slowly. With the card's own driver it builds and the save loads. Now every device is logged, and of two of the same kind the one with the newer driverVersion is picked. RX_VK_DEVICE=<n> picks one by its index in that list. 2. Over the VRAM budget, evict what has gone unused for 60 frames, not 8 (vk_texture.cpp) On this 8 GB card the VRAM sits at the driver's limit in Kokiri Forest (7313 MB used of 7313 MB allowed), the budget shrinks and eviction runs every 10 frames over whatever the last 8 frames did not use. The game samples many textures less often than that. Measured with the new RX_VK_LOG_REMADE=1: in a few minutes, ~300 textures were evicted and made again, every one within 60 frames (~200 within 10), each uploaded and decoded again; a 260 x 260 texture the GPU renders and the game samples every 40 frames came back each time over storage the GPU had rendered, so it was not uploaded and was sampled empty, 22 times. The result was the lit scene black for a frame every 10-20 frames, plus a dark tiled pattern over the ground. min. unused 8 (before) 60 (this PR) textures sampled empty after eviction 22 2 one-frame black flashes caught by RX_VK_FLASH=1 13 0 ground pattern visible gone What is really done with still goes, 52 frames later. RX_VK_EVICT_MIN_UNUSED=<frames> sets the minimum. RX_VK_LOG_REMADE=1 logs the textures evicted and made again within 600 frames, and those of them sampled empty (off by default). Not in this PR, for reference Another ground artifact (a dark tiled pattern in other places of Kokiri Forest) is a separate problem. The game renders into a 64 x 64 BC4 texture (0x1133ccb000, 16 layers) through an R16G16B16A16_UINT view as a colour attachment. BC images are made without COLOR_ATTACHMENT, so the view is never made (view of texture ... (vk 139) as vk 95 ... not made (for a render target; the image's usage 0xf, the view's 0x10)) and the texture is never written. It probably needs a render-into-uncompressed-then-copy path (as vkd3d-proton does), and the image has 1 layer where the game renders 16. I can look into it if it is not already known. Tested In game on the RX 7700S (on foliage-linux-updater, renderer rebuilt with these changes and EvilOOT's flicker fix): the save loads without RX_VK_NOOPT, and the ground and flash numbers are in the table above. main: RX_VK_ONLY=1 python -I nx2/build.py --standalone builds. The source regressions pass with clang++. nx2/test_nup_paths.py and tests/test_rumble_refresh.py fail on Windows on main without these changes as well. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Commenting is not possible because the repository is archived.
No description provided.