[Feature Request] Unified Memory / Zero-Copy Path for AMD APUs on Linux (Steam Deck,Other Handhelds, BC-250, RADV) #309
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot#309
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
The idea
Summary
On unified memory hardware running Linux + Mesa RADV (such as the Steam Deck, Ryzen Z1/Z2 handhelds, and AMD BC-250 systems), CPU and GPU share a single physical memory pool. Currently, Hookshot treats these devices like discrete-GPU PCs—allocating a guest memory arena in system RAM and duplicating assets into
DEVICE_LOCALVulkan memory—which quickly exhausts 16 GB unified pools despite the target Switch 2 hardware operating within a 9 GB game budget.Adding an opt-in unified memory path (e.g.,
RX_VK_UNIFIED_MEM=1) would drastically reduce memory duplication and prevent OOM stalls or crashes on Linux APUs.Problem Description
DEVICE_LOCALVRAM heaps, causing the same data to occupy two regions of the same physical LPDDR5/GDDR6 chips.Expected Benefit
Eliminating guest-to-VRAM duplication on unified APUs should bring total runtime memory usage much closer to native Switch 2 hardware, avoiding OOM kills on 16 GB devices without sacrificing texture quality.
Anything else
Proposed Technical Approach (RADV / Linux APU Zero-Copy)
VK_EXT_external_memory_host:VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) supportingVK_EXT_external_memory_host, bind guest RAM allocations directly as host-imported Vulkan buffers for geometry, uniform buffers, and staging data instead of allocating separateDEVICE_LOCALcopies.HOST_VISIBLE | HOST_COHERENT | DEVICE_LOCALwhere exposed by RADV's resizable BAR / large-BAR heap) with the existingRX_VK_COMPACT=1compaction logic so free memory returns cleanly to the shared OS pool.Adding a data point from a consumer APU that is not in the list above:
RDNA 3.5 (Krackan) on Linux RADV.
Hardware
[1002:1114]rev d2 —Vulkan reports
AMD Radeon 860M Graphics (RADV KRACKAN1)MESA_RADV/dev/udmabufavailable (ACL granted to the user)Observed on Hookshot v2.1.0 (this tree's ancestor), 100% render at 1536x864:
textures 4614 MBagainst a default budget of 2560 MB — the gameevicted and re-uploaded across zone transitions
RX_VK_VRAM_MBto 6144 removed the churn; textures settled at4614 MB with 1536 MB of live imports
CPU-bound · device lost: 0
This matches the "static heap pressure" case described above: with an 8 GB
carve-out and a 27,934 MB GTT, a discrete-style budget does not fit the
pool, and the 2560 MB default is far below what the game's own textures need.
More precise numbers from the same run, in case they help size the problem.
Settings: Handheld profile On — this is what fixes the output at
1536x864, so "100% render" means 100% of 1536x864, not of 1920x1080.
Output resolution 1920x1080, Upscaler "Game's own", Frame generation Off.
Memory after
RX_VK_VRAM_MB=6144:textures 4614 MB (budget 6144 MB)imports: 44 live (1536 MB)The symptom was specific: entering a zone for the first time stuttered,
the second pass was smooth — texture eviction and re-upload, not shader
compilation. At the default budget the log had textures above it
(2783 MB against 2560).
Still failing: 11 shader programs, which on this GPU are the game's own AA
networks — the log says
matrix multiplies in software (the cooperative matrices lack 16x8x16 f16).I will add numbers from a Longshot build once v3.0.0 is out.
What Longshot's native Linux build already does on the Steam Deck, from our Deck runs (Steam Deck OLED, SteamOS 3.9.5, RADV, stock clocks, docked; the player's rc.4 user build with #222 applied, Kokiri Forest route).
Buffers are already zero-copy. The guest memory window is a memfd, handed to the GPU as dma-bufs through udmabuf. Draws read the game's own pages in place, and VRAM mirrors (the discrete-card path) are off, so there are no mirror syncs or write-back copies:
What is still copied, and why:
capture: a submitlines).Why not host-pointer imports (
VK_EXT_external_memory_host): under Proton the Windows build can only import guest memory as host pointers, and amdgpu checks each page of those again at every submission.vkQueueSubmittook 148-189 ms a frame under Proton, against 4 ms natively.Where the memory goes instead.
a00c485c) at default settings on the Deck reached an 11.2-11.4 GB RSS and was stopped for memory in all 3 starts.Copying less isn't an fps win by itself here. With
RX_VK_READBACK_EARLY=1, which is what makes the capture wait for late pages, taking that wait out (RX_VK_CAPTURE_WAIT=0) removed 8-19 ms of memory sync a frame. Fps didn't follow, because the game's readbacks then waited instead: