Skip to content

Graphics Debugging & Troubleshooting

Real-world debugging for when the display stack breaks. This article covers systematic diagnosis of the most common failures: black screen after boot, compositor crashes on hotplug, tearing despite VSync, GPU hangs and resets. Then the complete debugging toolkit: Mesa debug environment variables, DRM kernel debugging, Wayland protocol tracing, the "works on X11 but not Wayland" checklist, and strace patterns for graphics ioctls. Every section includes the actual commands and output you would see when diagnosing the problem.


1. "Black Screen After Boot"

The most common graphics failure. Systematic diagnosis from the bottom of the stack upward.

Step 1: Do you have a console?

# If the screen is completely black, try switching to a text VT
Ctrl+Alt+F2    # switch to VT2
# If this works: the kernel and display driver are fine, the compositor failed
# If this does not work: the problem is in the kernel display driver

Step 2: Kernel console

# Add kernel parameters to force a text console (edit bootloader):
# GRUB: edit at boot, append to linux line:
nomodeset                         # disable KMS entirely (uses BIOS framebuffer)
# OR:
drm.modeset=1 fbcon=map:0        # force framebuffer console on first output

# If nomodeset gives you a console: the DRM driver is the problem
# If even nomodeset fails: hardware issue, cable, or BIOS/UEFI config

Step 3: DRM debug logging

# Enable comprehensive DRM/KMS debug logging (kernel parameter):
drm.debug=0x1ff

# This enables ALL DRM debug categories:
# 0x001 = DRM_UT_CORE      (core DRM)
# 0x002 = DRM_UT_DRIVER    (driver-specific)
# 0x004 = DRM_UT_KMS       (modesetting)
# 0x008 = DRM_UT_PRIME     (PRIME/dma-buf)
# 0x010 = DRM_UT_ATOMIC    (atomic modesetting)
# 0x020 = DRM_UT_VBL       (vblank handling)
# 0x040 = DRM_UT_STATE     (state management)
# 0x080 = DRM_UT_LEASE     (DRM leases)
# 0x100 = DRM_UT_DP        (DisplayPort)

# Runtime (without reboot):
echo 0x1ff > /sys/module/drm/parameters/debug

# Read the debug output:
dmesg | grep -i '\[drm\]'
journalctl -k | grep -i drm

Step 4: Check connector and EDID

# List all DRM connectors and their status
cat /sys/class/drm/card0-*/status
# card0-HDMI-A-1/status: connected
# card0-DP-1/status: disconnected

# Read EDID (monitor identification)
cat /sys/class/drm/card0-HDMI-A-1/edid | edid-decode
# If EDID is empty or corrupt: the monitor is not communicating properly

# Or use drm_info (comprehensive DRM information)
drm_info
# Shows: connectors, CRTCs, planes, formats, modifiers, EDID

Step 5: Manual modesetting test

# modetest: set a mode manually, bypassing the compositor entirely
# This proves whether the kernel DRM driver can drive the display

# List available modes
modetest -M i915 -c    # -M <driver>, -c = connectors
# Output:
# Connectors:
#   32 HDMI-A-1 (connected)
#     Modes:
#       1920x1080@60.00   ← use this

# Set a test pattern
modetest -M i915 -s 32:1920x1080@60.00
# If this shows a test pattern: kernel driver works, problem is userspace
# If this fails: kernel driver bug or hardware issue

Step 6: Check initramfs

# If the display works with nomodeset but not with KMS:
# The DRM driver might not be in the initramfs

# List modules in initramfs
lsinitramfs /boot/initramfs-$(uname -r).img | grep -E 'drm|i915|amdgpu|nouveau'

# If your GPU driver is missing, add it:
# Debian/Ubuntu:
echo "i915" >> /etc/initramfs-tools/modules
update-initramfs -u

# Dracut (Fedora/RHEL):
echo 'add_drivers+=" i915 "' > /etc/dracut.conf.d/gpu.conf
dracut --force

Decision tree

