Skip to content

Import shm buffers through udmabuf - #2254

Open
Netflate wants to merge 7 commits into
Smithay:masterfrom
Netflate:shm-udmabuf
Open

Netflate wants to merge 7 commits into
Smithay:masterfrom
Netflate:shm-udmabuf

Conversation

@Netflate

@Netflate Netflate commented Oct 30, 2026 •

Copy link
Copy Markdown

Description

Import shm buffers via udmabuf.

Closes #2044, indirectly helps a bit with #1652.

Details

  • udmabuf is only enabled on integrated i915 (with LLC), xe and amdgpu GPUs: discrete ones are slower through it, and other drivers are either broken or untested.
    • an external renderer doesn't pass the driver, so udmabuf is disabled by default for it. If preferred, we can require external renderers to define prefers_udmabuf, but it's a breaking change.
  • Client can start writing to a buffer after wl_buffer.release while the gpu is still reading it. Two solutions are implemented: a blocking one via a fence, and a fast non blocking one via DrmCompositor (not a driver workaround). Fence is still required when DrmCompositor isn't available.
  • I didn't really initially plan an udmabuf pool, at least in this pr (plus Kde doesn't have one either), but without it the gains really drop when client keeps creating new wl_buffer for every frame, like in Firefox.
  • Up to 4 udmabufs are cached instead of 1, because sctk clients cycle through 4 buffers. With 1 the gain would drop.
  • create_buffer_from_memfd: removed the stride and offset checks. Offset and size no longer need to be page multiples: the udmabuf starts at the page boundary, and the remainder is passed as the plane offset.
    • The stride check is really only needed for Nvidia (silently shows broken frames), which is disabled by default anyway. Intel works with any stride. AMD needs 256 (as ids1024 said), but seems like the driver rejects an incorrect stride itself.
    • Offsets: not needed on Intel, Nvidia rejects non-multiples of 64 for me
    • AMD : Kde doesn't have a stride check, and everything is okay, but for offsets there isn't any past experience, so that requires testing, which i can't do

Testing results

Intel Tiger Lake + NVIDIA GeForce RTX 3050 Ti Mobile, using Cosmic and anvil.

Results on Intel:

  1. Firefox on Cosmic (1080p60, new wl_buffer every frame): ~650–690 microseconds copying vs ~22 microseconds with cached udmabuf (~255 microsecond without cache).
  2. anvil + test_subsurface (1024×768, reused buffers): ~545–577 microseconds copying vs ~26–30 microseconds with udmabuf.
  3. anvil + Okular: ~0.7–2.3 ms copying vs ~20–28 microseconds with udmabuf.
  4. anvil compositor load: −37% during video playback and −55% during scrolling.
  5. Buffer holding: in tty maximum wait before wl_buffer.release goes from 1.6 ms to 19 microseconds with it

small note: Nvidia stale pixel issue (the reason it's fully denied in kde) occurs very rarely for me, but it was widely reported in Kde, so there's no point in making an exception for Nvidia.

Checklist

Copilot AI balanced review requested due to automatic review settings October 30, 2026 22:49

This comment was marked as low quality.

@Netflate

Copy link
Copy Markdown
Author

About holding buffers in DrmCompositor: it doesn't look like the most elegant solution, but it's kinda the only way to avoid the blocking wait without an async fence based release, which would need an event loop where smithay releases buffers

(And I'm really sorry for whatever copilot thing is??? It never happened in my other PRs, I have no idea why it was even enabled)

@ids1024

ids1024 commented Oct 31, 2026

Copy link
Copy Markdown
Member

(And I'm really sorry for whatever copilot thing is??? It never happened in my other PRs, I have no idea why it was even enabled)

I don't think anyone's explicitly enabled anything Copilot related on this repo. Maybe something Github has turned on by default that we may want to disable...

@Netflate

Copy link
Copy Markdown
Author

Don't worry, turns out 'automatic copilot code review' was enabled on my side. Tho I'm confused why it showed up only here for the first time, and there aren't any security logs suggesting it was enabled. Really want to blame github, but couldn't find anyone reporting github enabling this itself, so whatever
image

Comment thread src/backend/allocator/udmabuf.rs Outdated
"virtio_gpu" => false,
// kernel driver leaks imported dma-bufs
"vmwgfx" => false,
_ => true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this isn't something we can generally assume to be properly supported by drivers, we should probably default to false.

There are various other drivers that might be used on ARM hardware, and I'm not sure how it will compare there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it. Plus I originally planned something for discrete gpus but for now they're slower through udmabuf (decided that gpus thing will be in a separate pr after this one)

@ids1024

ids1024 commented Oct 31, 2026

Copy link
Copy Markdown
Member

So the idea of PoolUdmabufs is that Firefox creates a new wl_buffer each time, but reuses the same offset/width/height/etc?

Something I was wondering is if we can just allocate a udmabuf file descriptor for the whole wl_shm_pool, then create multiple of smithay's (slightly inaccurately named) Dmabuf with different offsets. In #2085 I updated Dmabuf to use an Arc<OwnedFd> so we can share a file descriptor like this, though I haven't done testing of exactly how that ends up working with udmabuf.

Does that amount to the same thing as creating multiple udmabufs with different offsets? And perform the same? If so we may need to create new udmabufs on pool resizes, but it sounds cleaner than trying to make assumptions about how many buffers to cache per pool.

Only integrated GPUs are allowed. Discrete would read udmabuf
over PCIe on every draw, so copying into their own memory is faster
if a buffer is drawn more than once.

Known broken ones:
- nvidia-drm: sometimes shows outdated data, `DMA_BUF_IOCTL_SYNC` doesn't help
- i915 without LLC: CPU cache is flushed only on the first import
- virtio_gpu: breaks virgl context (KWin report, precaution)
- vmwgfx: kernel leak (KWin report, precaution)
gpu reads use DMA_BUF_IOCTL_SYNC for sync, END on every import,
and START right after udmabuf creation (since the kernel rejects
END without a preceding START).

The syncs only matter where CPU caches aren't coherent with the GPU (e.g. many ARM SoCs).
Delays their wl_buffer.release until gpu is done reading them, so
`wait_udmabuf_idle` doesn't block the compositor for miliseconds.

Unlike `wait_udmabuf_idle`, this also works on gpus that don't report
their reads (e.g. nvidia).
@Netflate

Netflate commented Nov 1, 2026 •

Copy link
Copy Markdown
Author

Yeah that's it, every wl_buffer creation is with the same layout, that's why the pool cache really helps. Copy ~760 microseconds, udmabuf without cache ~345, with ~27 (cpu 10.0% / 7.8% / 5.5%).

I've considered one udmabuf per pool. For the gpu it's the same thing and works fine, but it's not faster, the renderer caches imports per Dmabuf, so a new Dmabuf per wl_buffer means a new import every frame, increasing cpu usage, and +- doubling import time. Fixing that needs the same cache again.
And it hits udmabuf's 64 mb limit: at 4K sctk's pool reaches 127 mb, so nothing gets imported and goes back to copying. The only gain is fewer udmabuf creations at startup for pools with several buffers, which are more of an exception.

About buffers number: my description was a bit misleading, it's up to 4, not always 4. Cache only keeps layouts pool actually used, and the vast majority of apps use only one. Dynamic number is easy to implement I think, but I don't know any app using more than 4, and if it needs more it will just create a new udmabuf, which is still faster than copying

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants