Files
punktfunk/crates
enricobuehler dea6395772 fix(capture): xdph offers BGRA on its dmabuf pod, and we offered BGRx, so the link never negotiated
A Hyprland/sway client went black with no error of ours: PipeWire failed the
link itself with

    pw.link: (73.0.0 -> 81.0.0) negotiating -> error no more input formats (-22)

Measured on Hyprland 0.55.4 + xdph 1.3.12 by dumping both EnumFormat pods from
the PipeWire DAEMON (`PIPEWIRE_DEBUG=*:1,pw.link:5` — the pods are not in our
own process's log, which is why this hid for so long):

  ours   BGRx only | 12 NVIDIA tiled + 0 (LINEAR)      | MANDATORY
  xdph   BGRA only | the same 12 + MOD_INVALID         | MANDATORY|DONT_FIXATE
  xdph   BGRA or BGRx, no modifier                     | (the SHM pod)

The modifiers intersect perfectly. Only the fourcc never does, which is exactly
why the failure reads as a GPU/modifier problem and is not one — the host's own
message ("the compositor never accepted the dmabuf-only offer (EGL->CUDA GPU
import)") points at the GPU, and our advert line prints only the first 6 of 13
modifiers so LINEAR is invisible. Both misled a full session of debugging.
Since our offer is dmabuf-only, xdph's mixed SHM pod could not rescue it.

Offer a BGRA dmabuf pod beside the BGRx one. BGRA and BGRx are the same 32-bit
layout, the alpha byte is ignored all the way to the encoder (`vk_util` maps
both to B8G8R8A8_UNORM, VAAPI both to Pixel::BGRA), and the import is driven by
the NEGOTIATED format's fourcc, so an AR24 frame imports as AR24.

Vendor-neutral by construction: the two modifier lists are enumerated PER FOURCC
(`XR24` and `AR24` asked separately), because EGL and libva answer per format and
nothing entitles us to assume a driver importing one imports the other. On the
VAAPI passthrough path there is no importer, so both lists are LINEAR (plus the
PyroWave Vulkan set when armed) — AMD and Intel get the BGRA pod on the same
terms as NVIDIA rather than an NVIDIA-shaped guess.

The BGRA pod is listed AFTER BGRx, so a producer offering both still lands on
the pre-existing path — first compatible consumer pod wins, so this is purely
additive. Both pods are now guarded on a non-empty list (`build_dmabuf_format`
indexes `modifiers[0]`).

Also name `linear_offered` and both counts in the advert log, so the truncated
`sample` can no longer be misread as the whole offer.
2026-08-14 23:56:35 +02:00
..