Settings for a binary black-white display

Setting a smartphone display to greyscale tends to make it less appealing tends to reduce addicted device use. Greyscale still offers a full continuous range of brightness between black and white. We can do better.

A strictly black-and-white quantised display uses 2 colours in place of greyscale's usual 256, but yields much more than 1/128 of the visible information.

Linux desktops are deeply configurable and so make for an easy testing ground. Most Linux desktops are based around either Xorg or Wayland. Most niche visual effects are based around fragment shaders. Under Xorg, you can add shaders with a compositor, such as picom. Under Wayland, your compositor must be one that supports shaders, of which the most popular is Hyprland.

picom

Under a working Xorg session, run

picom --backend glx --window-shader-fg bw.glsl &

where bw.glsl is (the path to) a text file of the following:

#version 330
in vec2 texcoord;
uniform sampler2D tex;
vec4 default_post_processing(vec4 c);

vec4 window_shader() {
    vec4 c = texelFetch(tex, ivec2(texcoord), 0);
    float l = dot(c.rgb, vec3(0.2126, 0.7152, 0.0722));
    return default_post_processing(vec4(vec3(step(0.5, l)), c.a));
}

If picom crashes with an error about GLX, perhaps your GPU or its drivers are too old. If so, add LIBGL_ALWAYS_SOFTWARE=1 to the start of the picom command.

If windows turn black and white, but don't respond to input, blindly type pkill picom (and press Enter) in your terminal. Then figure out the rest where I could not.

Hyprland

This also relies on a shader file, .config/hypr/bw.frag

#version 300 es
precision highp float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 fragColor;

void main() {
    vec3 c = texture(tex, v_texcoord).rgb;
    float l = dot(c, vec3(0.2126, 0.7152, 0.0722));
    fragColor = vec4(vec3(step(0.5, l)), 1.0);
}

To turn on the feature temporarily, run hyprctl eval "hl.config({ decoration = { screen_shader = '$HOME/.config/hypr/bw.frag' } })" and replace the path with '' to turn it off.

Android

To configure Android deeply, you need to root it. I haven't been able to root my phone, so I could only test the method below in a LineageOS virtual machine.

Run the following in an ADB shell:

su -c "service call SurfaceFlinger 1015 i32 1 \
    f 212.6 f 212.6 f 212.6 f 0 \
    f 715.2 f 715.2 f 715.2 f 0 \
    f 72.2 f 72.2 f 72.2 f 0 \
    f -500 f -500 f -500 f 1"

The command relies on the obscure fact that invoking SurfaceFlinger's code 1015 loads a custom colour-mapping matrix.