This commit is quite large because it's fairly interconnected and can't
be split up in a logical way. The main part of this commit is that alpha
blending is now always done in the Display P3 color space, and depending
on the configured `window-colorspace` colors will be converted from sRGB
or assumed to already be Display P3 colors. In addition, a config option
`text-blending` has been added which allows the user to configure linear
blending (AKA "gamma correction"). Linear alpha blending also applies to
images and makes custom shaders receive linear colors rather than sRGB.
In addition, an experimental option has been added which corrects linear
blending's tendency to make dark text look too thin and bright text look
too thick. Essentially it's a correction curve on the alpha channel that
depends on the luminance of the glyph being drawn.
This refactor enables two very significant improvements to our font
handling, which I will be implementing next:
1. Automatically adjust size of fallback faces to better align with the
primary face, a la CSS
[`font-size-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size-adjust).
[^1]
2. Move glyph resizing/positioning out of GPU-land and in to
`renderGlyph` and apply alignment/resizing rules from the nerd fonts
patcher[^2] to the glyphs at rasterization time, so that we can ensure
exact cell fits and swap out our embedded JB Mono with an unpatched
version with a separate dedicated symbols-only nerd font.
In addition to being necessary prep work for those two changes, this PR
is also a minor but real stand-alone improvement. By only computing the
cell metrics for our primary font, we avoid a *lot* of wasted work when
loading fallback fonts, and also avoid that being a source of load
errors, which we don't yet handle gracefully[^3].
To validate this PR I've run the full set of font backend tests locally
on my Mac with no failures, and did a sanity check of running Ghostty
with both renderers and with CoreText and FreeType font backends and
then `cat`ing a file that requires fallback fonts to render, and
everything looks correct.
[^1]: #3029
[^2]: The alignment and resizing rules for the nerd font symbols are
defined in the patcher
[here](6d0b8ba05a/font-patcher (L866-L1151))
[^3]: #2991
This is achieved by rendering to an alpha-only context rather than a
normal single-channel context, and adjusting the brightness at which
coretext thinks it's drawing the glyph, which affects how it applies
font smoothing (which is what `font-thicken` enables).
The renderer must track if the foreground, background, and cursor colors
are explicitly set by an OSC so that changes are not overridden when the
config file is reloaded.
Fixes: https://github.com/ghostty-org/ghostty/issues/2795
The renderer must track if the foreground, background, and cursor colors
are explicitly set by an OSC so that changes are not overridden when the
config file is reloaded.
Fixes#2332
Two bugs fixed to fix this behavior:
1. Our destination height didn't account for the top-left being
offscreen.
2. We were using the wrong height for the source rectangle. When a rows
param (r=) is specified, the image height and destination height are
at different scales. We were using the viewport scale for the offset
but it should be the image scale.
Fixes#2921
Our z-index handling was pretty much completely broken, hence I can't
think of a better initial commit message. We were splitting the
placements at the wrong points and just generally putting images in the
wrong z-index. I'm shocked this didn't come up earlier.
This is more correct: a pagelist is a linked list of nodes, not pages.
The nodes themselves contain pages but we were previously calling the
nodes "pages" which was confusing, especially as I plan some future
changes to the way pages are stored.
Some Intel MacBook Pro laptops have both an integrated and discrete
GPU and support automatically switching between them. The system
uses the integrated GPU by default, but the default Metal device on
those systems is the discrete GPU. This means that Metal‐using
applications activate it by default, presumably as the intended
audience is high‐performance graphics applications.
This is unfortunate for productivity applications like terminals,
however, as the discrete GPU decreases battery life and worsens the
thermal throttling problems these machines have always had. Prefer
to use an integrated GPU when present and not using an external GPU.
The behaviour should be unchanged on Apple Silicon, as the platform
only supports one GPU. I have confirmed that the resulting app runs,
works, and doesn’t activate the AMD GPU on my MacBook Pro, but have
not done any measurements of the resulting performance impact. If
it is considered sufficiently noticeable, a GPU preference setting
could be added.
See <https://github.com/zed-industries/zed/issues/5124>,
<https://github.com/zed-industries/zed/pull/13685>,
<https://github.com/zed-industries/zed/pull/14738>, and
<https://github.com/zed-industries/zed/pull/14744> for discussion,
measurements, and changes relating to this issue in the Zed
project. The logic implemented here reflects what Zed ended up
settling on.
The [Metal documentation] recommends using
`MTLCopyAllDevicesWithObserver` to receive notifications of when
the list of available GPUs changes, such as when [external GPUs
are connected or disconnected]. I didn’t bother implementing that
because it seemed like a lot of fussy work to deal with migrating
everything to a new GPU on the fly just for a niche use case on a
legacy platform. Zed doesn’t implement it and I haven’t heard
about anyone complaining that their computer caught fire when they
unplugged an external GPU, so hopefully it’s fine.
[Metal documentation]: https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/multi-gpu_systems/finding_multiple_gpus_on_an_intel-based_mac
[external GPUs are connected or disconnected]: https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/multi-gpu_systems/handling_external_gpu_additions_and_removalsCloses: #2572
Significant rework that also removes a lot of unnecessarily duplicated
work while rebuilding cells in both renderers. Fixes multiple issues
with decorations and bg colors on wide chars and ligatures, while
reducing the amount of special case handling required.
Metal needed to be changed to account for wide chars having decorations
on the right half and OpenGL needed to account for multiple glyphs being
under the cursor at once (decorations and combining marks) as well as
wide chars.
This makes sure that underline styles are consistent and not stretched,
and avoids rendering overlapping text decorations or extraneous
background cells for the right halves of wide chars.
This commit refactors RepeatablePath to contain a list of tagged unions
containing "optional" and "required" variants. Both variants have a null
terminated file path as their payload, but the tag dictates whether the
path must exist or not. This implemenation is used to force consumers to
handle the optional vs. required distinction.
This also moves the parsing of optional file paths into RepeatablePath's
parseCLI function. This allows the code to be better unit tested. Since
RepeatablePath no longer contains a simple list of RepeatableStrings,
many other of its methods needed to be reimplemented as well.
Because all of this functionality is built into the RepeatablePath type,
other config options which also use RepeatablePath gain the ability to
specify optional paths as well. Right now this is only the
"custom-shaders" option. The code paths in the renderer to load shader
files has been updated accordingly.
In the original optional config file parsing, the leading ? character
was removed when paths were expanded. Thus, when config files were
actually loaded recursively, they appeared to be regular (required)
config files and an error occurred if the file did not exist. **This
issue was not found during testing because the presence of the
"theme" option masks the error**. I am not sure why the presence of
"theme" does this, I did not dig into that.
Now because the "optional" or "required" state of each path is tracked
in the enum tag the "optional" status of the path is preserved after
being expanded to an absolute path.
Finally, this commit fixes a bug where missing "config-file" files were
not included in the +show-config command (i.e. if a user had
`config-file = foo.conf` and `foo.conf` did not exist, then `ghostty
+show-config` would only display `config-file =`). This bug applied to
`custom-shaders` too, where it has also been fixed.
Before, cells that were explicitly set to match the default bg color
were treated as if they did NOT have the default and extending would
occur. We now check the exact RGB of each cell.
Fixes#2099
This is another heuristic of sorts to make `window-padding-color=extend`
look better by default. If a fully covering glyph is used then we use
the fg color to extend rather than the background.
This doesn't account for fonts that may do this for whatever codepoints,
but I think that's a special scenario that we should just recommend
disabling this feature.
Before this fix, if vsync was on the GPU cells buffer could be cleared
for a frame while resizing the terminal down. This was due to the fact
that the surface sent messages for the resize to both the renderer and
the IO thread. If the renderer thread was processed first then the GPU
cells buffer(s) would be cleared and not rebuilt, because the terminal
state would be larger than the GPU cell buffers causing updateFrame to
bail out early, leaving empty cell buffers.
This fixes the problem by changing the origin of the renderer's resize
message to be the IO thread, only after properly updating the terminal
state, to avoid clearing the GPU cells buffers at a time they can't be
successfully rebuilt.
- Significant changes to optimize memory usage.
- Adjusted formatting of the metal shader code to improve readability.
- Normalized naming conventions in shader code.
- Abstracted repetitive code for attribute descriptors to a helper
function.
With a minimum contrast set, the colored glyphs that Powerline uses
would sometimes be set to white or black while the surrounding background
colors remain unchanged, breaking up contiguous colors on segments of
the Powerline.
This no longer happens with this patch as Powerline glyphs are now
special-cased and exempt from the minimum contrast adjustment.
There are scenarios where this configuration looks bad. This commit
introduces some heuristics to prevent it. Here are the heuristics:
* Extension is always enabled on alt screen.
* Extension is disabled if a row contains any default bg color. The
thinking is that in this scenario, using the default bg color looks
just fine.
* Extension is disabled if a row is marked as a prompt (using semantic
prompt sequences). The thinking here is that prompts often contain
perfect fit glyphs such as Powerline glyphs and those look bad when
extended.
This introduces some CPU cost to the extension feature but it should be
minimal and respects dirty tracking. This is unfortunate but the feature
makes many terminal scenarios look much better and the performance cost
is minimal so I believe it is worth it.
Further heuristics are likely warranted but this should be a good
starting set.