graph TD
    Start["Black screen"] --> VT{"Ctrl+Alt+F2<br/>works?"}
    VT -->|Yes| Comp["Compositor problem<br/>(check Sway logs)"]
    VT -->|No| NoModeset{"nomodeset<br/>gives console?"}
    NoModeset -->|Yes| DRMBug["DRM driver issue<br/>(check dmesg, drm.debug)"]
    NoModeset -->|No| HW["Hardware/cable/BIOS issue"]
    DRMBug --> Modetest{"modetest<br/>shows pattern?"}
    Modetest -->|Yes| UserSpace["Userspace issue<br/>(EGL, Mesa config)"]
    Modetest -->|No| KernelBug["Kernel driver bug<br/>(check firmware, EDID)"]

2. "Compositor Crashes on Output Hotplug"

Plugging/unplugging a monitor (or a VNC client connecting/disconnecting to a virtual output) triggers DRM connector probing. This is a common crash vector.

The problem

When a connector state changes:

  1. Kernel sends a DRM hotplug uevent.
  2. Compositor re-probes all connectors (drmModeGetConnector()).
  3. If a connector was removed: its CRTC, planes, and framebuffers become invalid.
  4. If the compositor still holds references to these objects: crash (use-after-free or invalid ioctl).

Diagnosis

# Monitor DRM hotplug events
udevadm monitor --subsystem-match=drm
# KERNEL[12345.678] change /devices/pci.../drm/card0 (drm)
# ACTION=change, HOTPLUG=1

# Check connector state after hotplug
cat /sys/class/drm/card0-*/status

# In Sway debug log:
sway -d 2>&1 | grep -E 'hotplug|output|connector'
# [DEBUG] output_manager: output HDMI-A-1 disconnected
# [ERROR] wlr_output_commit: invalid CRTC   ← crash incoming

EDID parsing failures

Some monitors send corrupt or non-standard EDID data:

# Read raw EDID
cat /sys/class/drm/card0-HDMI-A-1/edid | xxd | head -20

# Parse with edid-decode (shows warnings for non-standard data)
cat /sys/class/drm/card0-HDMI-A-1/edid | edid-decode 2>&1
# WARN: EDID block 0 checksum is invalid
# WARN: Non-standard detailed timing descriptor

# Force a specific mode if EDID is unreliable:
# Kernel parameter:
video=HDMI-A-1:1920x1080@60e    # 'e' = force enable
# Or in Sway config:
output HDMI-A-1 mode 1920x1080@60Hz

Fallback modes

When EDID fails, the kernel falls back to a built-in mode list:

# The kernel's fallback modes (drivers/gpu/drm/drm_edid.c):
# 1024x768@60Hz (the "safe" mode)
# 800x600@60Hz
# 640x480@60Hz

# Check which mode is actually active
cat /sys/class/drm/card0-HDMI-A-1/modes
# If only low resolutions appear: EDID is the problem

3. "Tearing Despite VSync"

Tearing means the display shows parts of two different frames simultaneously. Even with VSync "enabled", tearing can occur.

Understanding the presentation modes

graph LR
    subgraph "Double Buffering + VSync (FIFO)"
        FB1["Front Buffer<br/>(displayed)"] --> Swap["Swap at<br/>vblank"]
        FB2["Back Buffer<br/>(rendering)"] --> Swap
    end
Mode Behavior Tearing? Latency
Immediate (no sync) Swap buffers instantly Yes Lowest
FIFO (VSync on) Wait for vblank to swap No +1 frame (16.67ms)
FIFO relaxed FIFO, but if you miss vblank, swap immediately Sometimes Variable
Mailbox (triple buffering) Latest frame replaces previous in mailbox, swap at vblank No Lowest without tearing

Why tearing still happens with VSync

Cause 1: Legacy page flip (not atomic)

The old drmModeSetCrtc() / drmModePageFlip() API can tear if the flip is not synchronized with vblank:

# Check if Sway is using atomic modesetting
sway -d 2>&1 | grep -i atomic
# [DEBUG] wlr_drm: using atomic modesetting
# If you see "using legacy modesetting" → upgrade wlroots or check DRM driver

