mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-16 06:46:09 +00:00
renderer: fix color glyph rendering under OpenGL
Also changes color atlas to always use an sRGB internal format so that the texture reads automatically linearize the colors. Renames the misleading `rgba` atlas format to `bgra`, since both FreeType and CoreText are set up to draw color glyphs in bgra.
This commit is contained in:
@@ -50,15 +50,18 @@ modified: std.atomic.Value(usize) = .{ .raw = 0 },
|
|||||||
resized: std.atomic.Value(usize) = .{ .raw = 0 },
|
resized: std.atomic.Value(usize) = .{ .raw = 0 },
|
||||||
|
|
||||||
pub const Format = enum(u8) {
|
pub const Format = enum(u8) {
|
||||||
|
/// 1 byte per pixel grayscale.
|
||||||
grayscale = 0,
|
grayscale = 0,
|
||||||
rgb = 1,
|
/// 3 bytes per pixel BGR.
|
||||||
rgba = 2,
|
bgr = 1,
|
||||||
|
/// 4 bytes per pixel BGRA.
|
||||||
|
bgra = 2,
|
||||||
|
|
||||||
pub fn depth(self: Format) u8 {
|
pub fn depth(self: Format) u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.grayscale => 1,
|
.grayscale => 1,
|
||||||
.rgb => 3,
|
.bgr => 3,
|
||||||
.rgba => 4,
|
.bgra => 4,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -79,7 +79,7 @@ pub fn init(
|
|||||||
|
|
||||||
var atlas_grayscale = try Atlas.init(alloc, 512, .grayscale);
|
var atlas_grayscale = try Atlas.init(alloc, 512, .grayscale);
|
||||||
errdefer atlas_grayscale.deinit(alloc);
|
errdefer atlas_grayscale.deinit(alloc);
|
||||||
var atlas_color = try Atlas.init(alloc, 512, .rgba);
|
var atlas_color = try Atlas.init(alloc, 512, .bgra);
|
||||||
errdefer atlas_color.deinit(alloc);
|
errdefer atlas_color.deinit(alloc);
|
||||||
|
|
||||||
var result: SharedGrid = .{
|
var result: SharedGrid = .{
|
||||||
|
@@ -391,7 +391,7 @@ pub const Face = struct {
|
|||||||
const format: ?font.Atlas.Format = switch (bitmap_ft.pixel_mode) {
|
const format: ?font.Atlas.Format = switch (bitmap_ft.pixel_mode) {
|
||||||
freetype.c.FT_PIXEL_MODE_MONO => null,
|
freetype.c.FT_PIXEL_MODE_MONO => null,
|
||||||
freetype.c.FT_PIXEL_MODE_GRAY => .grayscale,
|
freetype.c.FT_PIXEL_MODE_GRAY => .grayscale,
|
||||||
freetype.c.FT_PIXEL_MODE_BGRA => .rgba,
|
freetype.c.FT_PIXEL_MODE_BGRA => .bgra,
|
||||||
else => {
|
else => {
|
||||||
log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode });
|
log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode });
|
||||||
@panic("unsupported pixel mode");
|
@panic("unsupported pixel mode");
|
||||||
|
@@ -347,7 +347,7 @@ pub fn initAtlasTexture(
|
|||||||
) Texture.Error!Texture {
|
) Texture.Error!Texture {
|
||||||
const pixel_format: mtl.MTLPixelFormat = switch (atlas.format) {
|
const pixel_format: mtl.MTLPixelFormat = switch (atlas.format) {
|
||||||
.grayscale => .r8unorm,
|
.grayscale => .r8unorm,
|
||||||
.rgba => .bgra8unorm,
|
.bgra => .bgra8unorm_srgb,
|
||||||
else => @panic("unsupported atlas format for Metal texture"),
|
else => @panic("unsupported atlas format for Metal texture"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -440,7 +440,7 @@ pub fn initAtlasTexture(
|
|||||||
const format: gl.Texture.Format, const internal_format: gl.Texture.InternalFormat =
|
const format: gl.Texture.Format, const internal_format: gl.Texture.InternalFormat =
|
||||||
switch (atlas.format) {
|
switch (atlas.format) {
|
||||||
.grayscale => .{ .red, .red },
|
.grayscale => .{ .red, .red },
|
||||||
.rgba => .{ .rgba, .srgba },
|
.bgra => .{ .bgra, .srgba },
|
||||||
else => @panic("unsupported atlas format for OpenGL texture"),
|
else => @panic("unsupported atlas format for OpenGL texture"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -336,7 +336,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
const color = try api.initAtlasTexture(&.{
|
const color = try api.initAtlasTexture(&.{
|
||||||
.data = undefined,
|
.data = undefined,
|
||||||
.size = 1,
|
.size = 1,
|
||||||
.format = .rgba,
|
.format = .bgra,
|
||||||
});
|
});
|
||||||
errdefer color.deinit();
|
errdefer color.deinit();
|
||||||
|
|
||||||
|
@@ -87,19 +87,19 @@ void main() {
|
|||||||
case MODE_TEXT_COLOR:
|
case MODE_TEXT_COLOR:
|
||||||
{
|
{
|
||||||
// For now, we assume that color glyphs
|
// For now, we assume that color glyphs
|
||||||
// are already premultiplied sRGB colors.
|
// are already premultiplied linear colors.
|
||||||
vec4 color = texture(atlas_color, in_data.tex_coord);
|
vec4 color = texture(atlas_color, in_data.tex_coord);
|
||||||
|
|
||||||
// If we aren't doing linear blending, we can return this right away.
|
// If we are doing linear blending, we can return this right away.
|
||||||
if (!use_linear_blending) {
|
if (use_linear_blending) {
|
||||||
out_FragColor = color;
|
out_FragColor = color;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we need to linearize the color. Since the alpha is
|
// Otherwise we need to unlinearize the color. Since the alpha is
|
||||||
// premultiplied, we need to divide it out before linearizing.
|
// premultiplied, we need to divide it out before unlinearizing.
|
||||||
color.rgb /= vec3(color.a);
|
color.rgb /= vec3(color.a);
|
||||||
color = linearize(color);
|
color = unlinearize(color);
|
||||||
color.rgb *= vec3(color.a);
|
color.rgb *= vec3(color.a);
|
||||||
|
|
||||||
out_FragColor = color;
|
out_FragColor = color;
|
||||||
|
@@ -553,19 +553,19 @@ fragment float4 cell_text_fragment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MODE_TEXT_COLOR: {
|
case MODE_TEXT_COLOR: {
|
||||||
// For now, we assume that color glyphs are
|
// For now, we assume that color glyphs
|
||||||
// already premultiplied Display P3 colors.
|
// are already premultiplied linear colors.
|
||||||
float4 color = textureColor.sample(textureSampler, in.tex_coord);
|
float4 color = textureColor.sample(textureSampler, in.tex_coord);
|
||||||
|
|
||||||
// If we aren't doing linear blending, we can return this right away.
|
// If we're doing linear blending, we can return this right away.
|
||||||
if (!uniforms.use_linear_blending) {
|
if (uniforms.use_linear_blending) {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we need to linearize the color. Since the alpha is
|
// Otherwise we need to unlinearize the color. Since the alpha is
|
||||||
// premultiplied, we need to divide it out before linearizing.
|
// premultiplied, we need to divide it out before unlinearizing.
|
||||||
color.rgb /= color.a;
|
color.rgb /= color.a;
|
||||||
color = linearize(color);
|
color = unlinearize(color);
|
||||||
color.rgb *= color.a;
|
color.rgb *= color.a;
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
|
Reference in New Issue
Block a user