mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
renderer(metal): implement blinking (untested!)
See a9561a46 (this commit's OpenGL equivalent) for more information. Untested for now since I don't have a macOS setup.
This commit is contained in:
@ -97,6 +97,9 @@ cursor_color: ?terminal.color.RGB,
|
||||
/// foreground color as the cursor color.
|
||||
cursor_invert: bool,
|
||||
|
||||
/// Whether blinking cells are currently visible. Synchronized with cursor blinking.
|
||||
blink_visible: bool = true,
|
||||
|
||||
/// The current frame background color. This is only updated during
|
||||
/// the updateFrame method.
|
||||
current_background_color: terminal.color.RGB,
|
||||
@ -867,7 +870,7 @@ pub fn updateFrame(
|
||||
self: *Metal,
|
||||
surface: *apprt.Surface,
|
||||
state: *renderer.State,
|
||||
cursor_blink_visible: bool,
|
||||
blink_visible: bool,
|
||||
) !void {
|
||||
_ = surface;
|
||||
|
||||
@ -950,7 +953,7 @@ pub fn updateFrame(
|
||||
const cursor_style = renderer.cursorStyle(
|
||||
state,
|
||||
self.focused,
|
||||
cursor_blink_visible,
|
||||
blink_visible,
|
||||
);
|
||||
|
||||
// Get our preedit state
|
||||
@ -1027,6 +1030,9 @@ pub fn updateFrame(
|
||||
.full_rebuild = full_rebuild,
|
||||
};
|
||||
};
|
||||
|
||||
self.blink_visible = blink_visible;
|
||||
|
||||
defer {
|
||||
critical.screen.deinit();
|
||||
if (critical.preedit) |p| p.deinit(self.alloc);
|
||||
@ -1101,6 +1107,8 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
||||
errdefer self.gpu_state.releaseFrame();
|
||||
// log.debug("drawing frame index={}", .{self.gpu_state.frame_index});
|
||||
|
||||
self.uniforms.blink_visible = self.blink_visible;
|
||||
|
||||
// Setup our frame data
|
||||
try frame.uniforms.sync(self.gpu_state.device, &.{self.uniforms});
|
||||
try frame.cells_bg.sync(self.gpu_state.device, self.cells.bg_cells);
|
||||
@ -1603,6 +1611,11 @@ fn drawCellFgs(
|
||||
@as(c_ulong, 1),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setFragmentBuffer:offset:atIndex:"),
|
||||
.{ frame.uniforms.buffer.value, @as(c_ulong, 0), @as(c_ulong, 1) },
|
||||
);
|
||||
|
||||
encoder.msgSend(
|
||||
void,
|
||||
@ -2539,15 +2552,19 @@ fn updateCell(
|
||||
break :glyph;
|
||||
}
|
||||
|
||||
const mode: mtl_shaders.CellText.Mode = switch (try fgMode(
|
||||
var mode: mtl_shaders.CellText.Mode = .{ .fg = true };
|
||||
|
||||
switch (try fgMode(
|
||||
render.presentation,
|
||||
cell_pin,
|
||||
)) {
|
||||
.normal => .fg,
|
||||
.color => .fg_color,
|
||||
.constrained => .fg_constrained,
|
||||
.powerline => .fg_powerline,
|
||||
};
|
||||
.normal => {},
|
||||
.color => mode.fg_color = true,
|
||||
.constrained => mode.fg_constrained = true,
|
||||
.powerline => mode.fg_powerline = true,
|
||||
}
|
||||
|
||||
mode.fg_blink = style.flags.blink;
|
||||
|
||||
try self.cells.add(self.alloc, .text, .{
|
||||
.mode = mode,
|
||||
|
@ -137,6 +137,9 @@ pub const Uniforms = extern struct {
|
||||
cursor_pos: [2]u16 align(4),
|
||||
cursor_color: [4]u8 align(4),
|
||||
|
||||
/// Whether blinking cells and cursors are visible on this frame.
|
||||
blink_visible: bool align(1),
|
||||
|
||||
const PaddingExtend = packed struct(u8) {
|
||||
left: bool = false,
|
||||
right: bool = false,
|
||||
@ -324,12 +327,15 @@ pub const CellText = extern struct {
|
||||
mode: Mode align(1),
|
||||
constraint_width: u8 align(1) = 0,
|
||||
|
||||
pub const Mode = enum(u8) {
|
||||
fg = 1,
|
||||
fg_constrained = 2,
|
||||
fg_color = 3,
|
||||
cursor = 4,
|
||||
fg_powerline = 5,
|
||||
pub const Mode = packed struct(u8) {
|
||||
fg: bool,
|
||||
fg_constrained: bool,
|
||||
fg_color: bool,
|
||||
cursor: bool,
|
||||
fg_powerline: bool,
|
||||
fg_blink: bool,
|
||||
|
||||
_padding: u3 = 0,
|
||||
};
|
||||
|
||||
test {
|
||||
|
@ -18,6 +18,7 @@ struct Uniforms {
|
||||
float min_contrast;
|
||||
ushort2 cursor_pos;
|
||||
uchar4 cursor_color;
|
||||
bool blink_visible;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
@ -161,9 +162,9 @@ fragment float4 cell_bg_fragment(
|
||||
enum CellTextMode : uint8_t {
|
||||
MODE_TEXT = 1u,
|
||||
MODE_TEXT_CONSTRAINED = 2u,
|
||||
MODE_TEXT_COLOR = 3u,
|
||||
MODE_TEXT_CURSOR = 4u,
|
||||
MODE_TEXT_POWERLINE = 5u,
|
||||
MODE_TEXT_COLOR = 4u,
|
||||
MODE_TEXT_CURSOR = 8u,
|
||||
MODE_TEXT_POWERLINE = 16u,
|
||||
};
|
||||
|
||||
struct CellTextVertexIn {
|
||||
@ -257,7 +258,7 @@ vertex CellTextVertexOut cell_text_vertex(
|
||||
// If we're constrained then we need to scale the glyph.
|
||||
// We also always constrain colored glyphs since we should have
|
||||
// their scaled cell size exactly correct.
|
||||
if (in.mode == MODE_TEXT_CONSTRAINED || in.mode == MODE_TEXT_COLOR) {
|
||||
if (in.mode & (MODE_TEXT_CONSTRAINED | MODE_TEXT_COLOR)) {
|
||||
float max_width = uniforms.cell_size.x * in.constraint_width;
|
||||
if (size.x > max_width) {
|
||||
float new_y = size.y * (max_width / size.x);
|
||||
@ -285,14 +286,14 @@ vertex CellTextVertexOut cell_text_vertex(
|
||||
// since we want color glyphs to appear in their original color
|
||||
// and Powerline glyphs to be unaffected (else parts of the line would
|
||||
// have different colors as some parts are displayed via background colors).
|
||||
if (uniforms.min_contrast > 1.0f && in.mode == MODE_TEXT) {
|
||||
if (uniforms.min_contrast > 1.0f && !(mode & ~(MODE_TEXT | MODE_TEXT_BLINK))) {
|
||||
float4 bg_color = float4(bg_colors[in.grid_pos.y * uniforms.grid_size.x + in.grid_pos.x]) / 255.0f;
|
||||
out.color = contrasted_color(uniforms.min_contrast, out.color, bg_color);
|
||||
}
|
||||
|
||||
// If this cell is the cursor cell, then we need to change the color.
|
||||
if (
|
||||
in.mode != MODE_TEXT_CURSOR &&
|
||||
!(in.mode & MODE_TEXT_CURSOR) &&
|
||||
in.grid_pos.x == uniforms.cursor_pos.x &&
|
||||
in.grid_pos.y == uniforms.cursor_pos.y
|
||||
) {
|
||||
@ -305,7 +306,8 @@ vertex CellTextVertexOut cell_text_vertex(
|
||||
fragment float4 cell_text_fragment(
|
||||
CellTextVertexOut in [[stage_in]],
|
||||
texture2d<float> textureGrayscale [[texture(0)]],
|
||||
texture2d<float> textureColor [[texture(1)]]
|
||||
texture2d<float> textureColor [[texture(1)]],
|
||||
constant Uniforms& uniforms [[buffer(1)]]
|
||||
) {
|
||||
constexpr sampler textureSampler(
|
||||
coord::pixel,
|
||||
@ -313,28 +315,23 @@ fragment float4 cell_text_fragment(
|
||||
filter::nearest
|
||||
);
|
||||
|
||||
switch (in.mode) {
|
||||
default:
|
||||
case MODE_TEXT_CURSOR:
|
||||
case MODE_TEXT_CONSTRAINED:
|
||||
case MODE_TEXT_POWERLINE:
|
||||
case MODE_TEXT: {
|
||||
// We premult the alpha to our whole color since our blend function
|
||||
// uses One/OneMinusSourceAlpha to avoid blurry edges.
|
||||
// We first premult our given color.
|
||||
float4 premult = float4(in.color.rgb * in.color.a, in.color.a);
|
||||
|
||||
// Then premult the texture color
|
||||
float a = textureGrayscale.sample(textureSampler, in.tex_coord).r;
|
||||
premult = premult * a;
|
||||
|
||||
return premult;
|
||||
}
|
||||
|
||||
case MODE_TEXT_COLOR: {
|
||||
return textureColor.sample(textureSampler, in.tex_coord);
|
||||
}
|
||||
if (in.mode & MODE_TEXT_COLOR) {
|
||||
return textureColor.sample(textureSampler, in.tex_coord);
|
||||
}
|
||||
if (in.mode & MODE_TEXT_BLINK && !uniforms.blink_visible) {
|
||||
discard_fragment();
|
||||
}
|
||||
|
||||
// We premult the alpha to our whole color since our blend function
|
||||
// uses One/OneMinusSourceAlpha to avoid blurry edges.
|
||||
// We first premult our given color.
|
||||
float4 premult = float4(in.color.rgb * in.color.a, in.color.a);
|
||||
|
||||
// Then premult the texture color
|
||||
float a = textureGrayscale.sample(textureSampler, in.tex_coord).r;
|
||||
premult = premult * a;
|
||||
|
||||
return premult;
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Image Shader
|
||||
|
Reference in New Issue
Block a user