Cause 2: Direct scanout format/modifier mismatch

When Sway attempts direct scanout (client buffer → display, no compositing), it may choose a buffer with the wrong format or modifier:

# Check if direct scanout is happening
sway -d 2>&1 | grep -i scanout
# [DEBUG] output: direct scanout for surface 0xNNNN
# [WARN] output: direct scanout failed, falling back to compositing

Cause 3: Multi-plane tearing (hardware bug)

Some GPU hardware has tearing between overlapping planes (primary + cursor, primary + overlay). The atomic commit should be atomic across planes, but some drivers have bugs:

# Disable hardware cursor (forces cursor into compositing pass)
# Sway config:
seat * hide_cursor when-typing enable
# Or: WLR_NO_HARDWARE_CURSORS=1 sway

Cause 4: VRR (Variable Refresh Rate) misconfiguration

With VRR (FreeSync/G-Sync), the display refresh rate adapts to the application. If VRR is partially enabled, you can get tearing:

# Check VRR status
cat /sys/class/drm/card0-HDMI-A-1/vrr_capable
# 0 = not supported, 1 = supported

# Enable/disable in Sway:
output HDMI-A-1 adaptive_sync on   # enable VRR
output HDMI-A-1 adaptive_sync off  # disable VRR

4. "GPU Hang / Reset"

A GPU hang means the GPU stops processing commands. The kernel driver detects this (usually via a watchdog timer) and attempts a reset.

Reading dmesg for GPU hangs

# Intel i915
dmesg | grep -E 'GPU HANG|i915.*reset|Resetting'
# [  123.456] i915 0000:00:02.0: GPU HANG: ecode 9:1:0x00000000,
#     in chromium [1234], reason: Hang on render ring, action: reset
# [  123.789] i915 0000:00:02.0: Resetting chip for Hang on render ring

# AMD amdgpu
dmesg | grep -E 'amdgpu.*reset|gpu_recover|job timeout'
# [  456.789] amdgpu 0000:03:00.0: amdgpu: GPU reset begin!
# [  456.800] amdgpu: ring gfx timeout, but soft recovered
# [  457.123] amdgpu 0000:03:00.0: amdgpu: GPU reset succeeded

GPU hang analysis

# Intel: capture GPU error state (devcoredump)
ls /sys/class/devcoredump/devcd*/
cat /sys/class/devcoredump/devcd0/data > gpu-hang.bin

# Decode with intel_error_decode (from intel-gpu-tools)
intel_error_decode < gpu-hang.bin
# Shows: batch buffer contents, register state, which shader was running

# AMD: devcoredump analysis
cat /sys/class/devcoredump/devcd0/data | umr --dump-ib
# Shows: the GPU instruction buffer that was running when the hang occurred

Common GPU hang causes

Cause Symptoms Fix
Shader infinite loop Consistent hang on specific content WebGL content issue; --disable-webgl in Chromium
Memory corruption Random hangs, different contexts Update GPU firmware, Mesa, kernel
Power management Hang after idle period i915.enable_rc6=0 (Intel) or amdgpu.dpm=0 (AMD)
Overheating Hang under load, mcelog thermal events Check cooling, sensors output
Firmware bug Hang at specific GPU frequency Update linux-firmware package
# Update GPU firmware (most GPU hangs are firmware bugs)
apt update && apt install -y linux-firmware
# Reboot for firmware to take effect

# Check current firmware version
dmesg | grep -i firmware
# [    2.345] i915: loaded firmware i915/tgl_guc_70.1.1.bin

5. Mesa Debugging Toolkit

Mesa is the userspace graphics driver stack. It provides debug knobs for every level.

Environment variables

# General Mesa debug
MESA_DEBUG=1 sway          # enable Mesa debug output
MESA_DEBUG=flush sway      # flush after every GL call (slow but catches errors)
LIBGL_DEBUG=verbose sway   # verbose GL context creation

# Force software rendering (bypass GPU entirely)
LIBGL_ALWAYS_SOFTWARE=1 sway
# Uses llvmpipe (CPU-based GL). If this works and hardware GL crashes:
# the problem is in the GPU driver.

