Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metal alpha blending fixes + color handling improvements #4913

Merged

Conversation

qwerasd205
Copy link
Collaborator

This PR addresses #2125 for the Metal renderer. Both options are available: "Apple-style" blending where colors are blended in a wide gamut color space, which reduces but does not eliminate artifacts; and linear blending where colors are blended in linear RGB.

Because this doesn't add support for linear blending on Linux, I don't know whether the issue should be closed or not.

List of changes in no particular order

  • We now set the layer's color space in the renderer not in the apprt
  • We always set the layer to Display P3 color spaces
  • If the user hasn't configured their window-colorspace to display-p3 then terminal colors are automatically converted from sRGB to the corresponding Display P3 color in the shader
  • Background color is not set with the clear color anymore, instead we explicitly set all bg cell colors since this is needed for minimum contrast to not break with dark text on the default bg color (try it out, it forces it fully white right now), and we just draw the background as a part of the bg cells shader. Note: We may want to move the main background color to be the backgroundColor property on the CAMetalLayer, because this should fix the flash of transparency during startup (macOS: background bleeds/flicker when resizing splits, creating tabs #4516) and the weirdness at the edge of the window when resizing. I didn't make that a part of this PR because it requires further changes and my changes are already pretty significant, but I can make it a follow-up.
  • Added a config option for changing alpha blending between "native" blending, where colors are just blended directly in sRGB (or Display P3) and linear blending, where colors are blended in linear space.
  • Added a config option for an experimental technique that I think works pretty well which compensates for the perceptual thinning and thickening of dark and light text respectively when using linear blending.
  • Custom shaders can now be hot reloaded with config reloads.
  • Fixed a bug that was revealed when I changed how we handle backgrounds, page widths weren't being set while cloning the screen.

Main takeaways

Color blending now matches nearly identically to Apple apps like Terminal.app and TextEdit, not quite identical in worst case scenarios, off by the tiniest bit, because the default color space is slightly different than Display P3.

Linear alpha blending is now available for mac users who prefer more accurate color reproduction, and personally I think it looks very nice with the alpha correction turned on, I will be daily driving that configuration.

Future work

  • Handle primary background color with CALayer.backgroundColor instead of in shader, to avoid issues around edges when resizing.
  • Parse color space info directly from ICC profiles and compute the color conversion matrix dynamically, and pass it as a uniform to the shaders.
  • Port linear blending option to OpenGL.
  • Maybe support wide gamut images (right now all images are assumed to be sRGB).

src/config/Config.zig Outdated Show resolved Hide resolved
} else .{
.color = true,
.depth = 4,
.space = try macos.graphics.ColorSpace.createDeviceRGB(),
.space = try macos.graphics.ColorSpace.createNamed(.displayP3),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qwerasd205 suggestion: Should we make this ...ColorSpace.createFromName(.displayP3)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I could understand changing it to createWithName if we wanted to match the name of the CoreGraphics function, but this really feels like splitting hairs either way. I'm not devoted to the name, but if I changed it I'd be more likely to change it to createWithName than createFromName unless there's particularly good reasoning...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qwerasd205 The way I see it, we are creating a ColorSpace from a ColorSpace.Name called .displayP3.

From that perspective, it would logically flow into ColorSpace.createFromName(.displayP3).

I do think createWithName is also a great option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically our macos pkg is a thin layer over Carbon/AppKit APIs and we just mirror their names, so technically the correct name here is createWithName but I'm not going to lose sleep over it and don't really care.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mitchellh @qwerasd205 Im also happy if we leave it the way it is.

Resolving comment.

@@ -520,6 +520,7 @@ pub fn clone(
assert(node.data.capacity.rows >= chunk.end - chunk.start);
defer node.data.assertIntegrity();
node.data.size.rows = chunk.end - chunk.start;
node.data.size.cols = chunk.node.data.size.cols;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This took me over an hour to find 😭

qwerasd205 and others added 3 commits January 13, 2025 13:50
Otherwise pages may have the wrong width if they were resized down with
a fast path that just chanes the size without adjusting capacity at all.
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.
@mitchellh mitchellh force-pushed the alpha-compositing-and-color-spaces branch from 6c5b251 to a8b9c5b Compare January 13, 2025 21:59
@mitchellh mitchellh enabled auto-merge January 13, 2025 22:00
@mitchellh mitchellh mentioned this pull request Jan 13, 2025
@mitchellh mitchellh merged commit 5081e65 into ghostty-org:main Jan 13, 2025
30 checks passed
@github-actions github-actions bot added this to the 1.1.0 milestone Jan 13, 2025
@qwerasd205 qwerasd205 deleted the alpha-compositing-and-color-spaces branch January 13, 2025 23:08
mitchellh added a commit that referenced this pull request Jan 24, 2025
)

This fixes a regression introduced by the rework of this area before
during the color space changes (#4913). It seems like the original
intent of this code was the behavior it regressed to, but it turns out
to be better like this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants