People keep telling me that X11 doesn’t support DPI scaling, or fractional scaling, or multiple monitors, or something. There’s nothing you can do to make it work. I find this surprising. Why doesn’t it work? I figure the best way to find out is try the impossible and see how far we get.
I’m just going to draw a two inch circle on the screen. This screen, that screen, any screen, the circle should always be two inches. Perhaps not the most exciting task, but I figure it’s isomorphic to any other scaling challenge. Just imagine it’s the letter o or a button we wish to draw at a certain size.
I have gathered around me a few screens of different sizes and resolutions. My laptop screen, and then a bit to the right a desktop monitor, and then somewhere over that way a nice big TV. Specifically:
$ xrandr | grep \ connected eDP connected primary 2880x1800+0+0 (normal left inverted right x axis y axis) 302mm x 189mm DisplayPort-0 connected 2560x1440+2880+0 (normal left inverted right x axis y axis) 590mm x 334mm DisplayPort-1 connected 3840x2160+5440+0 (normal left inverted right x axis y axis) 1600mm x 900mm
I think I just spoiled the ending, but here we go anyway.
I’m going to draw the circle with OpenGL, using a simple shader and OBT. There’s a bunch of not very exciting code to create a window and a GLX context, but eventually we’re going to be looking at the shader. This may not be the best way to draw a circle, but it’s my way. For reference, the full code is in circle.c.
void main ( ) { float thick = radius / 10 ; if ( abs ( center . y - gl_FragCoord . y ) < thick / 2 ) thick = 2 ; float pi = 3 . 14159 ; float d = distance ( gl_FragCoord . xy , center ) ; float angle = atan ( gl_FragCoord . y - center . y , gl_FragCoord . x - center . x ) ; angle /= 2 * pi; angle += 0 . 5 ; angle += 0 . 25 ; if ( angle > 1 . 0 ) angle -= 1 . 0 ; float amt = ( thick - abs ( d - radius ) ) / thick; if ( d < radius + thick && d > radius - thick ) fragment = vec4 ( rgb ( angle ) * amt , 1 . 0 ) ; else discard; }
I got a little carried away and made a pretty color wheel instead of a flat circle.
The key variable is radius which tells us how many pixels from the center the circle should be. But where does the shader get this from?
glUniform1f(0, radius);
... continue reading