# EGL debugging
EGL_LOG_LEVEL=debug sway
# Shows: EGL context creation, config selection, display initialization

# Vulkan debugging
VK_LOADER_DEBUG=all sway   # Vulkan loader debug
MESA_VK_ABORT_ON_DEVICE_LOSS=1 sway  # abort() on GPU hang (for debugging)

Shader debugging

# Dump compiled shaders to disk
MESA_SHADER_DUMP_PATH=/tmp/shaders sway
# Creates .glsl / .spirv files for every compiled shader

# Read back shader stats
MESA_SHADER_READ_PATH=/tmp/shaders sway
# Useful for testing shader modifications without recompiling Mesa

# Intel-specific: dump shader assembly
INTEL_DEBUG=bat,vs,fs sway
# bat = batch buffers, vs = vertex shaders, fs = fragment shaders

apitrace: record and replay GL calls

# Record all GL calls made by Sway
apitrace trace --api=egl sway

# Replay the trace (on any machine with compatible GL)
apitrace replay sway.trace

# Dump the trace as text (every GL call with parameters)
apitrace dump sway.trace | head -100
# 1 eglGetPlatformDisplay(platform = EGL_PLATFORM_GBM_KHR, ...)
# 2 eglInitialize(dpy = 0x1, major = &3, minor = &0)
# 3 eglChooseConfig(...)

# Find the GL call that causes a hang
apitrace replay --headless --loop sway.trace
# Binary search: apitrace trim to narrow down the problem call

RenderDoc (Vulkan/GL frame analysis)

# Capture a frame for analysis
renderdoccmd capture sway
# Opens a frame capture that shows:
# - Every draw call
# - Texture contents at each stage
# - Shader source code
# - Pipeline state (blend, depth, stencil)
# - GPU timing per draw call

6. DRM Kernel Debugging

drm.debug kernel parameter

The DRM subsystem has extensive debug logging controlled by a bitmask:

# Enable at boot (GRUB kernel parameter):
drm.debug=0x1ff

# Enable at runtime:
echo 0x1ff > /sys/module/drm/parameters/debug
# WARNING: this produces ENORMOUS log output. Use targeted bits:

# Just KMS/modesetting:
echo 0x04 > /sys/module/drm/parameters/debug
# Just atomic commits:
echo 0x14 > /sys/module/drm/parameters/debug
# Just dma-buf/PRIME:
echo 0x08 > /sys/module/drm/parameters/debug

drm_info: comprehensive DRM state

# Install: apt install drm-info (or build from source)
drm_info
# Output shows:
# - Device: /dev/dri/card0 (i915)
# - Connectors: HDMI-A-1 (connected), DP-1 (disconnected)
# - CRTCs: CRTC 0 (active, 1920x1080@60.00)
# - Planes: primary (formats: XRGB8888, ARGB8888, NV12...)
# - Modifiers: I915_FORMAT_MOD_Y_TILED, LINEAR

modetest: manual modesetting

# modetest is from libdrm-tests / drm-utils

# List everything
modetest -M i915

# Set a specific mode with a color pattern
modetest -M i915 -s 32:1920x1080@60.00 -P 31@51:1920x1080+0+0
# -s <connector_id>:<mode>
# -P <plane_id>@<crtc_id>:<WxH+X+Y>

# Test atomic modesetting
modetest -M i915 -a -s 32:1920x1080@60.00
# -a = use atomic API

Tracing DRM ioctls with strace

# Trace all DRM ioctls made by Sway
strace -e trace=ioctl -f -p $(pidof sway) 2>&1 | grep -i drm
# ioctl(7, DRM_IOCTL_MODE_ATOMIC, ...)    ← atomic commit
# ioctl(7, DRM_IOCTL_MODE_GETCONNECTOR, ...) ← connector probe
# ioctl(7, DRM_IOCTL_MODE_ADDFB2, ...)    ← add framebuffer
# ioctl(7, DRM_IOCTL_GEM_CLOSE, ...)      ← free buffer

