Skip to content

drm/apple: VRR on the desktop 26.6 panel without a mode set, no GAMMA_LUT on desktop 26.x - #763

Merged
RyanTheTide merged 2 commits into
aurora-wipfrom
j616s/vrr-gamma
Nov 1, 2026
Merged

RyanTheTide merged 2 commits into
aurora-wipfrom
j616s/vrr-gamma

Conversation

@RyanTheTide

Copy link
Copy Markdown
Contributor

Two display fixes for desktop 26.x DCPs (J616s, M4 Pro), measured on a J616s.

VRR never turned on in fullscreen on the panel. mutter toggles VRR_ENABLED in a plain page flip. The desktop 26.6 path made that a mode set, so the flip failed with EINVAL ("Page flip failed: drmModeAtomicCommit: Invalid argument" in the journal) and VRR stayed off. A mode set doesn't work for it either: the firmware tears the link down, and the panel goes dark for about 200 ms each time (207 ms commits).

On the panel, VRR timings are now installed with adaptive sync on. VRR_ENABLED then only moves the minimum rate on the live mode (IOMFBParameter 14): the mode's minimum when on, its nominal rate when off. The panel firmware applies that without a mode set.

The external processors ignore a live minimum. On an MSI MPG 325CQRXF (48-280 Hz), a live 280, 279 or 240 Hz left the idle desktop at 48 Hz, so the externals keep today's mode-set behaviour. VRR in fullscreen on externals needs a different mechanism and comes later.

KDE HDR looked washed out, and night light did nothing on the panel. GAMMA_LUT was accepted and then dropped ("unusable firmware gamma table, GAMMA_LUT ignored"). The driver composes the LUT through a firmware table that A420 doesn't hand out on these DCPs: the panel's table is not monotonic, and the external processors return status 2.

KWin, in its default "prefer efficiency" colour mode, tests a commit, then puts its blending-to-PQ curve into GAMMA_LUT. The panel therefore showed gamma 2.2 values as PQ. mutter's night light went into the same ignored table.

GAMMA_LUT is no longer offered on desktop 26.x. KWin then applies its curves while rendering, and mutter uses CTM for night light, which the DCP applies. Writing the gamma table directly (A421) is planned as a separate colour change.

How tested. J616s (T6041, DCP firmware 26.6.2), tt3 kernel, with these commits loaded as a test appledrm on one-shot boots, undocked and docked (Acer QG270 S3, MSI MPG 325CQRXF).

VRR:

  • Fullscreen glmark2-wayland under GNOME flips VRR_ENABLED to 1 and back to 0. The firmware logs minRR 0x180000, then 0x780000, with no failed flips and no link reselect.
  • Idle with a static image, the panel draws 440 mW less with VRR on than with it off. A mode-set toggle gives 290 mW less, a minRR of 0 when off only 70 mW. So the live minimum takes effect.
  • With VRR_ENABLED=0 the externals come up fixed (minRR 0, VRR=NO), as before.

GAMMA_LUT and night light:

  • GAMMA_LUT is gone from all three CRTCs and CTM is still there.
  • GNOME night light sets a CTM on the panel CRTC, with no failed flips.
  • A white field with CTM diag(1, 0.7, 0.4) shows warm, so the channel order is right.

Build and selftests:

  • Host selftests (tools/testing/selftests/drivers/gpu/apple-dcp/run.py): 83/83. vrr-rejection now checks that a VRR_ENABLED change never becomes a mode set on the panel, and still does on an external processor.
  • arm64 LLVM W=1 build of drivers/gpu/drm/apple: no warnings.

🤖 Generated with Claude Code

… set

GNOME never turned on variable refresh for a fullscreen game on the
J616s panel. Compositors toggle VRR_ENABLED in a plain page flip, but
the desktop 26.6 path made a VRR_ENABLED change a mode set, so the flip
failed with EINVAL ("Page flip failed: drmModeAtomicCommit: Invalid
argument" in the journal) and VRR stayed off. With ALLOW_MODESET the
toggle works but costs a full link reselect: the firmware shuts the
link down, the backlight is off for about 200 ms and the commit takes
207 ms on the panel (272 ms on an external display).

On the panel, install a VRR timing with adaptive sync on whatever
VRR_ENABLED says, at the mode's minimum rate, as the pipe pair path
already does. VRR_ENABLED then only moves the minimum rate on the live
mode (IOMFBParameter 14, sent ahead of the frame's swap): the mode's
minimum when on, its nominal rate when off, which holds the panel at
that rate. The firmware takes the new minimum without a mode set. The
external processors don't: on an MSI MPG 325CQRXF (48-280 Hz) a live
minimum of 280, 279 or 240 Hz left the idle desktop at 48 Hz, so they
keep applying VRR_ENABLED with a mode set.

On the J616s panel (3456x2234, 24-120 Hz, firmware 26.6.2) a fullscreen
glmark2-wayland under GNOME now flips VRR_ENABLED to 1 and back with no
failed flips and no link reselect. Idle with a static image, the panel
draws 290 mW less with VRR on than off when toggled through a mode set,
and 440 mW less when toggled live, so the live minimum rate takes
effect.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
KDE Plasma in HDR on the J616s panel looked washed out, and night light
did nothing there under GNOME.

GAMMA_LUT on desktop 26.x is composed through the firmware table that
A420 returns. On the J616s panel that table does not rise monotonically
and the external processors return none (status 2), so the driver logged
"unusable firmware gamma table, GAMMA_LUT ignored" and dropped every LUT
after accepting it in atomic check. KWin, with its default "prefer
efficiency" colour setting, tests and then moves its blending-space to
PQ curve into GAMMA_LUT, so the panel got gamma 2.2 code values read as
PQ. mutter put night light into the same ignored table.

Offer no GAMMA_LUT on desktop 26.x until the table can really be
programmed. KWin then applies its curves while rendering, and mutter
falls back to the CTM, which the DCP applies: a white field with CTM
diag(1, 0.7, 0.4) shows warm on the J616s panel.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
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