Blooey In case it's helpful, I took a couple of pictures this morning to show the effect of Stillcolor on my MBA M2 15-inch using your test pattern: https://imgur.com/a/uIge5kx

(Ignore the haloing around the white text… that's a demosaicing artifact from my camera.)

Given how strong the banding effect is at 9-bit, 10-bit, etc. with dither OFF, I think it's fairly likely that Stillcolor turns off both GPU and TCON dither (that's assuming there is normally any TCON dither in addition to GPU dither, which I'm not sure there is).

There is a well-known bug in Apple Silicon power management that would probably allow us to investigate whether there is normally any TCON dither; I'll make a post about that in a bit.

    async just last night actually! I came across it and and an AppleDisplayTCONControl private framework! Absolute treasure trove!

    libAppleTCONUpdater.dylib

    This seems to be the kernel code responsible for updating the TCON's firmware either through system software updates or perhaps using the Apple System Configurator. In theory if Apple wanted to turn off TCON dithering they can do so overnight via a software update.

    It uses IOAVDisplayMemoryRead and IOAVDisplayMemoryWrite heavily. If the TCON firmware is not cryptographically locked down we should in theory be able to reverse engineer this code and write to the device's memory. But we're gonna require Asahi-level reverse engineering chops.

    There's functionally different code for handling DP835 (possibly the base M1 TCON model), and DP855.

    AppleDisplayTCONControl

    At first glance, this private framework is less write-heavy and seems more about dumping data, generating reports and diagnostics. But we have our first confirmed hit of a dithering LUT!

    "TCON_LOAD_DITHERLUT"

    A debugging string probably used right before loading this particular LUT. There are references to many other LUTs too:

    PG LUT, SCALER LUT, DEGAMMA LUT, ENGAMMA LUT, WPC LUT, PRC LUT, IBC LUT, TRINITY LUT, CABAL LUT, BL CAL LUT, BRIGHTNESS LUT, KSF COMP LUT

    It appears that several of the IOMobileFramebuffer properties we've seen affect the TCON directly. Most notably PCC* and APT* (Apple TCON / Apple Parade TCON?) props.

    There are also references to EDID and DisplayPort stuff.

    I'm gonna spend some time trying to extract these LUTs and see if this helps us progress.

      Here is the ioreg for the M1 Air.

      "AppleParadeDP835TCONI2CPLS"=0,
      "AppleParadeDP835TCON"=0,
      “AppleParadeDP835TCONI2CTps65177"=0,
      "AppleParadeDP835TCONI2C"=0,
      "AppleParadeDP815TCON"=0,
      "AppleParadeDP855TCON"=1,

      Thanks for the great work. Makes my Macbook usable at last.

      Very happy to have found this thread and Stillcolor. It's massively improved the performance of e-ink monitors connected to my MacBook. Much appreciated 🙂

      Also wanted to add to the some of advice above to switch ProMotion devices to 60Hz. I get less eyestrain leaving ProMotion on but forcing it to stay at 120Hz. My hacky method…

      1. Install the https://tracesof.net/uebersicht/ widget manager
      2. Install the https://tracesof.net/uebersicht-widgets/#SmoothAnalogClock_widget widget

      ^ as long as the hands of the clock are turning and on a screen it maxes out the refresh rate

      This is optional, but I then made the clock all black (I have a pure black desktop), the height of my dock, and placed it the bottom left of my screen by editing the widget code. So it's always on screen, but not visible for me as long as all my windows are above the dock.

      Only tested it on a 16" MacBook M3 Max using Quartz Debug from 'Additional_Tools_for_Xcode_15'.

      It adds around 8% load to the GPU on my MacBook, and battery performance still seems fine to me.

        My friend who tried stillcolor on Mac said he also gets banding with stillcolor off BUT when using quick shade to dim the screen🤔

        Rowe interesting concept! I tried this with 1 external display connected, and the Quartz fps shot up to 240, I guess adding up fps of both displays.

        I can note no changes in Blooey gradient banding while 120fps is in effect which means that ProMotion does not reduce bpc.

        This trick should work with an inconspicuous menu bar item that animates at 120fps+.

        • Rowe replied to this.

          aiaf Awesome. I actually saw a reference to some cryptography function in one of the TCON ones. Still not certain things have to be as complex as editing the memory directly or messing with the firmware. Could be possible to just load one of the libs and start toggling options.

          When unpacking remember that some stuff is only available in the x86 cache, so both needs to be unpacked.

          I found Binary Ninja to be the best for browsing around.

          If anyone else wants to dig around this is roughly what I did:

          brew install keith/formulae/dyld-shared-cache-extractor
          dyld-shared-cache-extractor \
          /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e \
          $HOME/Projects/dyld-cache-arm64e

          dyld-shared-cache-extractor/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_x86_64 \
          $HOME/Projects/dyld-cache-x86_64

          cd $HOME/Projects/

          grep --recursive -i uniformity2D (find all libraries with some refernce to a certain string)

          There is also another tool to see what a framework depends on that can be useful

          brew install dylibtree
          dylibtree --depth 3 \
          --shared-cache-path /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e \
          $HOME/Projects/dyld-cache-arm64e/System/Library/PrivateFrameworks/AppleDisplayTCONControl.framework/Versions/A/AppleDisplayTCONControl

          • aiaf replied to this.

            photon78s I also am using the blackmagic ultrastudio recorder 3g capture device to test for dithering on hdmi output. The problem I have is I am recording no dithering at all on my should-be-dithering windows 11 pc. In my ffmpeg diff videos, moving the mouse will create the dithering effect but I should be seeing much more. I did try with an elgato capture card and that was capturing dithering. Just wondering what I am doing wrong with the blackmagic device.

            I don't have my capture setup nor a target device handy, but I was able to record a lack of dithering on a dithering setup by some degradation of color depth by the capturing PC, and nothing the output device was doing (unless there was some sort of bidirectional signaling outside of EDID going on). Sorry for not having more details.

              JTL

              Also using the same blackmagic device (bmd) and its drivers? What is your capturing device? In fact, my original thinking before Stillcolor was developed was to use a cheap hdmi to usb capture device (which I had purchased originally for my DSLR to use as webcam) with visible lossy compression and low color depth to view problematic windows PCs with dithering through OBS on a "safe" device which now is a mac.

              While I was recording on the capturing PC, I toggled Stillcolor off and then on on the mac mini. In the ffmpeg diff video, you can see the dithering appear then disappear in real time so that is confirmation of it working.

              DannyD2 Very cool. That is what I was expecting to see with the test image.

              dithering More bands above 8-bit. With some higher levels losing band edge sharpness if not enough frames are used in the dither.

              no dithering No additional bands above 8-bit. And sharp edged bands accross the entire test image.

              Your photos seem to meet that description. But on my M1 MacBook Pro 16", nothing significant changes with Stillcolor. It behaves more as if I have a native 10-bit panel. I see crisp edged, doubling bands all the way up to 10-bit, with and without Stillcolor. Above 10-bit the bands become muddy, and not clearly defined, with and without Stillcolor.

                aiaf 'This trick should work with an inconspicuous menu bar item that animates at 120fps+' Yes, that would be a good improvement

                photon78s Thanks! That is interesting. What model display is this? What I see is that even the 8-bit level breaks down without Apple dithering. That surprises me if this is truly an 8-bit native panel.

                And I think we can see from the no Apple dithering photograph that the banding does still have blending between divisions at the 8+ bit levels. This makes sense since the FRC of the LG display is likely taking over the dithering. To do this, it needs 9-bit or greater input signal. With an older/slower 8-bit cable, the banding should be sharp edged above 8-bits, and roughly match the 8-bit level in band count.

                What you are seeing here is what I would expect on a built in display of a MacBook if the TCON was taking over dithering. But @DannyD2 shows the MacBook Air M2 15" does not show any evidence of the TCON dithering taking over for Apple dithering.

                Another interesting note about your photos is how much higher quality the Apple dithering is than the LG TCON dithering, in terms of color. The edges are sharper above the native panel depth. So it makes good sense why Apple wants to pass their proprietary dithering to a display. And once they do, a dithering algorithm down the chain cannot touch Apple's signal. A dithered signal should simply pass through any further attempt at dithering down the chain, unchanged.

                But I am still curious why your LG display sees improvement with dithering at the 8-bit level. This really indicates that the panel is only 6-bit. I'm not sure if 7-bit native panels exist, but that would fit what we are seeing more accurately.

                  photon78s I just realized it's perfectly reasonable that the 8-bit level can show inconsistent banding. Even on an 8-bit native display. Because I forgot about ColorSync. The image has been color corrected for that monitor, so the linear 8-bit values are being shifted into non-native, higher bit depth levels. This explains why dithering even improves the 8-bit level.

                  Aggressive color correction should cause the native bit-level to break down. Something like Apple Night Shift, Apple True Tone, or any other aggressive icc color profile can in this way activate dithering on the native bit depth. Very cool to see this effect in your photo.

                    Blooey Don't forget about the monitor's own color settings too, adjusting contrast, gamma, or RGB values in the monitor OSD will clamp the color range further will introduce more banding

                    (And if there is some monitor where doing that doesn't introduce banding, that might mean the monitor itself is adding additional spatial or temporal dithering to the signal whenever it's own color adjustments are used)

                    async you're absolutely right. I really don't want to mess with the TCON just yet. My attempts to read from it have already failed from user space.

                    Instead, I'm going to re-visit my assumptions about _IOMobileFramebufferEnableDisableDithering and the following:

                    From IOKit _IOAVVideoInterfaceSetColorDitherRemoval
                    From SkyLight _WSWindowSetDitherDisabled
                    From CoreDisplay _CGXDisplayGetDither _CGXDisplaySetDither gDisplayDither
                    From IOSurface _kIOSurfaceDisplayDitherCbThresholds _kIOSurfaceDisplayDitherCrThresholds _kIOSurfaceDisplayDitherThresholds _kIOSurfaceDisplayDitherYThresholds

                    The thing that occurred to me is what if IOMobileFramebufferEnableDisableDithering (which calls IOMobileFramebufferAP::enable_disable_dithering) is not merely a setter for enableDither and actually does more than that, i.e. what if it configures the TCON too?

                    So I'm going to try to invoke these methods from a kext and see what happens.

                      Blooey

                      So for the user, what would you recommend for settings both for the monitor and in the OS? In the LG I have it set to default contrast and a "sRGB game mode" in which settings like gamma, color temp, and R/G/B are unavailable greyed out in the OSD. In the Mac OS, I have it set to sRGB IEC61966-2.1 for color profile. I don't use night shift and I don't have true tone available since this is a non-supported external monitor.

                      I'm picking up an M2 Air pretty soon to try out, I will let y'all know how it works for me with Stillcolor running on Sonoma 🙂

                      I possibly might be able to try an M2 Pro (13", Touch Bar, standard LCD) later this week too

                        dev