# Measure ioctl latency
strace -e trace=ioctl -T -f -p $(pidof sway) 2>&1 | grep DRM_IOCTL_MODE_ATOMIC
# ioctl(7, DRM_IOCTL_MODE_ATOMIC, ...) = 0 <0.000234>
#                                            ^^^^^^^^ 234 microseconds

7. Wayland Protocol Debugging

WAYLAND_DEBUG=1

The most important Wayland debugging tool. Logs every protocol message between client and compositor:

# Debug a specific client
WAYLAND_DEBUG=1 chromium --ozone-platform=wayland 2>&1 | head -50
# [1234567.890]  -> wl_compositor@3.create_surface(new id wl_surface@8)
# [1234567.891]  -> xdg_wm_base@5.get_xdg_surface(new id xdg_surface@9, wl_surface@8)
# [1234567.892]  -> xdg_surface@9.get_toplevel(new id xdg_toplevel@10)
# [1234567.893]  -> xdg_toplevel@10.set_title("Chromium")
# [1234567.894]  -> wl_surface@8.commit()
# [1234567.895] wl_display@1.error(xdg_surface@9, 4, "xdg_surface not configured")
#                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#                                                      Common error: commit before configure

# Debug the compositor side (all clients)
WAYLAND_DEBUG=server sway 2>&1 | grep -E 'error|destroy|commit'

Protocol message format

[timestamp]  -> object@id.method(args)     # client → compositor (request)
[timestamp]     object@id.event(args)      # compositor → client (event)

Common protocol errors

Error message Cause Fix
xdg_surface not configured Client committed before handling the initial configure event Wait for xdg_surface.configure before committing
wl_buffer not released Client destroyed a buffer still in use by compositor Wait for wl_buffer.release before destroying
invalid object Client sent a request on a destroyed object Object lifecycle bug
no buffer attached Client committed a surface with no buffer Attach a buffer (wl_shm or dma-buf) before commit

wlhax: Wayland protocol inspector

# wlhax interposes between client and compositor
wlhax -- chromium --ozone-platform=wayland
# Shows protocol messages with pretty-printed arguments

# Filter for specific interfaces
wlhax --filter='wl_surface,xdg_*' -- chromium --ozone-platform=wayland

libinput debug-events

For input debugging (keyboard, mouse, touch):

# Show all input events as received by libinput
sudo libinput debug-events
# event4  POINTER_MOTION   +3.456s   12.34/ 5.67
# event4  POINTER_BUTTON   +3.789s   BTN_LEFT  pressed
# event6  KEYBOARD_KEY     +4.012s   KEY_A     pressed

# Show device capabilities
sudo libinput debug-events --show-keycodes
# Useful for diagnosing: "key not working", "mouse inverted", "touchpad gestures broken"

8. The "It Works on X11 but Not Wayland" Checklist

When an application works on X11 but fails on Wayland, check these in order:

1. XWayland fallback

# Check if the app is running on XWayland or native Wayland
xprop -root | grep -i wayland  # runs on X11 (shows nothing meaningful)
# Better: check the app's environment
cat /proc/$(pidof myapp)/environ | tr '\0' '\n' | grep DISPLAY
# DISPLAY=:0     ← XWayland
# WAYLAND_DISPLAY=wayland-1  ← native Wayland
# Both present → app might use either

# Force XWayland (workaround)
GDK_BACKEND=x11 myapp
QT_QPA_PLATFORM=xcb myapp

# Force native Wayland
GDK_BACKEND=wayland myapp
QT_QPA_PLATFORM=wayland myapp
ELECTRON_OZONE_PLATFORM_HINT=wayland myapp

2. Missing Wayland protocols

# Check which protocols the compositor supports
wayland-info
# Outputs all interfaces and versions. Look for:
# - xdg_wm_base (v6)          ← window management
# - zwp_linux_dmabuf_v1 (v5)  ← zero-copy buffers
# - wp_viewporter (v1)         ← buffer scaling
# - xdg_activation_v1 (v1)    ← window activation
# - wp_fractional_scale_v1    ← fractional scaling

