detached 760a012

refactor(drm): mark the Vulkan-export output image fallback deprecated

Comment exportImages and its setupImages branch as a deprecated fallback
tracked by neferwl#23, and log the zero-copy output line as a warning
when it is used so reports show it.
commit
760a0121b387b1f89d2e7be46069dfc939b8526b
author
brice · · 2026-10-22 08:13 UTC
parent
f0c31c4
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
checks
1/1
2 files · +13 -2
M docs/dev/architecture.md +1 -1
@@ -29,7 +29,7 @@ About 35 channels connect them, all created in one place, so the full data flow
2929 A DRM output flips between two images the renderer draws into, with no CPU copy.
3030
3131 - **Allocation:** the images are allocated with GBM (`GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING`), with the modifiers the primary plane lists that the renderer can render into and import. The renderer imports them as Vulkan images, and KMS gets framebuffers made from the same dmabufs. GBM is the display driver's own allocator, so the layouts it picks scan out correctly on every driver.
32-- **Fallback:** when libgbm is missing, GBM allocates nothing usable, or Vulkan or KMS refuses the images, the renderer allocates and exports them itself. Each kind (driver modifier, single-plane, linear) tries GBM, then the renderer. The log line `zero-copy output` names the allocator in its `alloc` field (`gbm` or `vulkan`).
32+- **Fallback:** when libgbm is missing, GBM allocates nothing usable, or Vulkan or KMS refuses the images, the renderer allocates and exports them itself. Each kind (driver modifier, single-plane, linear) tries GBM, then the renderer. The log line `zero-copy output` names the allocator in its `alloc` field (`gbm` or `vulkan`), and is a warning for `vulkan`. This fallback is deprecated and goes away once GBM is validated on more setups (neferwl#23).
3333 - **Sync:** nvidia-drm before 560.35.3 does not wait for `IN_FENCE_FD`. On it, the output waits for each frame's fence on the CPU and commits without one. A client buffer whose fence is still pending is composed, not scanned out, while `IN_FENCE_FD` is unavailable.
3434
3535 I also like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, and other Go projects can use them:
@@ -29,7 +29,7 @@ About 35 channels connect them, all created in one place, so the full data flow
29 A DRM output flips between two images the renderer draws into, with no CPU copy.29 A DRM output flips between two images the renderer draws into, with no CPU copy.
30 30
31 - **Allocation:** the images are allocated with GBM (`GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING`), with the modifiers the primary plane lists that the renderer can render into and import. The renderer imports them as Vulkan images, and KMS gets framebuffers made from the same dmabufs. GBM is the display driver's own allocator, so the layouts it picks scan out correctly on every driver.31 - **Allocation:** the images are allocated with GBM (`GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING`), with the modifiers the primary plane lists that the renderer can render into and import. The renderer imports them as Vulkan images, and KMS gets framebuffers made from the same dmabufs. GBM is the display driver's own allocator, so the layouts it picks scan out correctly on every driver.
32-- **Fallback:** when libgbm is missing, GBM allocates nothing usable, or Vulkan or KMS refuses the images, the renderer allocates and exports them itself. Each kind (driver modifier, single-plane, linear) tries GBM, then the renderer. The log line `zero-copy output` names the allocator in its `alloc` field (`gbm` or `vulkan`).32+- **Fallback:** when libgbm is missing, GBM allocates nothing usable, or Vulkan or KMS refuses the images, the renderer allocates and exports them itself. Each kind (driver modifier, single-plane, linear) tries GBM, then the renderer. The log line `zero-copy output` names the allocator in its `alloc` field (`gbm` or `vulkan`), and is a warning for `vulkan`. This fallback is deprecated and goes away once GBM is validated on more setups (neferwl#23).
33 - **Sync:** nvidia-drm before 560.35.3 does not wait for `IN_FENCE_FD`. On it, the output waits for each frame's fence on the CPU and commits without one. A client buffer whose fence is still pending is composed, not scanned out, while `IN_FENCE_FD` is unavailable.33 - **Sync:** nvidia-drm before 560.35.3 does not wait for `IN_FENCE_FD`. On it, the output waits for each frame's fence on the CPU and commits without one. A client buffer whose fence is still pending is composed, not scanned out, while `IN_FENCE_FD` is unavailable.
34 34
35 I also like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, and other Go projects can use them:35 I also like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, and other Go projects can use them:
M internal/adapters/drm/images.go +12 -1
@@ -193,6 +193,9 @@ func (o *Output) setupImages(r ports.Renderer, kind imageKind, cause error, skip
193193 }
194194 o.log.Info().Err(gerr).Str("connector", o.conn.name).Int("kind", int(kind)).Str("alloc", allocGBM).Msg("output image allocation")
195195 }
196+ // Deprecated fallback (neferwl#23): renderer-exported images, kept
197+ // while GBM is validated on few setups. Remove once no report shows
198+ // "alloc":"vulkan" for a few releases.
196199 if err = o.exportImages(r, mods, kind == imagesSinglePlane); err == nil {
197200 return kind, nil
198201 }
@@ -232,6 +235,9 @@ func closeBufs(bufs []ports.DMABuf) {
232235 }
233236
234237 // exportImages makes the renderer's exported targets the output images.
238+//
239+// Deprecated fallback for gbmImages, to remove with neferwl#23. Exported
240+// Vulkan images corrupt scanout on nvidia-drm.
235241 func (o *Output) exportImages(r ports.Renderer, mods []uint64, singlePlane bool) error {
236242 o.dropImages(r)
237243 bufs, err := r.ExportTargets(len(o.fbs), mods, singlePlane)
@@ -266,7 +272,12 @@ func (o *Output) showBufs(r ports.Renderer, bufs []ports.DMABuf, alloc string) e
266272 return err
267273 }
268274 o.planes, o.imageMod = len(bufs[0].Planes), bufs[0].Modifier
269- o.log.Info().Str("connector", o.conn.name).Uint64("modifier", bufs[0].Modifier).Int("planes", o.planes).Str("alloc", alloc).Msg("zero-copy output")
275+ ev := o.log.Info()
276+ if alloc == allocVulkan {
277+ // The deprecated fallback is in use: make it visible in reports.
278+ ev = o.log.Warn()
279+ }
280+ ev.Str("connector", o.conn.name).Uint64("modifier", bufs[0].Modifier).Int("planes", o.planes).Str("alloc", alloc).Msg("zero-copy output")
270281 return nil
271282 }
272283
@@ -193,6 +193,9 @@ func (o *Output) setupImages(r ports.Renderer, kind imageKind, cause error, skip
193 }193 }
194 o.log.Info().Err(gerr).Str("connector", o.conn.name).Int("kind", int(kind)).Str("alloc", allocGBM).Msg("output image allocation")194 o.log.Info().Err(gerr).Str("connector", o.conn.name).Int("kind", int(kind)).Str("alloc", allocGBM).Msg("output image allocation")
195 }195 }
196+ // Deprecated fallback (neferwl#23): renderer-exported images, kept
197+ // while GBM is validated on few setups. Remove once no report shows
198+ // "alloc":"vulkan" for a few releases.
196 if err = o.exportImages(r, mods, kind == imagesSinglePlane); err == nil {199 if err = o.exportImages(r, mods, kind == imagesSinglePlane); err == nil {
197 return kind, nil200 return kind, nil
198 }201 }
@@ -232,6 +235,9 @@ func closeBufs(bufs []ports.DMABuf) {
232 }235 }
233 236
234 // exportImages makes the renderer's exported targets the output images.237 // exportImages makes the renderer's exported targets the output images.
238+//
239+// Deprecated fallback for gbmImages, to remove with neferwl#23. Exported
240+// Vulkan images corrupt scanout on nvidia-drm.
235 func (o *Output) exportImages(r ports.Renderer, mods []uint64, singlePlane bool) error {241 func (o *Output) exportImages(r ports.Renderer, mods []uint64, singlePlane bool) error {
236 o.dropImages(r)242 o.dropImages(r)
237 bufs, err := r.ExportTargets(len(o.fbs), mods, singlePlane)243 bufs, err := r.ExportTargets(len(o.fbs), mods, singlePlane)
@@ -266,7 +272,12 @@ func (o *Output) showBufs(r ports.Renderer, bufs []ports.DMABuf, alloc string) e
266 return err272 return err
267 }273 }
268 o.planes, o.imageMod = len(bufs[0].Planes), bufs[0].Modifier274 o.planes, o.imageMod = len(bufs[0].Planes), bufs[0].Modifier
269- o.log.Info().Str("connector", o.conn.name).Uint64("modifier", bufs[0].Modifier).Int("planes", o.planes).Str("alloc", alloc).Msg("zero-copy output")275+ ev := o.log.Info()
276+ if alloc == allocVulkan {
277+ // The deprecated fallback is in use: make it visible in reports.
278+ ev = o.log.Warn()
279+ }
280+ ev.Str("connector", o.conn.name).Uint64("modifier", bufs[0].Modifier).Int("planes", o.planes).Str("alloc", alloc).Msg("zero-copy output")
270 return nil281 return nil
271 }282 }
272 283

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close