Skip to content

Multi-GPU: Secondary AMD GPU output fails with "destination dmabuf unsupported" (external-only) when primary GPU is different AMD card #220

@Narcostic

Description

@Narcostic

Summary

On a dual-AMD system (RDNA4 + Polaris), an output connected to the secondary AMD GPU (RX 480) stays black when another AMD GPU (RX 9070) is the primary DRM device.

Aquamarine detects the connector, creates an output and renderer, and Hyprland assigns a workspace, but the frame commit fails with:

  • EGL (verifyDestinationDMABUF): FAIL, format is external-only
  • EGL (blit): failed to blit: destination dmabuf unsupported
  • drm: Backend requires blit, but blit failed
  • Couldn't commit output named DP-4

If I reverse the AQ_DRM_DEVICES order so that the RX 480 becomes the primary DRM GPU, all monitors (including DP-4) work fine. So this seems to be a multi-GPU blit/DMABUF issue between two AMD GPUs, not a configuration or EDID problem.


Environment

  • OS: NixOS 25.11 (unstable)
  • Kernel: 6.17.9-cachyos
  • GPUs:
    • 03:00.0 AMD Radeon RX 9070 XT (Navi 48) – intended primary / main GPU
    • 09:00.0 AMD Radeon RX 480 (Ellesmere/Polaris10) – secondary, DP-4 monitor attached
    • 0b:00.0 AMD RX 580 – bound to vfio-pci (not used by Aquamarine)
    • 0c:00.0 NVIDIA RTX 2080 – bound to vfio-pci (not used by Aquamarine)
  • Mesa: 25.3.0
    (from OpenGL version string: 4.6 (Compatibility Profile) Mesa 25.3.0)
  • Hyprland: from NixOS nixpkgs hyprland package (unstable channel)
    • Hyprland --version:

      Hyprland 0.52.1 built from branch unknown at commit unknown unknown (unknown).
      Date: unknown
      Tag: unknown, commits: 0
      
      Libraries:
      Hyprgraphics: built against 0.4.0, system has unknown
      Hyprutils: built against 0.10.2, system has unknown
      Hyprcursor: built against 0.1.13, system has unknown
      Hyprlang: built against 0.6.6, system has unknown
      Aquamarine: built against 0.9.5, system has unknown
      

Aquamarine is whatever version Hyprland 0.52.1 in nixpkgs is built against (Hyprland reports built against 0.9.5 above).


Configuration relevant to Aquamarine / DRM

I use udev rules to create stable symlinks for the two AMD GPUs:

services.udev.extraRules = ''
  # RX 9070 XT: 03:00.0 -> /dev/dri/gpu-9070
  SUBSYSTEM=="drm", KERNEL=="card*", SUBSYSTEMS=="pci", \
    KERNELS=="0000:03:00.0", SYMLINK+="dri/gpu-9070"

  # RX 480: 09:00.0 -> /dev/dri/gpu-480
  SUBSYSTEM=="drm", KERNEL=="card*", SUBSYSTEMS=="pci", \
    KERNELS=="0000:09:00.0", SYMLINK+="dri/gpu-480"
'';

Environment variables (set via NixOS):

environment.sessionVariables = {
  # Failing setup (bug present):
  # AQ_DRM_DEVICES = "/dev/dri/gpu-9070:/dev/dri/gpu-480";

  # Working setup (used for comparison and daily use):
  # AQ_DRM_DEVICES = "/dev/dri/gpu-480:/dev/dri/gpu-9070";

  LIBVA_DRIVER_NAME = "radeonsi";
  VDPAU_DRIVER      = "radeonsi";
  AMD_VULKAN_ICD    = "RADV";
};

Hyprland config (relevant bits):

debug {
    full_cm_proto = true
    disable_logs = false
}

cursor {
    no_hardware_cursors = true
}

# Aquamarine-related envs in hyprland.conf
env = AQ_NO_MODIFIERS,1
env = AQ_MGPU_NO_EXPLICIT,1

I start the debug session from a TTY like this:

HYPRLAND_TRACE=1 AQ_TRACE=1 Hyprland

and collect the log from $XDG_RUNTIME_DIR/hypr/<instance>/hyprland.log.


Reproduction steps

  1. Boot into NixOS with both GPUs active:

    • RX 9070: primary GPU, several monitors attached (DP-1, DP-2, DP-3, HDMI-A-1)
    • RX 480: one monitor attached on DP-4 (1680×1050)
  2. Set environment (either via NixOS config or temporarily in the TTY):

    export AQ_DRM_DEVICES=/dev/dri/gpu-9070:/dev/dri/gpu-480
    export AQ_NO_MODIFIERS=1
    export AQ_MGPU_NO_EXPLICIT=1
  3. Start Hyprland from a TTY with tracing enabled:

    HYPRLAND_TRACE=1 AQ_TRACE=1 Hyprland
  4. Hyprland/Aquamarine start correctly, all monitors on RX 9070 work.

  5. The DP-4 monitor on RX 480:

    • wakes up (no “no signal” OSD),
    • is reported by hyprctl monitors as an active monitor with workspace and correct mode (1680×[1050@59.95Hz](mailto:1050@59.95Hz)),
    • but stays completely black (no background, no cursor, no windows).
  6. Check hyprland.log – see error lines shown below.

