Most active commenters
  • okanat(5)

←back to thread

Ancient X11 scaling technology

(flak.tedunangst.com)
283 points todsacerdoti | 27 comments | | HN request time: 0.418s | source | bottom
1. wmf ◴[] No.44370040[source]
Drawing a circle is kind of cheating. The hard part of scaling is drawing UI elements like raster icons or 1px hairlines to look non-blurry.
replies(5): >>44370438 #>>44370470 #>>44370877 #>>44370924 #>>44372811 #
2. phkahler ◴[] No.44370438[source]
>> The hard part of scaling is drawing UI elements like raster icons or 1px hairlines to look non-blurry.

And doing so actually using X not OpenGL.

replies(2): >>44372644 #>>44373467 #
3. dark-star ◴[] No.44370470[source]
yeah, exactly. Nobody claimed that it is impossible to determin the physical geometry of your display (but that might be tricky for remote X sessions, I don't know if it would work there too?)
replies(1): >>44370515 #
4. kvemkon ◴[] No.44370515[source]
> tricky for remote X sessions, I don't know if it would work there too

The author did exactly this:

> Even better, I didn’t mention that I wasn’t actually running this program on my laptop. It was running on my router in another room, but everything worked as if

5. okanat ◴[] No.44370877[source]
And also doing it for multiple monitors with differing scales. Nobody claims X11 doesn't support different DPIs. The problems occur when you have monitors with differing pixel densities.

At the moment only Windows handles that use case perfectly, not even macOS. Wayland comes second if the optional fractional scaling is implemented by the toolkit and the compositor. I am skeptical of the Linux desktop ecosystem to do correct thing there though. Both server-side decorations and fractional scaling being optional (i.e. requires runtime opt-in from compositor and the toolkit) are missteps for a desktop protocol. Both missing features are directly attributable to GNOME and their chokehold of GTK and other core libraries.

replies(5): >>44371327 #>>44371399 #>>44372093 #>>44374657 #>>44374920 #
6. zozbot234 ◴[] No.44370924[source]
That depends on what kind of filtering is used when upscaling those icons. If you use modern resampling filters, you are more likely to get a subtle "oil painting" or "watercolor"-like effect with some very minor ringing effects next to sharp transitions (the effect of correctly-applied antialiasing, with a tight limit on spatial frequencies) as opposed to any visible blur. These filters may be somewhat compute-intensive when used for upscaling the entire screen - but if you only upscale small raster icons or other raster images, and use native-resolution rendering for everything else, that effect is negligible.
7. akdor1154 ◴[] No.44371327[source]
This is exactly right.

There is no mechanism for the user to specify a per-screen text DPI in X11.

(Or maybe there secretly is, and i should wait for the author to show us?)

replies(2): >>44371850 #>>44372697 #
8. axus ◴[] No.44371399[source]
Speaking of X11 and Windows, any recommended Windows Xservers to add to this StackOverflow post? https://stackoverflow.com/questions/61110603/how-to-set-up-w...

I hadn't heard of WSLg, vcxsrv was the best I could do for free.

replies(1): >>44371889 #
9. okanat ◴[] No.44371850{3}[source]
Natively in X11? No. Even with Xrandr. It is no. But you can obtain the display size and then draw things differently using OpenGL but now you're reinventing the display protocol in your drawing engine (which is what GLX is after all but I digress). You need to onboard every toolkit to your protocol.
replies(1): >>44373694 #
10. okanat ◴[] No.44371889{3}[source]
With WSLg, Windows runs a native Wayland server under Windows and it will use Xwayland to display X11 apps. You should be able to use any GUI app without any extra setup. You should double check the environment variables though. Sometimes .bashrc etc. or WSL's systemd support interferes with them.
11. Avamander ◴[] No.44372093[source]
Where does Windows handle it? It's a hodgepodge of different frameworks that often look absolutely abysmal at any scale besides 100%.
replies(1): >>44372349 #
12. okanat ◴[] No.44372349{3}[source]
Every UI framework that runs on Windows has to communicate using Win32 API at the lowest level. Here is the guide: https://learn.microsoft.com/en-us/windows/win32/hidpi/high-d...

Every GUI application on Windows runs an infinite event loop. In that loop you handle messages like [WM_INPUT](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-...). With Windows 8, Microsoft added a new message type: [WM_DPICHANGED](https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpi...). To not break the existing applications with an unknown message, Windows requires the applications to opt-in. The application needs to report its DPI awareness using the function [SetProcessDpiAwareness](https://learn.microsoft.com/en-us/windows/win32/api/shellsca...). The setting of the DPI awareness state can also be done by attaching an XML manifest file to the .exe file.

With the message Windows not only provides the exact DPI to render the Window contents for the display but also the size of the window rectangle for the perfect pixel alignment and to prevent weird behavior while switching displays. After receiving the DPI, it is up to application to draw things at that DPI however it desires. The OS has no direct access to dictate how it is drawn but it does provide lots of helper libraries and functions for font rendering and for classic Windows UI elements.

If the application is using a Microsoft-implemented .NET UX library (WinForms, WPF or UWP), Microsoft has already implemented the redrawing functions. You only need to include manifest file into the .exe resources.

After all of this implementation, why does one get blurry apps? Because those applications don't opt in to handle WM_DPICHANGED. So, the only option that's left for Windows is to let the application to draw itself at the default DPI and then stretch its image. Windows will map the input messages to the default DPI pixel positions.

Microsoft does provide a half way between a fully DPI aware app and an unaware app, if the app uses the old Windows resource files to store the UI in the .exe resources. Since those apps are guaranteed to use Windows standard UI elements, Windows can intercept the drawing functions and at least draw the standard controls with the correct DPI. That's called "system aware". Since it is intercepting the application's way of drawing, it may result in weird UI bugs though.

13. kllrnohj ◴[] No.44372644[source]
Yeah this is kinda the big elephant in the room here? They didn't prove what they set out to prove. Yes obviously OpenGL does scaling just fine, the entire point of Wayland is to get the compositor to just being a compositor. They didn't do any scaling with X. They didn't do anything at all with X other than ask it some basic display information.
replies(1): >>44372813 #
14. somat ◴[] No.44372697{3}[source]
X11 has had this since day one. However the trade offs to actually employing it are... unfortunate. It leans real hard on the application to actually cross screen boundaries and very few applications were willing to put the work in. so xrandr was invented. which does more of what people want with multiple screens by treating them as parts of one large virtual screen but you loose the per screen dpi.

http://wok.oblomov.eu/tecnologia/mixed-dpi-x11/

15. DonHopkins ◴[] No.44372811[source]
Ha ha, funny you should mention circles! It's so just much fun filling and stroking arcs and circles correctly with X11. From the horse's mouth:

https://archive.org/details/xlibprogrammingm01adri/page/144/...

Xlib Programming Manual and Xlib Reference Manual, Section 6.1.4, pp 144:

>To be more precise, the filling and drawing versions of the rectangle routines don't draw even the same outline if given the same arguments.

>The routine that fills a rectangle draws an outline one pixel shorter in width and height than the routine that just draws the outline, as shown in Figure 6-2. It is easy to adjust the arguments for the rectangle calls so that one draws the outline and another fills a completely different set of interior pixels. Simply add 1 to x and y and subtract 1 from width and height. In the case of arcs, however, this is a much more difficult proposition (probably impossible in a portable fashion).

https://news.ycombinator.com/item?id=11484148

DonHopkins on April 12, 2016 | parent | context | favorite | on: NeWS – Network Extensible Window System

>There's no way X can do anti-aliasing, without a ground-up redesign. The rendering rules are very strictly defined in terms of which pixels get touched and how.

>There is a deep-down irreconcilable philosophical and mathematical difference between X11's discrete half-open pixel-oriented rendering model, and PostScript's continuous stencil/paint Porter/Duff imaging model.

>X11 graphics round differently when filling and stroking, define strokes in terms of square pixels instead of fills with arbitrary coordinate transformations, and is all about "half open" pixels with gravity to the right and down, not the pixel coverage of geometric region, which is how anti-aliasing is defined.

>X11 is rasterops on wheels. It turned out that not many application developers enjoyed thinking about pixels and coordinates the X11 way, displays don't always have square pixels, the hardware (cough Microvax framebuffer) that supports rasterops efficiently is long obsolete, rendering was precisely defined in a way that didn't allow any wiggle room for hardware optimizations, and developers would rather use higher level stencil/paint and scalable graphics, now that computers are fast enough to support it.

>I tried describing the problem in the Unix-Haters X-Windows Disaster chapter [1]:

>A task as simple as filing and stroking shapes is quite complicated because of X's bizarre pixel-oriented imaging rules. When you fill a 10x10 square with XFillRectangle, it fills the 100 pixels you expect. But you get extra "bonus pixels" when you pass the same arguments to XDrawRectangle, because it actually draws an 11x11 square, hanging out one pixel below and to the right!!! If you find this hard to believe, look it up in the X manual yourself: Volume 1, Section 6.1.4. The manual patronizingly explains how easy it is to add 1 to the x and y position of the filled rectangle, while subtracting 1 from the width and height to compensate, so it fits neatly inside the outline. Then it points out that "in the case of arcs, however, this is a much more difficult proposition (probably impossible in a portable fashion)." This means that portably filling and stroking an arbitrarily scaled arc without overlapping or leaving gaps is an intractable problem when using the X Window System. Think about that. You can't even draw a proper rectangle with a thick outline, since the line width is specified in unscaled pixel units, so if your display has rectangular pixels, the vertical and horizontal lines will have different thicknesses even though you scaled the rectangle corner coordinates to compensate for the aspect ratio.

[1] The X-Windows Disaster: http://www.art.net/~hopkins/Don/unix-haters/x-windows/disast...

replies(1): >>44373491 #
16. slackfan ◴[] No.44372813{3}[source]
X shouldn't be displaying anything that isn't a right angle anyway.

All circular UI elements are haram.

17. kelnos ◴[] No.44373467[source]
Toolkits don't use X to do much (if any) drawing these days. They all use something like cairo or skia or -- yes -- OpenGL to render offscreen, and then upload to X for display (or in the case of OpenGL, they can also do direct rendering).
replies(2): >>44374386 #>>44381018 #
18. wmf ◴[] No.44373491[source]
I think that stuff was all fixed long ago by Cairo/Skia on XRender.
replies(1): >>44375165 #
19. uecker ◴[] No.44373694{4}[source]
Is this different to Wayland?
replies(1): >>44383526 #
20. sprash ◴[] No.44374386{3}[source]
If you use Cairo on X11 rendering automatically happens with the XRender extension. This is a rather efficient wire protocol that supports sub-pixel coordinates, transparency, gradients and more. No off-screen rendering required. (Some of the older gtk2 theme engines worked that way and allowed beautiful UIs with fast remote capabilities.)
21. ChocolateGod ◴[] No.44374657[source]
> you have monitors with differing pixel densities. At the moment only Windows handles that use case perfectly

I have a mixed DPI setup and Windows falls flat (on latest Win 11), the jank when you move a application from one monitor to another as it tells the application to redraw is horrible, and even then it sometimes fails and I end up with a cut oversized application or the app crashes.

Where as on GNOME Wayland I can resize an application to cover all my monitors and it 'just works' in making them it the same physical size on all even when one monitor is 4K and the others 1440p. There's no jank, no redraw. Yes, there's sometimes artifacting from it downscaling as the app targets the highest DPI and gets downsized by the compositor, but that's okay to me.

22. dontlaugh ◴[] No.44374920[source]
I've found the opposite, that only macOS handles that perfectly.

Windows still breaks in several situations like different size and density monitors, but it's generally good enough.

Recent Gnome on Wayland does about as well as Windows.

replies(1): >>44381032 #
23. DonHopkins ◴[] No.44375165{3}[source]
Yes, I agree: Cairo is "really good stuff" as Jim Gettys so modestly puts it! It's one of the best things to come out of X-Windows and the original Xr extension. ("The name Cairo derives from the original name Xr, interpreted as the Greek letters chi and rho.")

Finally (and for a long time now) it's an independent library, no longer tied into the X server and Xr extension, and there are a lot of wrappers for it, browser and GTK and many other frameworks use it, and it has lots of nice bindings to languages, like pycairo.

Jim Gettys, one of Cairo's authors and an original X-Windows architect, also worked on the OLPC project and its Sugar user interface framework (designed for making educational apps for kids), which used Cairo via GTK/PyGTK/PyCairo/Pango/Poppler.

Jim's big cause is that he champions eradicating "Bufferbloat":

https://en.wikipedia.org/wiki/Bufferbloat

https://gettys.wordpress.com/2010/12/03/introducing-the-crim...

I had a great time using it for the Micropolis (open source SimCity) tile rendering engine, which I wrote in C++, then wrapped with David Beazly's SWIG tool as a Python extension, so Python PyGTK apps could pass their existing Cairo rendering context into C++ and it could render at high speed without the Python interpreter in the way, on either windows or bitmaps.

https://en.wikipedia.org/wiki/SWIG

The TileEngine is a C++ python module wrapped with SWIG, that uses the Cairo library and knows how to accept a PyGTK Cairo context as a parameter to draw on directly via the api -- Python just passes pointers back and forth between PyGTK by wrangling and unwrangling wrappers around the Cairo context pointer:

TileEngine: https://github.com/SimHacker/micropolis/tree/master/Micropol...

tileengine.h: https://github.com/SimHacker/micropolis/blob/master/Micropol...

tileengine.cpp: https://github.com/SimHacker/micropolis/blob/master/Micropol...

pycairo.i: https://github.com/SimHacker/micropolis/blob/master/Micropol...

tileengine-swig-python.i: https://github.com/SimHacker/micropolis/blob/master/Micropol...

tileengine.i: https://github.com/SimHacker/micropolis/blob/master/Micropol...

Then you can call the tile engine from Python, and build GTK widgets and apps on top of it like so, and it all runs silky smooth, with pixel perfect tiling and scaling, so you can zoom into the SimCity map, and Python can efficiently draw sprites and overlays on it like Godzilla, tornados, trains, airplanes, helicopters, the cursor, etc:

tiledrawingarea.py: https://github.com/SimHacker/micropolis/blob/master/Micropol...

tilewindow.py: https://github.com/SimHacker/micropolis/blob/master/Micropol...

tiletool.py: https://github.com/SimHacker/micropolis/blob/master/Micropol...

I've written about Cairo on HN before, sharing some email with Jim about it:

https://news.ycombinator.com/item?id=20379336

DonHopkins on July 8, 2019 | parent | context | favorite | on: The death watch for the X Window System has probab...

Cairo wasn't the library behind the X11 drawing API, it was originally the Xr rendering extension, that was an alternative to the original X11 drawing API.

https://en.wikipedia.org/wiki/Cairo_(graphics)

>The name Cairo derives from the original name Xr, interpreted as the Greek letters chi and rho.

You're right, it doesn't actually make sense to put your drawing functions in the display server any more (at least in the case of X11, which doesn't have an extension language to drive the drawing functions -- but it did make sense for NeWS which also used PostScript as an extension language as well as a drawing API).

So Cairo rose above X11 and became its own independent library, so it could be useful to clients and toolkits on any window system or hardware.

https://www.osnews.com/story/3602/xr-x11-cross-device-render...

https://web.archive.org/web/20030805030147/http://xr.xwin.or...

https://keithp.com/~keithp/talks/xarch_ols2004/xarch-ols2004...

Here's some email discussion with Jim Gettys about where Cairo came from:

From: Jim Gettys <jg@laptop.org> Date: Jan 9, 2007, 11:04 PM

The day I thought X was dead was the day I installed CDE on my Alpha.

It was years later I realized the young turks were ignoring the disaster perpetrated by the UNIX vendors in the name of "standardization"; since then, Keith Packard and I have tried to pay for our design mistakes in X by things like the new font model, X Render extension, Composite, and Cairo, while putting stakes in the heart of disasters like XIE, LBX, PEX, the old X core font model, and similar design by committee mistakes (though the broken core 2D graphics and font stuff must be considered "original sin" committed by people who didn't know any better at the time).

So we've mostly succeeded at dragging the old whale off the beach and getting it to live again.

From: Don Hopkins <dhopkins@donhopkins.com> Date: Wed, Jan 17, 2007, 10:50 PM

Cairo looks wonderful! I'm looking forward to using it from Python, which should be lots of fun.

A lot of that old X11 stuff was thrown in by big companies to shill existing products (like using PEX to sell 3d graphics hardware, by drawing rotating 3-d cubes in an attempt to hypnotize people).

Remember UIL? I heard that was written by the VMS trolls at DEC, who naturally designed it with an 132 column line length limitation and no pre-processor of course. The word on the street was that DEC threw down the gauntlet and insisted on UIL being included in the standard, even though the rest of the committee hated it for sucking so bad. But DEC threatened to hold their breath until they got their way.

And there were a lot of weird dynamics around commercial extensions like Display PostScript, which (as I remember it) was used as an excuse for not fixing the font problems a lot earlier: "If you want to do readable text, then you should be using Display PostScript."

The problem was that Linux doesn't have a vendor to pay the Display PostScript licensing fee to Adobe, so Linux drove a lot of "urban renewal" of problems that had been sidelined by the big blundering companies originally involved with X.

>So we've mostly succeeded at dragging the old whale off the beach and getting it to live again.

Hey, that's a lot better than dynamiting the whale, which seemed like a such good idea at the time! (Oh the humanity!)

https://www.youtube.com/watch?v=AtVSzU20ZGk

From: Jim Gettys <jg@laptop.org> Date: Jan 17, 2007, 11:41 PM

> Cairo looks wonderful! I'm looking forward to using it from Python, which should be lots of fun.

Yup. Cairo is really good stuff. This time we had the benefit of Lyle Ramshaw to get us unstuck. Would that I'd known Lyle in 1986; but it was too late 3 years later when I got to know him.

https://cairographics.org/bibliography/

Here's some more of the discussion with Jim about Cairo and X-Windows:

https://news.ycombinator.com/item?id=7727953

>In 2007, I apologized to Jim Gettys for the tone of the X-Windows Disaster chapter I wrote for the book, to make sure he had no hard feelings and forgave me for my vitriolic rants and cheap shots of criticism:

http://www.donhopkins.com/home/catalog/unix-haters/x-windows...

DH>> I hope you founds it more entertaining than offensive!

JG> At the time, I remember it hurting; now I find it entertaining. Time cures such things. And Motif was definitely a vendor perpetrated unmitigated disaster: the worst of it was that it "succeeded" in unifying the UNIX gui, which means it succeeded at stopping all reasonable work on gui's on UNIX until the young Linux turks took over.

JG> And by '93 or so, the UNIX vendors actively wanted no change, as they had given up on the desktop and any innovation would cost them money.

DH>> The whole "Unix-Haters Handbook" thing was intended to shake up the status quo and inspire people to improve the situation instead of blindly accepting the received view. (And that's what's finally happened, although I can't take the credit, because it largely belongs to Linux -- and now that's the OLPC's mission!)

DH>> The unix-haters mailing list was a spin-off of its-lovers@mit-ai: in order to qualify for the mailing list you had to post a truly vitriolic no-holds-barred eyeball-popping flame.

DH>> I hope that helps to explain the tone of "The X-Windows Disaster", which I wrote to blow off steam while I was developing the X11 version of SimCity.

JG> Yup. I won't hold it against you ;-). Though any operating system with ddt as its shell is downright user hostile...

JG>>> The day I thought X was dead was the day I installed CDE on my Alpha. [...]

And more about Pango, the text rendering library on top of Cairo, the OLPC's Sugar user interface, which was built on PyGTK, and the OLPC Read book reader app that used the Cairo-based Poppler PDF rendering library:

https://en.wikipedia.org/wiki/Poppler_(software)

https://news.ycombinator.com/item?id=16852148

>I worked on making the Read activity usable in book mode (keyboard folded away, but gamepad buttons usable), and I vaguely recall putting in an ioctl to put the CPU to sleep after you turned a page, but I'm not sure if my changes made it in. [...]

>Sugar had a long way to go, and wasn't very well documented. They were trying to do too much from scratch, and choose a technically good but not winning platform. It was trying to be far too revolutionary, but at the same time building on top of layers and layers of legacy stack (X11, GTK, GTK Objects, PyGTK bindings, Python, etc).

>Sugar was written in Python and built on top of PyGTK, which necessitated buying into a lot of "stuff". On top of that, it used other Python modules and GTK bindings like Cairo for imaging, Pango for text, etc. All great industrial strength stuff. But then it had its own higher level Hippo canvas and user interface stuff on top of that, which never really went anywhere (for good reason: it was complex because it was written for PyGTK in a misshapen mish-mash of Python and C with the GTK object system, instead of pure simple Python code -- hardly what Alan Kay thinks of as "object oriented programming"). And for browser based stuff there were the Python bindings to xulrunner, which just made you yearn for pure JavaScript without all the layers of adaptive middle-ware between incompatible object systems.

>The problem is that Sugar missed the JavaScript/Web Browser boat (by arriving a bit too early, or actually just not having enough situational awareness). Sugar should have been written in JavaScript and run in any browser (or in an Electron-like shell such as xulrunner). Then it would be like a Chromebook, and it would benefit from the enormous amount of energy being put into the JavaScript/HTML platform. Python and GTK just hasn't had that much lovin'.

>When I ported the multi player TCL/Tk/X11 version of SimCity to the OLPC, I ripped out the multi player support because it was too low level and required granting full permission to your X server to other players. I intended to eventually reimplement it on top of the Sugar grid networking and multi user activity stuff, but that never materialized, and it would have been a completely different architecture than one X11 client connecting to multiple X11 servers.

>Then I made a simple shell script based wrapper around the TCL/Tk application, to start and stop it from the Sugar menus. It wasn't any more integrated with Sugar than that. Of course the long term plan was to rewrite it from the ground up so it was scriptable in Python, and took advantage of all the fancy Sugar stuff.

>But since the Sugar stuff wasn't ready yet, I spent my time ripping out TCL/Tk, translating the C code to C++, wrapping it with SWIG and plugging it into Python, then implementing a pure PyGTK/Cairo user interface, without any Sugar stuff, which would at least be a small step in the direction of supporting Sugar, and big step in the direction of supporting any other platform (like the web).

[...]

24. lotharcable ◴[] No.44381018{3}[source]
Yes toolkit authors have realized they have to avoid X11 as much as possible if they want to have good results.

This one of the major motivations as to why X11 guys decided Wayland was a good idea.

Because having your display server draw your application's output instead of your application drawing the output is a bad idea.

25. lotharcable ◴[] No.44381032{3}[source]
Windows is the only platform that tries to do it "correctly" as per the internet peanut gallery.

And, of course, doing it "wrongly" as per what OS X and Gnome does works a lot better in practice.

replies(1): >>44389117 #
26. okanat ◴[] No.44383526{5}[source]
Yes. Wayland is designed to be flexible of what does the drawing and where (currently only shared memory and EGL surfaces are implemented / supported). So it needs to define monitors as abstract concepts. They are called outputs and the client can query the size directly in Wayland protocol without needing display drivers or OpenGL.

However, there is no common way of handling different custom DPIs / scaling in the core Wayland protocol. Fractional scaling is implemented optionally by the client and the server and both need to opt-in.

27. dontlaugh ◴[] No.44389117{4}[source]
I don't know what Gnome does differently from macOS, but moving a window between screens of different density doesn't behave as expected. macOS gets this right, Windows doesn't either.