Add software GAMMA_LUT/CTM color management on the CRTC#584
Open
iDoMeteor wants to merge 2 commits into
Open
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
evdi's virtual CRTC never calls
drm_crtc_enable_color_mgmt(), so itnever exposes
GAMMA_LUT/CTMDRM/KMS properties. Compositors thatapply 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()inevdi_crtc_init(), and applies the resulting transform in software inevdi_painter.c'scopy_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
GRABPIXioctl.evdi_color.c/.h: self-contained transform (LUT + fixed-point CTM,built on
drm_fixed.h's S32.32 helpers), independent of whatever LUTlength 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.make KVER=...), clean withW=1.confirmed the CRTC now exposes
CTM/GAMMA_LUT/GAMMA_LUT_SIZE=256via a direct
DRM_IOCTL_MODE_OBJ_GETPROPERTIESquery.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.