# If a protocol is missing and the app needs it:
# the app will fall back to a less efficient path or fail

3. Client-Side Decorations (CSD) vs Server-Side (SSD)

# Sway uses SSD by default for xdg_toplevel
# If an app draws its own title bar AND the compositor draws one:
# → double decorations

# Check if the app supports xdg-decoration protocol
WAYLAND_DEBUG=1 myapp 2>&1 | grep decoration
# If no decoration negotiation: app assumes CSD

# Sway config to force CSD or SSD:
for_window [app_id="chromium"] border none    # no SSD
for_window [app_id="firefox"] border normal   # SSD with title bar

4. Clipboard and drag-and-drop

# X11 clipboard (CLIPBOARD, PRIMARY) ↔ Wayland clipboard
# XWayland bridges this automatically
# Native Wayland apps use wl_data_device

# Debug clipboard issues
wl-copy "test"    # copy to Wayland clipboard
wl-paste          # paste from Wayland clipboard
xclip -o          # paste from X11 clipboard (via XWayland bridge)

5. Screen capture / recording

The biggest X11 → Wayland difference. X11 allows any client to capture any window (XGetImage). Wayland does not. Solutions:

# Wayland screen capture protocols:
# - ext-image-copy-capture-v1 (new, preferred, Sway 1.10+)
# - wlr-screencopy (wlroots-specific, widely supported)
# - xdg-desktop-portal + PipeWire (GNOME/KDE)

# Check if PipeWire screen sharing works
pw-cli ls
# Look for video source nodes

# For OBS:
# Needs xdg-desktop-portal-wlr (for Sway) or portal-gnome

6. Input method (IME)

# Wayland IME protocol: zwp_text_input_v3
# Supported by: Sway (wlroots), GNOME, KDE

# Check if IME works
WAYLAND_DEBUG=1 myapp 2>&1 | grep text_input
# If no text_input messages: app does not support Wayland IME
# Workaround: run via XWayland

9. strace Patterns for Graphics

Tracing DRM ioctls

# All DRM ioctls with timing
strace -e trace=ioctl -T -f -p $(pidof sway) 2>&1 | \
    grep -E 'DRM_IOCTL_(MODE_ATOMIC|MODE_ADDFB|PRIME|GEM)'

# Decoded ioctl names (strace knows DRM ioctls since strace 5.x)
strace -e trace=%ioctl -y -f -p $(pidof sway) 2>&1 | grep drm
# ioctl(7</dev/dri/card0>, DRM_IOCTL_MODE_ATOMIC, ...) = 0 <0.000234>
#       ^ -y flag shows the file path

Spotting failed GBM allocations

# Trace GBM buffer allocations (via ltrace)
ltrace -e 'gbm_bo_create+gbm_bo_create_with_modifiers' -p $(pidof sway)
# gbm_bo_create(0x55a, 1920, 1080, 875713112, 5) = 0x55b  ← success
# gbm_bo_create(0x55a, 3840, 2160, 875713112, 5) = 0      ← FAILED

# The format argument (875713112 = 0x34325258 = "XR24" = XRGB8888)
# If gbm_bo_create returns NULL: the GPU driver does not support
# this format/modifier combination at this resolution

Finding the blocked ioctl

When Sway or a client hangs, find which syscall it is stuck on:

# Show the current syscall for each thread
cat /proc/$(pidof sway)/task/*/syscall
# If you see:
# 16 0x... 0x... 0x... ...  ← syscall 16 = ioctl
# Then strace -p to see which ioctl:
strace -p $(pidof sway) -e trace=ioctl
# ioctl(7, DRM_IOCTL_MODE_ATOMIC, ...) ← stuck here = waiting for vblank or GPU

# Or check the kernel wait state
cat /proc/$(pidof sway)/task/*/wchan
# drm_atomic_helper_wait_for_flip_done   ← waiting for page flip
# schedule                                ← sleeping (epoll_wait probably)

Tracing mmap for GPU buffer mapping

