fix(linux): don't try dma-buf imports on NVIDIA's driver #2340
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2340
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/linux-nvidia-dmabuf-type"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is for: a clean start on Linux with NVIDIA's driver. On Linux with NVIDIA's driver, the game asks the driver to import every block of guest memory as a udmabuf dma-buf, the driver refuses every one, and each block ends up a host-pointer import anyway. The attempts leave a kernel line at every start that reads like a driver fault (
NVRM: memMap_IMPL: CPU mapping not supported for addressSpace: 0x1). This change stops asking on NVIDIA's driver. Fixes #2339. What is measured: on one machine (RTX 4090, NVIDIA 615.78.08, Kokiri Forest): the refused imports and the kernel line are gone, and the frame rate is unchanged within the spread of identical runs (80.4 and 81.3 fps before, 79.6 and 81.5 after). Not measured: any other NVIDIA card or driver version, any other area, and whether the refusals ever cost a visible hitch in play. So this is a cleanup of the log and the start, not a speed-up.Problem
/dev/udmabuf(#448). The readme gives the reason: host-pointer imports can be much slower on AMD with RADV.import_dma_buf(gpu/vk/vk_memory.cpp) makes a udmabuf anddma_buf_memoryasks the driver which memory types it allows for it. NVIDIA's driver answers with two (allowed bits 0x9): type 0 with no flags, and type 3, host visible, coherent and cached. The code takes the first host-visible and coherent one: type 3.VK_ERROR_OUT_OF_DEVICE_MEMORY(vk: guest ...: its dma-buf not imported (VkResult -2)), for every pool, and a pool made of several pieces stays unbound (its 0 dma-bufs not bound (VkResult -13)).memMap_IMPLline 0.17 to 0.6 ms into it. Later refusals take microseconds and usually print nothing, but 2 of my 18 measured runs ofmainprinted the line three times. One later refusal, of a 64 MB piece during a save's load, took 198 ms on the presentation thread. I saw that once and can't say how often it happens.What changed
gpu/vk/vk_memory.cpp,import_dma_buf:/dev/udmabufis not opened whendev.driver_idisVK_DRIVER_ID_NVIDIA_PROPRIETARY, so no dma-buf is made or offered and every pool takes the host-pointer import from the start, as it already did after each refusal. The start-up line says why:vk: guest memory as dma-bufs: no (NVIDIA's driver refuses them: host pointers). Other drivers take the same path as before: the driver check is the only new condition.readme.md: the udmabuf paragraph says that NVIDIA's driver refuses these dma-bufs and the game uses host-pointer imports there.tests/import_buffer_binding_test.cpp: the fixture's device gets adriver_id, itsopencounts calls, and a newnvidiacase checks the dma route (noopen, no buffer, no allocation, no memfd kept) and the pool route (one host-pointer import).tests/test_import_buffer_binding.py: runs the new case on both routes (37 cases, was 34).Why skip the attempt instead of picking the other memory type. The driver does accept type 0: with an experiment that forced it, all 60 imports of a run succeeded and no kernel line appeared. But Kokiri Forest ran 2.5 % slower that way (79.17 and 78.53 fps against 80.63 and 81.13 with host pointers, taken in turn; identical runs differed by 0.6 to 0.8 %). I also don't know whether the GPU sees the CPU's writes coherently through an import that isn't host visible. So host pointers stay.
How it was tested
Environment: RTX 4090, NVIDIA 615.78.08 with its open kernel module, i9-13900K, 96 GB, Arch Linux (kernel 7.2.15), headless (
HOS_HEADLESS=1, no window), a build from source with clang 23.The test.
tests/test_import_buffer_binding.pypasses with the change (g++ and clang++). The new fixture againstmain'svk_memory.cppfails:fixture-0.exe dma nvidiaaborts on its assert.All checks.
python -I -B tests/run_all.pyon the branch: 361 passed, 3 failed, 10 skipped. The three failures are this machine's and don't touch the change:tests/test_updater_asset_digest.pyneeds the .NET 8 SDK (only .NET 10 is here),tests/test_wayland_libdecor_hint.pytrips a clang 23 warning under-Werror, andnx2/test_unsigned_image_types.pyfailed to compile while the load average was 120 to 370 and passes when run alone. That run was on the commit before a last edit that changed only a code comment; after the edit I rerantest_import_buffer_binding.pyalone (passes).In the game.
mainbdfe09cwith this commit againstbdfe09c, the two renderers built the same way. The user's save in Kokiri Forest, 13 camera turns of 4 s, uncapped (HOS_FPS_MAX=240), output 2048x1152, Render resolution Auto, no frame generation. Four runs of 90 s in turn (base, fix, base, fix) with nothing else on the card and no build running. The frame times are the game's own present-to-present intervals (HOS_PRESENT_TRACE) over the 30 s from 15 s after the save's load.The log and the kernel, per run:
("refused imports 7" is what the log shows before its own limit of 8 such lines; the count with a line per attempt is the 49 to 50 above.)
The frames, per run:
bdfe09cbdfe09c+ thisbdfe09cbdfe09c+ thisAdded 2026-11-11 15:56 UTC: a second driver, run by @CIB (his comment below). RTX 4090, NVIDIA 590.48.01 (open kernel module), Arch Linux, kernel 6.19.8; only the
vk_memory.cpphunk, on main8c92fe3in a tree with unrelated local scheduler work. Stock, three starts: each logs the refused imports (7 lines on a first start, 1 on the next two) and adds onememMap_IMPLline to the kernel log. With the hunk, two starts: neither line, and the newvk: guest memory as dma-bufs: no (NVIDIA's driver refuses them: host pointers). Frame times were not measured there.Risks
VK_DRIVER_ID_NVIDIA_PROPRIETARYmatched here with the open kernel module. Mesa's NVK reports a different driver id and keeps trying dma-bufs as before; I have not run it.RX_VK_NO_DMABUF=1andHOS_GUEST_MEMFD=0work as before.Not tested
Other NVIDIA cards, driver versions other than 615.78.08 (mine) and 590.48.01 (CIB's short starts), NVIDIA's closed kernel module, NVK, AMD, Intel, a run with a window, areas other than Kokiri Forest, the Steam Deck. Windows doesn't reach this code.
Other open pull requests
Twelve open pull requests touch
gpu/vk/vk_memory.cpp. None changes these lines. #2042 changes the line two above (getenv("RX_VK_NO_DMABUF")toenv_on(...)) and the same two test files; git merges the two without a conflict, and the merged function has both changes.Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 [email protected]
Independent check on a second NVIDIA driver (590.48.01)
I applied only the
gpu/vk/vk_memory.cpphunk on top ofmain8c92fe3(a local tree with unrelated scheduler work) and ran it on a different machine and driver from yours:hookshot_vk.sobuilt from source.Stock, three starts: every start logged
its dma-buf not imported (VkResult -2)(7 lines on a first start, 1 on the next two), and every start added exactly oneNVRM: memMap_IMPL: CPU mapping not supported for addressSpace: 0x1to the kernel log. The pools fell back to host pointers and the game reached its first decoder.With your hunk, two starts: zero
VkResult -2lines, zero newmemMap_IMPLlines, and the new linevk: guest memory as dma-bufs: no (NVIDIA's driver refuses them: host pointers). The renderer started and the game reached the first decoder in both.So the diagnosis and the gate hold on a driver you did not test, and the kernel line is gone here too. I did not measure frame times (my runs were short boots), so I can't add to your numbers there.
One note:
RX_VK_NO_DMABUF=1also removes the kernel line, but that arm hit an unrelatedguest 0xfffff00000000000sentinel crash at boot, so I would not use it as the validation arm.🤖 Generated with opencode using DeepSeek V4.1 Flash.
Thanks. A second driver was the first thing on my not-tested list, and your run covers it: 590.48.01 refuses the import the same way, and the hunk removes both lines there too. I've added your result to the description.
On
RX_VK_NO_DMABUF=1: here that arm ran without the crash you saw. On mainbdfe09cit ran 35 s at the title (1,680 presents, no FATAL or CRASH line; one run), andHOS_GUEST_MEMFD=0ran three minutes into Kokiri Forest at 60 fps. So the0xfffff00000000000crash doesn't come from the switch alone, at least on my tree and driver. If you open an issue for it with the log lines around the crash, tag me: that arm is one I can run here.Looks good. The gate is narrow and in the right place:
dev.driver_idis filled invk_main.cppbefore any pool is imported,/dev/udmabufsimply isn't opened onVK_DRIVER_ID_NVIDIA_PROPRIETARY,dmabuf_memfdstays -1, and every pool goes straight to the host-pointer import it already ended up on after each refusal. Other drivers (NVK included, which has its own driver id) take exactly the old path, and the new log reason sits after the existing ones so their messages are unchanged. The fixture covers both routes (noopen, no buffer/allocation on the dma route; one host-pointer import on the pool route), and the choice to skip rather than force memory type 0 is well argued with the 2.5 % numbers and the coherency doubt.@CIB's run on 590.48.01 confirms the same refusal and the same fix on a second driver, so the main "not tested" item is covered. His
RX_VK_NO_DMABUF=1crash is separate from this change (you couldn't reproduce it; an issue with logs would be the place for it).One nit on consistency with #2111 (inline): the startup warning from
reserve_guestinhost/hos_main.cruns before the Vulkan device exists, so it can't know the driver and will still tell NVIDIA users without access to ask an admin for/dev/udmabuf, a device the renderer now never uses on NVIDIA. Not worth plumbing the driver into that early probe, but the readme could say NVIDIA users can ignore it.CI: only the title check has run; the build/test workflows are waiting for a maintainer to approve them (action_required), so they need to go green before merge.
@ -132,0 +130,4 @@`udmabuf` module). Without it, Hookshot falls back to host-pointer imports, which can be much slower on AMD/RADV(NVIDIA's driver refuses these dma-bufs, so on NVIDIA the game uses host-pointer imports, which are not slow there);permission errors produce a warning on stderr and in `hookshot_log.txt`. With an NVIDIA card on NVIDIA's own driveryou do not need this access and can ignore that warning: the check runs at the start, before the game knows whichNit: since #2111 the startup probe in
host/hos_main.cstill prints the/dev/udmabuf permission deniedwarning on NVIDIA (it runs before the Vulkan device, so it can't know the driver). Maybe add here that NVIDIA users don't need the access and can ignore that warning, so nobody adds themselves tokvmor writes a udev rule for nothing.@ -132,0 +130,4 @@`udmabuf` module). Without it, Hookshot falls back to host-pointer imports, which can be much slower on AMD/RADV(NVIDIA's driver refuses these dma-bufs, so on NVIDIA the game uses host-pointer imports, which are not slow there);permission errors produce a warning on stderr and in `hookshot_log.txt`. With an NVIDIA card on NVIDIA's own driveryou do not need this access and can ignore that warning: the check runs at the start, before the game knows whichDone in
6af37596: the paragraph now says that with an NVIDIA card on NVIDIA's own driver you don't need the access and can ignore that warning, and why it still appears (the check runs at the start, before the game knows which GPU it has). I left the early probe itself alone, as you suggest.github-sync referenced this pull request2026-11-12 06:22:54 +00:00