CGSetDisplayTransferByTable is broken on macOS Tahoe 26.4 RC (and 26.3.1) with MacBook M5 Pro, Max and Neo

The CGSetDisplayTransferByTable() is not working on the latest round of Mac hardware, namely the MacBook Neo (external display), MacBook M5 Pro (both built-in and external display) and possibly the M5 Max.

All tested apps (BetterDisplay, MonitorControl, f.lux, Lunar) exhibit the very issue both in macOS Tahoe 26.3 and macOS Tahoe 26.4 RC. Tested on multiple Macs and installations on the MacBook Neo and MacBook M5 Pro.

This issue breaks several display related macOS apps.

Way to reproduce the issue using an affected app:

  • Install the app BetterDisplay (https://betterdisplay.pro)
  • Launch the app, open the app menu, choose Image Adjustments and try to adjust colors.
  • Adjustments take no effect

Way to reproduce the issue programmatically:

  • Attempt to use the affected macOS API feature:

https://developer.apple.com/documentation/coregraphics/cgsetdisplaytransferbytable(::::_:)


Here are the FB numbers:

  • FB22273730 (Filed this one as a developer on an unaffected MBP M3 Max)
  • FB22273782 (Filed from an affected MBP M5 Pro running 26.4 RC, with debug info attached)

Thank you for reporting this — it's a clear and well-documented write-up.

I was able to reproduce this on a MacBook M5 Max running macOS 26.3.1 (25D2128).

I built a small test app that exercises both CGSetDisplayTransferByTable and CGSetDisplayTransferByFormula with several different gamma tables (identity, warm tint, inverted, red-only, gamma 1.8). On the M5 Max:

  • Both APIs return kCGErrorSuccess
  • Reading back the table with CGGetDisplayTransferByTable returns the correct values that were just set
  • No visual change occurs on the display

The same test app works correctly on an M5 (non-Max) machine running the same macOS build — all gamma changes are immediately visible on screen.

This suggests the gamma tables are being stored correctly at the CoreGraphics level, but are not being applied to the display pipeline on M5 Max hardware.

Tested on both built-in and external displays.

I've related your two bugs (FB22273730 and FB22273782) together and attached the sample project I used to reproduce the problem to your bug report.

Please continue to test your software in release and pre-release versions of system software made available to you through your developer.apple.com account. When you do, add details about that into your bug report to keep it up to date. Please see https://developer.apple.com/download/.

Thanks for the thorough write-up and reproduction steps. This is a critical issue for display calibration workflows — tools like DisplayCAL and hardware colorimeters depend on CGSetDisplayTransferByTable for the final LUT upload. The fact that CGGetDisplayTransferByTable reads back correctly but the display pipeline ignores it suggests the disconnect is in the GPU driver or display controller firmware layer, not CoreGraphics itself.

For anyone affected and needing a workaround in the interim: check if setting the ColorSync profile directly via ColorSyncDeviceSetCustomProfiles produces visible changes — it uses a different path to the display pipeline and might bypass whatever is broken in the gamma table application.

An other, related issue with CGSetDisplayTransferByTable() - this is probably not the best place to note this, but since macOS Tahoe there is an inconsistency in how the API works. The 26.4 RC is also affected.

Before macOS Tahoe CGSetDisplayTransferByTable() redefined the color table of the SDR range and clipped the HDR range (much like custom color profiles in macOS usually do the same). In macOS Tahoe it does the same thing for most displays – except for the built-in XDR displays, when auto brightness is enabled and the display is in EDR mode (meaning: there is some HDR content on screen).

When this happens (XDR + auto brightness + EDR mode), the contents of the CGSetDisplayTransferByTable is being used to multiply the entire EDR (SDR+HDR) gamma range instead of overwriting the SDR range and clipping the HDR range. This might be a blessing in disguise for some apps (that use this feature for color adjustments or brightness upscaling like BetterDisplay - as this allows avoiding HDR clipping when a custom color table is being used for image adjustments), but since the behavior is inconsistent (with auto brightness disabled the very same function does affect only the SDR range and clips the enitre HDR range at 1.0 - peak SDR - luminance level as it used to do pre-Tahoe), this is probably just a bug, not a feature. Additionally, when a custom color table is applied to a built-in XDR display while in EDR mode is active, when the user turns of auto-brightness, the color table usually ends up in an inconsistent state (and the screen looks permanently bad until the user changes presets or do something similarly drastic) even after the app using CGSetDisplayTransferByTable() is terminated.

I do not have an FB filed for this one as honestly I saw very low chance of it reaching the appropriate engineers (being such an edge-case) - just wanted this to be out in case somebody in the team working on these things can do something about it. :)

CGSetDisplayTransferByTable is broken on macOS Tahoe 26.4 RC (and 26.3.1) with MacBook M5 Pro, Max and Neo
 
 
Q