4 ms·
> The first trick is "overwrite, don't clear". If you clear the "screen" and then add new content, you risk seeing a blank or partially blank frame for a brief
by dragontamer 4y ago
> The first trick is "overwrite, don't clear". If you clear the "screen" and then add new content, you risk seeing a blank or partially blank frame for a brief moment. It's far better to overwrite the content in the terminal entirely so that there is no intermediate blank frame.
> The second trick [...]
> The third trick [...]
This is pretty hilarious to consider when coming from Win32API.
Its traditional to clears the window before showing anything on Win32. Clearing the window happens so fast that you shouldn't see a flicker, even as the mouse moves over your window (each pixel your mouse cursor moves, Win32API will clear the window to its background, redraw the window (erasing the old mouse pointer), and draw the mouse pointer in the new location.
This "TUI needs to be overwritten, not cleared" idea seems quaint and slow. Win32API was drawRect(background color) for decades on ancient 386 machines and fast enough to deliver a good experience. Why is a 80 x 24 terminal window so much slower?
> In Textual the layout process creates a "render map". Basically a mapping of the Widget on to it's location on the screen. In an earlier version, Textual would do a wasteful refresh of the entire screen if even a single widget changed position. I wanted to avoid that by comparing the before and after render map.
Win32API creates and maintains the "invalidRect", the rectangle that needs to be re-rendered from scratch (ie: draw-calls called upon the hierarchy of "windows" from the background to foreground, in order , to make the overall window look unchanged).
Not only from mouse-cursor movements, but also as other windows "move" ontop of your window, or Clippy's speech bubble disappears (if you remember that little UI from the 90s version of Microsoft Word).
And again, this needed to be done every time the mouse moved one pixel, to erase the old mouse cursor (aka: redraw the entire window from scratch "over" the old mouse cursor, making it look like you've erased it) and redraw the mouse cursor on top of the fresh coat of paint. It was an incredibly common operation even in 20MHz 80386 land from the early `90s.
There's just no way a modern terminal is that slow, unless there's a billion layers of vsync / refreshes going on. There's definitely something wrong going on IMO here.
> Unicode art is good
This is true. Heck, ASCII art / symbols are often good enough to do many, many things.
There's something wrong with the terminal model at the fundamental level if you're a couple of magnitudes slower than the 1980s. I can't say I'm an expert on TUI (or guis for that matter), but... this whole blog post is kind of a horror story IMO.
- willm 4y agoWin32API was designed to render a GUI from day 1. The terminal protocol pre-dates Windows and wasn't designed with modern hardware in mind. It's not that it is slow per se.
- dragontamer 4y agoA 1920 byte (80x24x1-byte each) character window shouldn't be having performance problems on modern systems (ie: seeing blank-characters or whatever) when a 1080 x 1920 x 4-byte == 8MB desktop completes any execution faster than the eye can see on 30 year old hardware (blank, redraw, scale, etc. etc.) Something, somewhere, is flushing the screen and waiting for V-Sync, or something like that. You can write a 2D Canvas or even 3D world (involving the reupload of entire geometries each frame) that executes faster in Javascript compared to this 80x24x1 byte TUI window.
- willm 4y agoIt’s not a “performance” issue, it’s a protocol issue. One which is largely solved with the synchronisation protocol. Workarounds are needed for older emulators.
- badsectoracula 4y ago> Its traditional to clears the window before showing anything on Win32. Clearing the window happens so fast that you shouldn't see a flicker That is not due to speed but due to Windows API being smart with clipping regions/rectangles to only allow pixel updates in damaged regions (e.g. uncovered parts of a window as you move it). Note that nowadays this only happens inside windows as toplevel windows are composed via DWM in an offscreen buffer. Windows also tries to doublebuffer window drawing updates to avoid flickering. However in Win7 (with DWM -aka Aero mode- disabled) and earlier you'd be able to see flickering by, e.g. resizing windows with complex UIs. Also the "tradition" here isn't to clear the window but to invalidate the regions that were damaged so that the next update (which does clear the window) only affects the damaged regions instead of the entire window. This was most common during the 90s and early 2000s though, at some point computers and memory were fast and big enough to do double buffering during paint events (which in some cases you still need to do when working with GDI) to avoid visible flickering - and nowadays most common flickering issues are solved by Windows themselves doing it via composition. > even as the mouse moves over your window (each pixel your mouse cursor moves, Win32API will clear the window to its background, redraw the window (erasing the old mouse pointer), and draw the mouse pointer in the new location. This is what Windows did until Windows 3.1 (and you could see the cursor flickering when, e.g. a control drew itself while the cursor was over it) but with Windows 95 the system composed the mouse cursor to avoid that flickering. However nowadays (and for a long time now actually) the mouse cursor is drawn by the GPU as a separate hardware plane on top of the screen contents. All Windows do in that case is to send the cursor image to the GPU and set the registers that specify the plane (cursor) position whenever the mouse moves - no drawing takes place.