
This moves the OpenGL renderer out to a dedicated thread. The immediate effect is noticeably improved FPS under high load scenarios. But the future impact is also important: (1) required for multiple windows, tabs, etc. one day (2) forced a refactor to support pluggable renderers. == Architectural Notes Windowing events and IO remain on the main thread for now, but I plan to move IO to a dedicated thread in a future PR. Windowing events have to remain on the main thread for eternity since some platforms force all Window events onto one thread. This is one of the reasons that this will be required for multi-window. As more windows are opened, the windowing system will send more and more window events to our main thread, taking more and more time away from other tasks on the main thread. Windowing events are effectively free, so if the thread is ONLY handling windowing events, this can scale basically forever. Further, with OpenGL, each window must have its own "context." A context is the state used to draw. OpenGL mandates at most one context is active at any given time _per OS thread_. For multiple windows, this means that a single thread would have to draw one window at a time in serial. With multiple rendering threads, each thread can have its own context activated and draw in parallel. The renderer thread and main thread **do have shared state** and will have some shared state forever. The terminal screen state for example is shared memory. An immutable data structure or double buffering would be too expensive (I think, I'll check one day) so we use a mutex to protect access to the terminal state. The primary instigator of terminal state change is PTY read. This is the primary motivator to eventually move IO to its own dedicated thread as well. As multiple windows come up, each PTY under heavy load conditions will block only its own thread and hold the lock only for its own terminal state (and therefore its own renderer thread). We can continue to optimize critical areas from this point forward though and lower any contention. == Performance Notes I haven't done any hard benchmarking on this, only did some cursory memory measurements, CPU measurements, etc. I also ran superficial test programs such as `cat`-ing large files, scrolling through large buffers in vim, etc. In any case, it seems that responsivity is generally higher, although it appears that `cat`-ing large files slowed down by roughly 10%. This is probably due to the lock overhead with the renderer and optimizing for higher framerates with this setup.
ghostty
GPU-accelerated terminal emulator pushing modern features.
About
ghostty is a cross-platform, GPU-accelerated terminal emulator that aims to push the boundaries of what is possible with a terminal emulator by exposing modern, opt-in features that enable CLI tool developers to build more feature rich, interactive applications.
There are a number of excellent terminal emulator options that exist today. The unique goal of ghostty is to have a platform for experimenting with modern, optional, non-standards-compliant features to enhance the capabilities of CLI applications. We aim to be the best in this category, and competitive in the rest.
While aiming for this ambitious goal, ghostty is a fully standards compliant terminal emulator that aims to remain compatible with all existing shells and software. You can use this as a drop-in replacement for your existing terminal emulator.
Project Status: Pre-Alpha. It now supports enough to be used day to day for my use case, but is still missing a lot of functionality.
Roadmap and Status
The high-level ambitious plan for the project, in order:
# | Step | Status |
---|---|---|
1 | Standards-compliant terminal emulation | ⚠️ |
2 | Competitive rendering performance (not the fastest, but fast enough) | ✅ |
3 | Basic customizability -- fonts, bg colors, etc. | ❌ |
4 | Richer windowing features -- multi-window, tabbing, panes | ❌ |
5 | Optimal rendering performance | ❌ |
N | Fancy features (to be expanded upon later) | ❌ |
Standards-Compliant Terminal Emulation
I am able to use this terminal as a daily driver. I think that's good enough for a yellow status. There are a LOT of missing features for full standards compliance but the set that are regularly in use are working pretty well.
Competitive Rendering Performance
I want to automate the testing of this, but for now I've manually verified
we can maintain 120fps cat
-ing a 6MB file. In terms of raw draw speed,
cat
-ing a 6MB file is consistently faster on Linux using ghostty than
any other terminal emulator currently.
On macOS, cat
-ing the large file is acceptable performance but not optimal.
I don't know why and need to look into it.
Developing Ghostty
Ghostty is built using both the Zig programming
language as well as the Zig build system. At a minimum, Zig must be installed.
For Nix users, a shell.nix
is available which includes
all the necessary dependencies pinned to exact versions.
Note: Zig nightly is required. Ghostty is built against the nightly releases of Zig. The latest released version (0.9.1 at the time of this edit) will NOT work. You can find binary releases of nightly builds on the Zig downloads page.
With Zig installed, a binary can be built using zig build
:
$ zig build -fstage1
...
$ zig-out/bin/ghostty
Important: you must specify the -fstage1
flag. Ghostty can't yet be
built with the self-hosted Zig backend, so we have to use "stage1" (the
C++ LLVM backend).
This will build a binary for the currently running system (if supported).
You can cross compile by setting -Dtarget=<target-triple>
. For example,
zig build -Dtarget=aarch64-macos
will build for Apple Silicon macOS. Note
that not all targets supported by Zig are supported.
Other useful commands:
zig build test
for running unit tests.zig build run -Dconformance=<name>
run a conformance test case from theconformance
directory. Thename
is the name of the file. This runs in the current running terminal emulator so if you want to check the behavior of this project, you must run this command in ghostty.