I want to understand how dithering actually works at a lower level. While the original Stillcolor method successfully toggles dithering by setting enableDither in the IORegistry, I was curious whether there was a more direct way to communicate with the DCP.
Under the spoiler: The Touch Bar is considered an internal display, and you can disable dithering on it.
In the original Stillcolor author's post, they referenced a function _kern_EnableDisableDitheringin IOMobileFramebuffer that makes a direct call:
IOConnectCallScalarMethod(connection, 0x1E, &value, 1, NULL, NULL)
Selector 0x1E allows us to control dithering; the value 'value' specifies enabling (1) or disabling (0) dithering.
Selector 0x1E affects the Touch Bar driver, not the display driver. As mentioned earlier, the display driver responds to selector 0x1E with an error.
Breakpoints on these methods (IOMobileFramebufferEnableDisableDithering, _kern_EnableDisableDithering, and IOConnectCallScalarMethod — all of which use selector 0x1E) don't trigger when running Stillcolor code, meaning they are not involved in disabling dithering by setting enableDither in the IORegistry.
It appears selector 0x1E is not implemented in AppleMobileDispH13G-DCP.kext (the display driver), only in AppleMobileDispH13G-DFR.kext (the Touch Bar driver).
It feels like AppleMobileDispH13G-DCP.kext is part of the DCP firmware rather than a separate driver in macOS, since there's only a stub in the system folder.
Under the spoiler: Brief DCP firmware analysis
The ipsw utility can be used to extract DCP firmware files from the macOS IPSW image. I downloaded Sonoma 14.6.1 IPSW from ipsw.me.
brew install ipsw
ipsw extract ./UniversalMac_14.6.1_23G93_Restore.ipsw --files --pattern '.*dcp.*' -o ./dcp_firmware_extracted
This will extract many firmware files. We're only interested in these. For analysis, any of them can be used.
| Codename | Chip | Devices |
| t600x | M1 | MacBook Air, MacBook Pro 13", Mac mini, iMac |
| t602x | M2 | MacBook Air M2, MacBook Pro 13" M2 |
| t6030 | M3 | MacBook Pro 14" M3 |
| t603x | M3 Pro / Max | MacBook Pro 14"/16" M3 Pro/Max |
The firmware must first be unpacked using the img4tool utility:
img4tool -e -o t600xdcp.bin t600xdcp.im4p
Then, load the t600xdcp.bin file into the disassembler. I’m using Hopper.
Inside the DCP firmware, I found many strings (I suspect this is an array of strings) that represent properties. Among them is enableDither. Some of these properties can be set from userland, as Stillcolor does, while others cannot. For example, there is a property called gAFKConfigLogMask. The Asahi Linux kernel sets it to a specific value. However, this property does not appear to be accessible from userland in macOS (at least I couldn't access it).
The DCP firmware does not run on the CPU, but on a dedicated controller that has its own minimal operating system — RTKit. Therefore, communicating directly with the DCP firmware is not straightforward. Communication primarily happens via shared memory. We write the property value there and send a small message to the DCP through the mailbox mechanism, so that the DCP reads the property from the shared memory.
Inside the DCP firmware, there are methods. However, the problem is that directly calling an internal DCP method from the driver (e.g., by function address) is technically impossible because these are two isolated execution units (CPU vs. DCP). The DCP operates with its own physical and virtual memory. A function pointer in the context of ARM64 (the CPU) means nothing to the DCP.
In a regular dylib, you can call any function if you know its address — even a private, non-exported one, via symbol or offset. In DCP, even knowing the function's address is useless.
This means that we need not just the address of a method, but we need to reverse-engineer the RTKit messaging mechanism. In practice, you can only call methods that have a registered selector in the RTKit dispatcher and a defined protocol (selector + data format). I cannot call a method that lacks a selector and was never intended to be called from outside the DCP. This severely limits our ability to control the firmware.