# Trace all mmap/munmap calls (GPU buffer creation/destruction)
strace -e trace=mmap,munmap,mmap2 -f -p $(pidof sway) 2>&1 | \
    grep -v 'PROT_READ.*MAP_PRIVATE'  # filter out library loads
# mmap(NULL, 8294400, PROT_READ|PROT_WRITE, MAP_SHARED, 8, 0) = 0x7f...
#            ^^^^^^^^ = 1920*1080*4 bytes = one XRGB8888 framebuffer
#                                           ^^^^^^^^^^^ fd 8 = a dma-buf

10. Debugging Checklist by Symptom

Symptom First check Second check Third check
Black screen Ctrl+Alt+F2 (VT switch) dmesg \| grep drm modetest manual mode
Crash on hotplug sway -d log near crash udevadm monitor --subsystem=drm EDID: edid-decode
Tearing sway -d \| grep atomic Check VRR: cat vrr_capable Disable hardware cursor
GPU hang dmesg \| grep -i hang devcoredump in /sys/class/devcoredump/ Update linux-firmware
Slow rendering intel_gpu_top / radeontop GALLIUM_HUD=fps sway perf record -p PID
Wrong colors Check format: drm_info \| grep format MESA_DEBUG=1 Force XRGB8888
No Vulkan vulkaninfo ls /usr/share/vulkan/icd.d/ Set VK_ICD_FILENAMES
Client crash WAYLAND_DEBUG=1 myapp Look for protocol errors coredumpctl debug
Missing output sway -d \| grep output cat /sys/class/drm/card*/status Check cable/adapter
Flickering sway -d \| grep damage Atomic commit errors in dmesg Try WLR_NO_HARDWARE_CURSORS=1

What's new (2025--2026)
  • DRM panic handler (kernel 6.12): displays a QR code on kernel panic, linking to a bug report. Written in Rust by Jocelyn Falempe (Red Hat).
  • ext-image-copy-capture-v1: the new standard Wayland screen capture protocol, replacing the wlroots-specific wlr-screencopy. Sway 1.10 supports it.
  • Mesa 24.3+: improved error messages for buffer allocation failures, making MESA_DEBUG=1 much more useful.
  • intel_gpu_top now shows per-engine utilization for Xe2 (Lunar Lake) GPUs.

Glossary

DRM (Direct Rendering Manager)
Kernel subsystem managing GPU hardware: modesetting, buffer management, command submission.
KMS (Kernel Mode Setting)
DRM subsystem controlling display outputs: modes, CRTCs, planes, connectors.
EDID (Extended Display Identification Data)
Data structure sent by monitors over DDC (I2C), describing supported resolutions, timings, and capabilities.
modetest
Tool from libdrm-tests for manual DRM modesetting. Sets modes, creates framebuffers, displays test patterns.
drm_info
Tool displaying comprehensive DRM device information: connectors, CRTCs, planes, formats, modifiers.
devcoredump
Kernel mechanism for GPU drivers to dump hardware state after a hang. Available via /sys/class/devcoredump/.
apitrace
Tool for recording and replaying OpenGL/EGL API calls. Essential for reproducing GPU bugs.
GALLIUM_HUD
Mesa environment variable enabling real-time GPU metrics overlay (FPS, draw calls, VRAM usage).
XWayland
X11 compatibility layer running inside a Wayland compositor. Provides X11 services for legacy apps.
WAYLAND_DEBUG
Environment variable (set to 1 or server) enabling Wayland protocol message logging.
VRR (Variable Refresh Rate)
Display technology (FreeSync/G-Sync) where the monitor adapts its refresh rate to the application's frame rate.
nomodeset
Kernel parameter disabling KMS. Falls back to BIOS framebuffer. Used for diagnosis when KMS fails.
Direct scanout
Optimization: the compositor sends a client's buffer directly to the display without a compositing pass.
wl-copy / wl-paste
Command-line tools for Wayland clipboard access. Part of the wl-clipboard package.
PipeWire
Multimedia framework handling both audio and video streams. Used for Wayland screen capture via xdg-desktop-portal.