Now change the environment to:

export AQ_DRM_DEVICES=/dev/dri/gpu-480:/dev/dri/gpu-9070

and restart Hyprland.

With RX 480 as first/primary and RX 9070 second, all outputs including DP-4 work perfectly, with the same hardware and Hyprland config.


Expected behavior

With:

AQ_DRM_DEVICES=/dev/dri/gpu-9070:/dev/dri/gpu-480

I expect:

  • Primary DRM GPU: RX 9070

  • Secondary DRM GPU: RX 480

  • Both GPUs usable by Aquamarine, including:

    • All monitors on RX 9070 working
    • Monitor on RX 480 (DP-4) also showing the compositor output (desktop, cursor, windows), like it does when RX 480 is primary.

In other words: cross-GPU blitting from the primary GPU’s renderer to the secondary GPU’s scanout should succeed, or at least degrade gracefully, not result in a black screen.


Actual behavior

With AQ_DRM_DEVICES=/dev/dri/gpu-9070:/dev/dri/gpu-480:

  • Aquamarine detects RX 9070 as primary DRM GPU:

    [LOG] [AQ] drm: gpu /dev/dri/card1 becomes primary drm
    
  • It then detects and initializes DP-4 on RX 480:

    [LOG] [AQ] drm: Basic init pass for gpu /dev/dri/card0
    [LOG] [AQ] drm: Scanning connector id 92
    [LOG] [AQ] drm: Initializing connector id 92
    [LOG] [AQ] drm: Connector gets name DP-4
    ...
    [LOG] [AQ] drm: Connector DP-4 connected
    [LOG] [AQ] drm: Connecting connector DP-4, CRTC ID 75
    [LOG] [AQ] drm: Dumping detected modes:
    [LOG] [AQ] drm: Mode 0: 1680x1050@59.95Hz (preferred)
    ...
    [LOG] [AQ] drm: Description Acer Technologies P223W LAW0C0158610 (DP-4)
    
  • Aquamarine creates a renderer on RX 480:

    [LOG] [AQ] CDRMRenderer(drm): Using device /dev/dri/card0
    [LOG] [AQ] Creating CDRMRenderer on gpu /dev/dri/renderD129
    [LOG] [AQ] Renderer: AMD Radeon RX 480 Graphics (radeonsi, polaris10, ...)
    

Then the multi-GPU blit path kicks in and fails:

[LOG] [AQ] drm: Modesetting DP-4 with 1680x1050@59.95Hz
[TRACE] [AQ] drm: Committed a buffer, updating state
[TRACE] [AQ] drm: Backend requires blit, blitting
[WARN] [AQ] GBM: Using modifier-less allocation
[LOG] [AQ] GBM: Allocated a new buffer ... modifier 72057594037927935 aka INVALID
...
[ERR] [AQ] EGL (verifyDestinationDMABUF): FAIL, format is external-only
[ERR] [AQ] EGL (blit): failed to blit: destination dmabuf unsupported
[ERR] [AQ] drm: Backend requires blit, but blit failed
[ERR] Couldn't commit output named DP-4
[LOG] Monitor DP-4 -> destroyed all render data

Result:

  • DP-4 remains black, even though:

    • The monitor is considered connected and active by DRM,
    • Hyprland lists it as an active monitor with a workspace.

With the reversed order:

AQ_DRM_DEVICES=/dev/dri/gpu-480:/dev/dri/gpu-9070

the above error path does not trigger and DP-4 works as expected.


Additional context

  • This is not a simple EDID/CRTC issue:

    • The connector modes and EDID for DP-4 look correct.
    • The same monitor and cable work fine when the RX 480 is first in AQ_DRM_DEVICES.
  • The issue only appears when:

    • The primary DRM GPU is RX 9070,
    • The secondary DRM GPU is RX 480,
    • And DP-4 is connected to RX 480.
  • Other GPUs (RX 580, RTX 2080) are bound to vfio-pci and should be ignored by Aquamarine.

From my reading of the log, the core bug seems to be that the destination DMABUF for the secondary GPU’s output is marked “external-only” and Aquamarine aborts the blit instead of using a compatible intermediate buffer or a safer fallback path, which results in the output being unusable even though it’s otherwise properly detected and modeset.

I’m happy to test patches or additional debug instrumentation if that helps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions