Skip to content

server: make a dma-buf import of a compressed export ask for the export's size (AFBC) - #71

Draft
collegeming wants to merge 1 commit into
ASEbrahim:mainfrom
collegeming:fix/afbc-export-metadata
Draft

collegeming wants to merge 1 commit into
ASEbrahim:mainfrom
collegeming:fix/afbc-export-metadata

Conversation

@collegeming

Copy link
Copy Markdown

Problem

On Mali-G2-Ultra-NX MC16 (driver r56), a Zink surface exported as a dma-buf at DRM-modifier tiling:

Format / extent / usage / flags VK_FORMAT_B8G8R8A8_UNORM, 1668x2173, 0x97, 0x8
Modifier list [DRM_FORMAT_MOD_LINEAR, 0x0820000000000101, ...]; the driver chose 0x0820000000000101
vkGetImageMemoryRequirements 3,760,128 bytes (1728x2176 at 8bpp: the 16x16 superblocks' payload)
vkGetImageSubresourceLayout (COLOR and MEMORY_PLANE_0) offset 0, rowPitch 27,648, size 3,760,128

27,648 is 108 superblocks x 256 bytes, one superblock row of payload.

The same process then imported the dma-buf with
VkImageDrmFormatModifierExplicitCreateInfoEXT { drmFormatModifier = DRM_FORMAT_MOD_LINEAR, planeCount = 1, pPlaneLayouts = {offset 0, rowPitch 27,648, size 0} }.
Mali read the pitch as a pixel row's: 27,648 x 2172 + 6,672 = 60,058,128 bytes, and
vkAllocateMemory against the 3,760,128-byte dma-buf failed with
VK_ERROR_INVALID_EXTERNAL_HANDLE (-1000072003):

vkbridge-server W dma-buf import: 60058128 bytes asked for, the dma-buf has 3760128 (an importer's image laid out unlike the exporter's?)
vkbridge-server W device 457: vkAllocateMemory of 60058128 bytes in memory type 12 (flags 0xb, heap 0), dedicated to an image, dma-buf import, failed: -1000072003
MESA: error: zink: couldn't allocate memory: heap=0 size=60058128

Zink loses the surface and Gecko falls back to wl_shm.

The explicit AFBC modifier with the full layout instead is refused by the driver with
VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT.

Root cause

Mali's explicit-layout path sizes an image from the plane rowPitch as if it were a pixel row's.
For a compressed export the pitch is a superblock row's, so the requirement becomes ~16x the
dma-buf. The layout itself is what vkGetImageSubresourceLayout answered for the export, and the
bridge answers vkGetImageDrmFormatModifierPropertiesEXT for that export image with the true
modifier (0x0820000000000101, logged). No bridge answer can tell an importer the modifier when its
caller names LINEAR; the layout is what identifies the export.

Fix

  • server/server_dmabuf_meta.c/.h: a register of the newest 64 dma-buf exports this server made
    (format, extent, mip and layer counts, the modifier the driver chose, and the plane layout
    vkGetImageSubresourceLayout answered).
  • server/server_emu_layer.c: a dma-buf import that names an explicit DRM modifier and one plane
    layout matching a registered export is created at the export's modifier alone, without the
    explicit plane layout. The driver lays it out exactly as the exporter did; the requirement then
    matches the dma-buf, and the layout and modifier answers are the exporter's. If the driver refuses
    the modifier list, the original create info is restored and the existing retries run.
  • LINEAR exports are not registered: an importer that names LINEAR for a LINEAR export is right.
  • docs/afbc-dmabuf-import.md: measurements, a reproduction without an application, expected logs.
  • tests/dbmeta_unit.c with host/Makefile, host/CMakeLists.txt and host/run_ci_tests.sh.

Test evidence

Unit: dbmeta_unit 14/14 PASS (matching, size 0, wrong pitch/offset/format/extent/mips/layers,
LINEAR exports, newest wins, the oldest falls out).

Device, isolated server on a private socket and a probe that reproduces the shape:

before: B[LINEAR mod + exporter pitch] create OK, requirement 60058128, import VK_ERROR_INVALID_EXTERNAL_HANDLE
after:  B[LINEAR mod + exporter pitch] create OK, requirement 3760128,  import VK_SUCCESS
        B[exporter layout (offset pitch size)] create VK_SUCCESS, requirement 3760128, import VK_SUCCESS
        D list image import: VK_SUCCESS (unchanged)

and the server logs:

dma-buf import image (format 44 1668x2173): its layout (offset 0, row pitch 27648, size 3760128) is the dma-buf export's; made at modifier 0x820000000000101 without the explicit plane layout

Real application, Zen 1.24.1b (Zink through the project's Mesa), same isolated server: before, the
60,058,128 allocation failure above; after, no 60 MB allocation, and the import is made at
0x0820000000000101.

Known boundary

After the import is fixed, Zen's wl_buffer still names DRM_FORMAT_MOD_LINEAR with stride 27,648,
and the compositor refuses it:

(niri) Wayland protocol error: [destroyed object]: error 6: Invalid stride (27648) or height (2173) for plane 0.

That metadata is produced by the exporter, not by the bridge: the bridge answers
vkGetImageDrmFormatModifierPropertiesEXT for the export image with the true modifier, and the
exporter is the one handing the buffer to the compositor. An exporter must use the modifier it
queried, or a stride that matches the modifier it names. This PR does not change any answer given to
the exporter; it stops the importer from being sized from a compressed pitch. Until the exporter is
fixed, the failure moves from the allocation to the compositor.

Risk and rollback

  • The register only answers exact matches (format, extent, mips, layers, offset, row pitch), only for
    non-LINEAR exports, and only with the dma-buf export emulation on. A miss leaves the previous
    behaviour untouched.
  • If the driver refuses the modifier list, the create info goes back to what the application asked.
  • No format, protocol, client or default-branch changes. Revert the single commit to roll back.

…rt's size

Mali r56 lays an AFBC image out with the superblock row pitch (1668x2173 BGRA8:
27,648) and answers that pitch from vkGetImageSubresourceLayout, while the memory
requirement is the 16x16 superblocks' payload (3,760,128 bytes). An importer that
passes the layout back while naming DRM_FORMAT_MOD_LINEAR has the pitch read as a
pixel row's: 27,648 x 2172 + 6,672 = 60,058,128 bytes asked of a 3,760,128-byte
dma-buf, and vkAllocateMemory fails with VK_ERROR_INVALID_EXTERNAL_HANDLE (-1000072003).
Zink loses the surface and Gecko falls back to wl_shm. The explicit AFBC modifier
with the full layout is refused by the driver outright
(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT).

The server now remembers the shape and plane layout of the dma-buf exports it made
(server_dmabuf_meta.c) and, when an import carries one of them, creates the image at
the export's modifier without the explicit plane layout: the driver lays it out as
the exporter did, vkGetImageMemoryRequirements matches the dma-buf, and the layout
and modifier answers stay the exporter's. LINEAR exports are not remembered - their
importers are right about LINEAR - and the client is unchanged.

tests/dbmeta_unit.c covers the register and runs in host/run_ci_tests.sh.
docs/afbc-dmabuf-import.md has the measurements, a no-application reproduction and
the remaining exporter-side boundary (Zen's wl_buffer names LINEAR with the
compressed stride; the compositor then refuses it).
@collegeming
collegeming force-pushed the fix/afbc-export-metadata branch from e7ee6be to 186ba9b Compare November 8, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant