@aiaf do you have any pointers for being able to use IOKit in Swift on iOS so I could experiment with adjusting enableDither on my iOS devices? IOKit is a private framework on iOS and gives an error when trying to import it with IOKit.

Some people said they could use it through Objective-C instead, but I don't know how to write ObjC at all (despite me being very experienced with Swift). However, even when trying to do this just to see if it would work, I actually couldn't get IOKit to load in ObjC either.

———

FYI: As I am a mobile developer, I have a LOT of iOS devices I've collected over the years… so I can certainly help with testing anything iOS-related if this ever becomes something you're interested in.

For reference:

Devices I own with "good screens": iPhone 4 (iOS 7), iPhone 5 (iOS 6.1.3 native, but also runs iOS 7/8 via dual boot), iPhone 6 (iOS 12), iPhone 7 (iOS 15), iPad mini 2 (iOS 10.2), iPad 6 (iOS 15)

Devices I own with "bad screens": iPhone 5s (iOS 12), iPad Pro 11" 2018 (iOS 17), iPhone SE 2 (iOS 17.2.1), iPhone 14 Pro (iOS 16.4)

    DisplaysShouldNotBeTVs Update: I'd recommend only disabling dithering and uniformity2D — as disabling NormalModeEnable seems to make the system less stable / cause the cursor to lag / eventually randomly crash the WindowServer and log out.

    Disabling the other two, dithering and uniformity2D, works totally fine and that does most of the work in improving the screen, so disabling normal mode isn't that necessary.

    I'm still not sure which property will get rid of the "blotches of slightly different colors".

    I wonder why disabling NormalModeEnable is causing this?

    @aiaf just found AN IMPORTANT ONE

    Disable VUCEnable

    This causes even more banding to appear on the gradient test than just disabling dithering on my M1 Max XDR.

    Additionally, "irregular patterns of boxes" appear on certain solid color background shades.

    Potentially this is disabling the internal panel's FRC???

    If you turn the Mac backlight up to max and Software Brightness (BetterDisplay) very far down, you will also now see a "dark, heavily banded blotch that follows the mouse cursor like a trail" when moving the mouse on a dark gray background. (Easily seen after zooming in with Ctrl+Scroll accessibility zoom.)

    This confirms another thing I swear I could see for years, where it always felt like there was a dark spot around the mouse or that there was an area flickering around the mouse (specifically on the internal display). There IS, and it was literally being dithered (i.e. flickered) to hide it, too.

    This will also make a strange "animation" visible (that was present before but now very obvious) of all the "blotches" I've pointed out moving around whenever Software Brightness is changed, lagging behind a second or so with what seems like an intentionally smoothed out animation — even when BetterDisplay's own "software brightness smoothing" is disabled.

    I still don't know how to disable these blotches, but one thing's clear — they're basically programmed to "move around in the corner of your eye at a slower, smoothed out rate compared to everything else" whenever colors change on screen. And before enableDither=false, uniformity2D=false and VUCEnable=false, the effect was being dithered very aggressively in order to "hide" whatever this is.

      @aiaf firstly, thank you so much for your work on this, I can instantly feel a difference once enabled on an external studio display.

      @DisplaysShouldNotBeTVs thanks for your work too, and any chance you could share your code for additional properties you've disabled? I've tried to update the existing program but am getting the below errors so must have missed something

      Failed to set VUCEnable to true IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument

      Failed to set VUCEnable to true IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument

      Thanks!

        tmfd Go to Stillcolor at the top left of the Xcode file tree, then "Stillcolor" under TARGETS, then Signing and Capabilities. If you see stuff like "App Sandbox" and "Hardened Runtime" here, there should be trash can icons at the top right of each of them. Click the trash can on both so all you're left with is one tab called "🔻 Signing". This will remove the app sandbox and allow those properties to be changed.

        Then, just comment out the alert.runModal() line that shows the alert box that says "Stillcolor Issue". It will say "invalid argument" some times but then end with a "successful" anyway in the console after it tries a couple of times, so even though it makes it "look like" it didn't work, it does make the change as long as app sandbox is disabled and you eventually see "returned 0 -> (os/kern) successful" in the Xcode console.

        For example, here's what I get in the console when I disable VUCEnable:

        (Disabled = box checked in the Stillcolor menu bar BTW)

        AppleCLCD2 service: 310b
        AppleCLCD2 client: a17b
        IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        Failed to set VUCEnable to false IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        AppleCLCD2 service: 310f
        AppleCLCD2 client: a17f
        IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        Failed to set VUCEnable to false IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        AppleCLCD2 service: 3113
        AppleCLCD2 client: a183
        IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        Failed to set VUCEnable to false IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        AppleCLCD2 service: 3117
        AppleCLCD2 client: a187
        IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        Failed to set VUCEnable to false IORegistryEntrySetCFProperty returned -536870206 -> (iokit/common) invalid argument
        AppleCLCD2 service: 311b
        AppleCLCD2 client: a18b
        IORegistryEntrySetCFProperty returned 0 -> (os/kern) successful
        VUCEnable set to false

        It says "failed" a bunch of times, but eventually ends with successful, and the VUC change works in the end.

          Folks, do not waster your time. These dithering setting tweaks pretty much do nothing, or some very minor superficial stuff. It must be hardware related. You can tweak, you can install Asahi, all you do is change software, while hardware will remain the same. Also I have put myself into bad position by taking m2 airbook 13 for little workcation as only machine, and then when work duties came in I was torturing myself really badly with it. My conclusion software tweaks do nothing, only superficial stuff. And also limit your time with this machine as much as possible, because if you have it brand new you kind of excited with all the bells and whistles, but then after some time, it will create some real problems for you.

            Donux

            Donux These dithering setting tweaks pretty much do nothing, or some very minor superficial stuff.

            I cannot agree with this conclusion. The hardware has specific set of capabilities (like temporal dithering) which can be controlled via software. We can write at the specific control register in the graphics card to enable/disable dithering. The legal interface for this is the IORegistryEntrySetCFProperty() API.

              NewDwarf many thanks for your boot-args work too, it really lay the ground for a software solution! Do you have dumps or anything from reversing these drivers? Doesn't have to neat, just a gist or some hint on which frameworks to look at?

              DisplaysShouldNotBeTVs this is all very exciting! Thanks so much for trying these out, I've added these options in my own build and will release it soon. VUCEnable is particularly interesting because it changes the quality of banding- the bands are less regular and less logical so to speak? I'm not sure if this is says anything about dithering yet though.

              uniformity2D is also very obvious. It disables the vignette effect.

              Can you make a list of all the options you tried. There are still a ton of other options on the IOFramebuffer object, I will diff those soon.

              In other news I got my Carson microscope and will start recording befores and afters.

                Donux I don't deny that you are facing eyestrain issues with the internal display, even with software tweaks. But one of the primary functions of software is to control hardware, in fact that's the point of a display driver, and what we're doing here is modifying display driver settings to change the behavior of a display.

                Blooey interesting findings, thanks for testing! One thing is sure is that display manufacturers cannot be trusted with this information. We have to perform independent testing. I got my Carson microscope today and will do my own.

                Donux I don't agree. Stillcolor has made a huge difference for me on my M2 Air 15. I've probably used my computer more in the last few days than I've used it in the last month; the display feels so comfortable now. It seems like there are more issues to investigate on the MBPs because the display on the MBPs is more complex, but on the Airs this is definitely a game changer.

                @DannyD2 What kind of symptoms you get from displays and are you sensitive to PWM. Are there some displays that you can use?

                I'm asking to understand if you have the same situation as I have, so I could also get M2 and test stillcolor. I dont' want to do it right away, as I ve tested about 20 laptops and screens and TV's and I don't want to waste my time

                  Maxx Mackbook Air 15'' M2 is PWM free. So, by disabling the dithering we totally get rid (I hope) the main issues which cause problems. This can explain why MBA 15'' M2 becomes comfortable to use.

                  At the same time, many MBP models are NOT PWM free and even if dithering is disabled, one can fill discomfort.

                  …to measure the screen PWM, I made the special adapter based on the photoresistor. I plug it to the oscilloscope to measure the PWM value. It can measure up to 200 kHz.

                  Blooey

                  I have recorded some probably tens of dozen's of videos by now with different internal and external panels. I may have observed pixel inversion on a intel iGPU T480s laptop running a known dithering free OS/driver combination (windows 10 1809 with no intel graphics driver installed). Columns of pixels simultaneously gradually increase and decrease in brightness. Is this pixel inversion? In my other videos of other panels, the dithering flicker is with different pairs/groups of rgb pixels scattered at different places. The frequency may also be different and the groups pixels in a column are not exactly flickering in sync.

                  Videos labeled dithering or pixel inversion (recorded all on 60Hz panel with 240 fps camera played back in slow-mo at 30 fps). Also, best to download the video not view them within dropbox.
                  https://www.dropbox.com/scl/fo/47fw3ygxkxaq78ul0j19i/h?rlkey=a2fvkmlujs2m9tkmdw59ujwvl&dl=0

                  The videos labeled dithering are probably a combination of dithering and inversion.

                  This may also be informative:
                  https://ledstrain.org/d/2669-pixel-inversion-and-temporal-dithering-might-be-using-the-same-mechanism/2

                  Update: now not so sure if you can tell the difference. Probably most you could tell at a glance is that temporal dithering combined with inversion causes the flickering to be more apparent.

                  aiaf There are still a ton of other options on the IOFramebuffer object, I will diff those soon.

                  Just in case you missed the tool, there is a GUI wrapper on IOReg. It is called IORegistryExplorer, and is included in Apple's Additional Tools For Xcode package on the More Downloads Page. When you run IORegistryExplorer, type IOMobileFramebufferAP into the search field, then View menu select Browser View.

                  Pretty great for this work, since it shows the properties update in near real time, so you can see the enableDither property toggle to false in real time when enabling Stillcolor. It also lists many other properties available on IOMobileFramebufferAP, and how they are changing over time and with different system settings.

                    dev