Skip to content

Add software GAMMA_LUT/CTM color management on the CRTC#584

Open
iDoMeteor wants to merge 2 commits into
DisplayLink:mainfrom
iDoMeteor:add-crtc-color-management
Open

Add software GAMMA_LUT/CTM color management on the CRTC#584
iDoMeteor wants to merge 2 commits into
DisplayLink:mainfrom
iDoMeteor:add-crtc-color-management

Conversation

@iDoMeteor

Copy link
Copy Markdown

Problem

evdi's virtual CRTC never calls drm_crtc_enable_color_mgmt(), so it
never exposes GAMMA_LUT/CTM DRM/KMS properties. Compositors that
apply color correction exclusively through those CRTC properties
(e.g. GNOME's Night Light) have nothing to set on an evdi output and
silently do nothing there, while native hardware CRTCs on the same
session are corrected normally.

Fix

Since evdi has no real display hardware behind it, there's no
gamma/CTM block to program. This registers the properties (256-entry
gamma LUT, 3x3 CTM) via drm_crtc_enable_color_mgmt() in
evdi_crtc_init(), and applies the resulting transform in software in
evdi_painter.c's copy_primary_pixels()/copy_primary_pixels_on_xe()

  • the only place the driver has direct access to raw pixel bytes
    before they're copied out to userspace via the GRABPIX ioctl.

  • evdi_color.c/.h: self-contained transform (LUT + fixed-point CTM,
    built on drm_fixed.h's S32.32 helpers), independent of whatever LUT
    length a client actually uploads.

  • The transform is skipped entirely (identity fast path, zero added
    cost) unless a client has actually set a LUT or CTM - the common
    case is unaffected.

  • module/tests/test_evdi_color.c: KUnit coverage of identity/gamma/
    CTM/channel-order behavior, no hardware required.

Testing

  • ci/run_style_check (checkpatch.pl): clean on all touched/new files.
  • Built against a running 7.1.3 Fedora kernel's headers (make KVER=...), clean with W=1.
  • Loaded on real hardware (DisplayLink dock + external monitor) and
    confirmed the CRTC now exposes CTM/GAMMA_LUT/GAMMA_LUT_SIZE=256
    via a direct DRM_IOCTL_MODE_OBJ_GETPROPERTIES query.

Note: on my own machine, GNOME's Night Light still doesn't visually
apply to this output in practice - but that traced back to an
unrelated GNOME/Mutter + colord monitor-identity collision (two
identical-model monitors whose EDID doesn't include a serial number),
not to anything in evdi. With a single monitor (or one with a real
EDID serial) behind the dock, this should work end-to-end.

jj added 2 commits July 20, 2026 08:34
evdi's virtual CRTC never called drm_crtc_enable_color_mgmt(), so it
never exposed GAMMA_LUT/CTM properties. Compositors that apply color
correction (e.g. GNOME's Night Light) exclusively through those DRM/KMS
CRTC properties therefore have nothing to set on an evdi output, and
silently do nothing there, while native hardware CRTCs are corrected
normally.

Since evdi has no real display hardware behind it, there is no gamma/
CTM block to program. Instead, register the properties (256-entry
gamma LUT, 3x3 CTM) via drm_crtc_enable_color_mgmt() and apply the
resulting transform in software, in evdi_painter.c's
copy_primary_pixels()/copy_primary_pixels_on_xe() - the only place the
driver has direct access to raw pixel bytes before they are copied out
to userspace via the GRABPIX ioctl. The transform is skipped entirely
(zero added cost) unless a client has actually set a LUT or CTM.

evdi_color.c/.h hold the transform math (LUT + fixed-point CTM,
reusing drm_fixed.h's S32.32 helpers) as a self-contained, unit-tested
component; module/tests/test_evdi_color.c covers identity/gamma/CTM/
channel-order behavior without requiring hardware.

Signed-off-by: jj <jj@fedora.local>
drm_fourcc.h documents DRM_FORMAT_XRGB8888/ARGB8888 as "[31:0] x:R:G:B
... little endian", which puts B at byte 0 and R at byte 2 in memory
(XBGR8888/ABGR8888 swap that). The r_idx/b_idx assignment had this
backwards, so a gamma/CTM transform meant for the red channel was
applied to the blue byte and vice versa.

Confirmed on real hardware: before this fix, Night Light produced a
static purple/cool tint that didn't track the configured color
temperature; after, it correctly renders as a warm orange shift that
tracks temperature changes.

Also corrects module/tests/test_evdi_color.c's expected values, which
had been written to match the buggy output rather than derived
independently from the true byte layout - the previous version of
this test suite could not have caught this bug.

Signed-off-by: jj <jj@fedora.local>
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