protonscr

Wine Wayland HDR: games crash on KWin with invalid_luminance protocol error (min_lum >= max_lum)

protonclosed
ValveSoftware/Proton#9672 · opened 2026-04-15 by omercagatay · updated 2026-04-15 · 4 comments · github
1 matching comments, n / p to jump
Oomercagatay 2026-04-15 github

Summary

Games running through Proton with HDR enabled on KDE Plasma Wayland crash when the game sends HDR mastering display metadata with min_luminance >= max_luminance. KWin rejects the metadata per the wp_color_management_v1 Wayland protocol spec, raising invalid_luminance, which kills the Wayland connection and terminates the game.

This affects NVIDIA specifically because Mesa's WSI implementation filters out invalid luminance values before they reach the compositor, but NVIDIA's driver does not.

Error

[destroyed object]: error 5: min_lum can't be higher or equal to max_lum
err:waylanddrv:wayland_read_events_thread Failed to read events from the compositor, terminating process

Root Cause

  1. Game sends HDR metadata with min_luminance >= max_luminance (often both zero, or nonsensical values)
  2. Proton's Wine Wayland driver (winewayland.drv) passes these values through to wp_color_management_surface_v1.set_mastering_luminance
  3. The Wayland protocol spec mandates: "If max L is less than or equal to min L, the protocol error invalid_luminance is raised"
  4. KWin follows the spec, raises the error, and disconnects the client
  5. Game crashes

Mesa's Vulkan WSI layer sanitizes these values before calling set_mastering_luminance, so this only affects NVIDIA users.

Suggested Fix

Sanitize HDR mastering display luminance values in Wine's Wayland driver (or in Proton's HDR WSI layer) before passing them to the compositor. For example:

  • If min_luminance >= max_luminance, clamp min_luminance to 0
  • Or skip the set_mastering_luminance call entirely when values are invalid

This matches what Mesa's WSI already does and avoids triggering the protocol error regardless of compositor.

Affected Software

  • Proton: proton-cachyos-10.0-20260408-slr (also affects Proton Experimental, GE-Proton)
  • Compositor: KDE Plasma 6.6.4 / KWin on Wayland
  • GPU driver: NVIDIA 595.58.03 (open kernel module)
  • GPU: NVIDIA GeForce RTX 5080 Laptop GPU
  • Kernel: Linux 7.0.0-1-cachyos-gcc
  • Confirmed game: Crimson Desert (AppID 3321460) — likely affects any DX12 game sending invalid HDR metadata through Proton

Reproduction

  1. Enable HDR on KDE Wayland with NVIDIA GPU
  2. Set launch options: PROTON_ENABLE_NVAPI=1 DXVK_ENABLE_NVAPI=1 PROTON_ENABLE_WAYLAND=1 PROTON_ENABLE_HDR=1 ENABLE_HDR_WSI=1 %command%
  3. Launch Crimson Desert (or another game that sends HDR metadata)
  4. Enable HDR in the game's graphics settings
  5. Game crashes immediately with the invalid_luminance protocol error

Workaround

Binary patching KWin's libkwin.so to skip the min_lum >= max_lum validation works but is not a proper fix — it requires the compositor to deviate from the Wayland protocol spec.

Related

Oomercagatay 2026-04-15 github

Temporary Workaround: KWin Binary Patch

Warning: This is an unofficial workaround that binary patches your compositor (libkwin.so) to skip a Wayland protocol validation check. It makes KWin non-spec-compliant and must be reapplied after every KWin update. Use at your own risk. The proper fix belongs in Proton's Wine Wayland HDR WSI layer, as described above.

If you need HDR working in games right now, this script patches out the min_lum >= max_lum validation in KWin:

#!/bin/bash
# Patch KWin to skip min_lum >= max_lum validation in HDR metadata
# Re-run after every KWin update (pacman -S kwin)

set -euo pipefail

LIBKWIN="/usr/lib/libkwin.so"
BACKUP="${LIBKWIN}.bak"
PATCH_FROM="735f"  # jae (jump if above or equal)
PATCH_TO="9090"    # NOP NOP

find_patch_offset() {
    python3 -c "
import sys

with open('${LIBKWIN}', 'rb') as f:
    data = f.read()

errstr = b'min_lum can\x27t be higher or equal to max_lum'
str_offset = data.find(errstr)
if str_offset == -1:
    print('ERROR: error string not found', file=sys.stderr)
    sys.exit(1)

comisd = b'\x66\x0f\x2f\xc1'
candidates = []
pos = max(0, str_offset - 0x200000)
while True:
    idx = data.find(comisd, pos, str_offset)
    if idx == -1:
        break
    patch_offset = idx + 4
    next_bytes = data[patch_offset:patch_offset + 2]
    if next_bytes == b'\x90\x90':
        candidates.append(patch_offset)
    elif next_bytes[0] == 0x73:
        jae_target = patch_offset + 2 + next_bytes[1]
        if b'\xbe\x05' in data[jae_target:jae_target + 30]:
            candidates.append(patch_offset)
    pos = idx + 1

if not candidates:
    print('ERROR: patch location not found', file=sys.stderr)
    sys.exit(1)

offset = candidates[-1]
print(f'{offset:#x} {data[offset:offset+2].hex()}')
"
}

echo "=== KWin HDR min_lum Patch ==="
RESULT=\$(find_patch_offset)
PATCH_OFFSET=\$(echo "\$RESULT" | awk '{print \$1}')
CURRENT=\$(echo "\$RESULT" | awk '{print \$2}')

echo "Location: \${PATCH_OFFSET}  Current: \${CURRENT}"

if [ "\$CURRENT" = "\$PATCH_TO" ]; then echo "Already patched."; exit 0; fi
if [ "\$CURRENT" != "\$PATCH_FROM" ]; then echo "ERROR: unexpected bytes"; exit 1; fi

[ ! -f "\$BACKUP" ] && sudo cp "\$LIBKWIN" "\$BACKUP"

echo "Patching: \${PATCH_FROM} -> \${PATCH_TO}"
sudo python3 -c "
with open('\${LIBKWIN}', 'r+b') as f:
    f.seek(\${PATCH_OFFSET})
    assert f.read(2) == bytes.fromhex('\${PATCH_FROM}')
    f.seek(\${PATCH_OFFSET})
    f.write(bytes.fromhex('\${PATCH_TO}'))
"
echo "Done. Log out and back in to apply."

What it does: Replaces a jae instruction with two NOPs at the point where KWin validates mastering display luminance values, so it accepts the metadata instead of killing the client.

To revert: sudo cp /usr/lib/libkwin.so.bak /usr/lib/libkwin.so and log out/in. Or just update KWin — pacman overwrites the patch.

Tested on: KDE Plasma 6.6.4, KWin 6.5+, NVIDIA 595.58.03, Crimson Desert with proton-cachyos-slr.

Oomercagatay 2026-04-15 github

Also reported to KDE as a feature request to consider clamping instead of disconnecting: https://bugs.kde.org/show_bug.cgi?id=519000

Oomercagatay 2026-04-15 github

Correction: This bug only affects Proton builds that include Wine's native Wayland driver (winewayland.drv), such as proton-cachyos-slr and GE-Proton.

Valve's official Proton Experimental and Hotfix do not ship winewayland.drv — they use XWayland, so they cannot hit this codepath. The original report incorrectly stated it also affects Proton Experimental.

The bug is still relevant for the Proton project since the Wine Wayland driver is upstream and will presumably ship in official Proton builds eventually.

Kkisak-valve maintainer 2026-04-15 github

No, it's not relevant at this time and should be reported to and evaluated in the upstream wine project.