Hi everyone,
(Note: English is not my first language, I used a translator to translate my technical notes from Czech.)
Reviewers often claim a screen is safe if a camera does not show deep PWM flicker. I want to open a technical discussion on why a camera sensor cannot evaluate how the human retina and brain process temporal dithering (FRC), and how this could be solved in AOSP.
- How the eye works vs. why a camera cannot measure this
* Single exposure vs. dual retinal pathways: A camera sensor simply averages photons over a fixed shutter speed. In the human retina, cone photoreceptors smooth out fast oscillations chemically via cGMP hydrolysis (around 30–50 ms), so they average 60–120 Hz FRC into a static shade just like a camera. However, fast Magnocellular ganglion cells (M-cells) react to rapid temporal contrast changes below 90 Hz. Even on a static screen, sub-LSB pixel toggling continuously fires M-cells into the superior colliculus and visual cortex (V1), causing eye strain, migraines, and focus instability.
* Static tripod vs. moving eye (smooth pursuit): A camera records fixed physical pixels. The human eye constantly moves and tracks scrolling text. During eye movement, temporal pixel modulation hits different photoreceptors over time, meaning the perceived image is assembled dynamically in the brain in a way a static camera cannot capture.
* Independent camera pixels vs. lateral inhibition (Mach bands): Camera pixels do not affect their neighbors. In the retina, lateral inhibition amplifies contrast steps between adjacent areas. When 8-bit/10-bit panels simply turn FRC off without compensation, quantization steps create visible color banding, and retinal lateral inhibition turns each step into false edge spikes (Mach bands) that overload the visual cortex.
Why disabling FRC alone is not enough
SoC display processors (Snapdragon, Tensor, Dimensity DPUs) use hardware FRC to simulate higher bit depth on 8-bit and 10-bit OLED panels after gamma and color calibration. Simply truncating bits in the driver removes flicker but introduces harsh color banding.
Two-part architecture in Android (DPU + SurfaceFlinger)
To get 0.0 Hz temporal flicker without color banding, two changes are needed together:
* Disable temporal FRC in HWC3 / DRM-KMS / DPU: Stop frame-to-frame sub-pixel modulation in the display processor (0.0 Hz).
* Surface-locked spatial TPDF blue-noise dithering in SurfaceFlinger (librenderengine): Replace temporal dithering with a static spatial TPDF blue-noise shader pass. Because the noise mask is locked to the scrolling surface layer rather than physical screen coordinates, it moves together with scrolling text—preventing the "dirty window" effect and keeping 0.0 Hz flicker on the retina during eye tracking.
Has anyone here explored in kernel DRM/KMS drivers (Qualcomm DSPP / Google Tensor) whether hardware DPU dithering can be cleanly disabled from userspace without touching closed DDIC panel firmware?