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.
|
/// foreground color as the cursor color.
|
||||||
cursor_invert: bool,
|
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 current frame background color. This is only updated during
|
||||||
/// the updateFrame method.
|
/// the updateFrame method.
|
||||||
current_background_color: terminal.color.RGB,
|
current_background_color: terminal.color.RGB,
|
||||||
@ -867,7 +870,7 @@ pub fn updateFrame(
|
|||||||
self: *Metal,
|
self: *Metal,
|
||||||
surface: *apprt.Surface,
|
surface: *apprt.Surface,
|
||||||
state: *renderer.State,
|
state: *renderer.State,
|
||||||
cursor_blink_visible: bool,
|
blink_visible: bool,
|
||||||
) !void {
|
) !void {
|
||||||
_ = surface;
|
_ = surface;
|
||||||
|
|
||||||
@ -950,7 +953,7 @@ pub fn updateFrame(
|
|||||||
const cursor_style = renderer.cursorStyle(
|
const cursor_style = renderer.cursorStyle(
|
||||||
state,
|
state,
|
||||||
self.focused,
|
self.focused,
|
||||||
cursor_blink_visible,
|
blink_visible,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get our preedit state
|
// Get our preedit state
|
||||||
@ -1027,6 +1030,9 @@ pub fn updateFrame(
|
|||||||
.full_rebuild = full_rebuild,
|
.full_rebuild = full_rebuild,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.blink_visible = blink_visible;
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
critical.screen.deinit();
|
critical.screen.deinit();
|
||||||
if (critical.preedit) |p| p.deinit(self.alloc);
|
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();
|
errdefer self.gpu_state.releaseFrame();
|
||||||
// log.debug("drawing frame index={}", .{self.gpu_state.frame_index});
|
// log.debug("drawing frame index={}", .{self.gpu_state.frame_index});
|
||||||
|
|
||||||
|
self.uniforms.blink_visible = self.blink_visible;
|
||||||
|
|
||||||
// Setup our frame data
|
// Setup our frame data
|
||||||
try frame.uniforms.sync(self.gpu_state.device, &.{self.uniforms});
|
try frame.uniforms.sync(self.gpu_state.device, &.{self.uniforms});
|
||||||
try frame.cells_bg.sync(self.gpu_state.device, self.cells.bg_cells);
|
try frame.cells_bg.sync(self.gpu_state.device, self.cells.bg_cells);
|
||||||
@ -1603,6 +1611,11 @@ fn drawCellFgs(
|
|||||||
@as(c_ulong, 1),
|
@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(
|
encoder.msgSend(
|
||||||
void,
|
void,
|
||||||
@ -2539,15 +2552,19 @@ fn updateCell(
|
|||||||
break :glyph;
|
break :glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mode: mtl_shaders.CellText.Mode = switch (try fgMode(
|
var mode: mtl_shaders.CellText.Mode = .{ .fg = true };
|
||||||
|
|
||||||
|
switch (try fgMode(
|
||||||
render.presentation,
|
render.presentation,
|
||||||
cell_pin,
|
cell_pin,
|
||||||
)) {
|
)) {
|
||||||
.normal => .fg,
|
.normal => {},
|
||||||
.color => .fg_color,
|
.color => mode.fg_color = true,
|
||||||
.constrained => .fg_constrained,
|
.constrained => mode.fg_constrained = true,
|
||||||
.powerline => .fg_powerline,
|
.powerline => mode.fg_powerline = true,
|
||||||
};
|
}
|
||||||
|
|
||||||
|
mode.fg_blink = style.flags.blink;
|
||||||
|
|
||||||
try self.cells.add(self.alloc, .text, .{
|
try self.cells.add(self.alloc, .text, .{
|
||||||
.mode = mode,
|
.mode = mode,
|
||||||
|
@ -137,6 +137,9 @@ pub const Uniforms = extern struct {
|
|||||||
cursor_pos: [2]u16 align(4),
|
cursor_pos: [2]u16 align(4),
|
||||||
cursor_color: [4]u8 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) {
|
const PaddingExtend = packed struct(u8) {
|
||||||
left: bool = false,
|
left: bool = false,
|
||||||
right: bool = false,
|
right: bool = false,
|
||||||
@ -324,12 +327,15 @@ pub const CellText = extern struct {
|
|||||||
mode: Mode align(1),
|
mode: Mode align(1),
|
||||||
constraint_width: u8 align(1) = 0,
|
constraint_width: u8 align(1) = 0,
|
||||||
|
|
||||||
pub const Mode = enum(u8) {
|
pub const Mode = packed struct(u8) {
|
||||||
fg = 1,
|
fg: bool,
|
||||||
fg_constrained = 2,
|
fg_constrained: bool,
|
||||||
fg_color = 3,
|
fg_color: bool,
|
||||||
cursor = 4,
|
cursor: bool,
|
||||||
fg_powerline = 5,
|
fg_powerline: bool,
|
||||||
|
fg_blink: bool,
|
||||||
|
|
||||||
|
_padding: u3 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
@ -18,6 +18,7 @@ struct Uniforms {
|
|||||||
float min_contrast;
|
float min_contrast;
|
||||||
ushort2 cursor_pos;
|
ushort2 cursor_pos;
|
||||||
uchar4 cursor_color;
|
uchar4 cursor_color;
|
||||||
|
bool blink_visible;
|
||||||
};
|
};
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
@ -161,9 +162,9 @@ fragment float4 cell_bg_fragment(
|
|||||||
enum CellTextMode : uint8_t {
|
enum CellTextMode : uint8_t {
|
||||||
MODE_TEXT = 1u,
|
MODE_TEXT = 1u,
|
||||||
MODE_TEXT_CONSTRAINED = 2u,
|
MODE_TEXT_CONSTRAINED = 2u,
|
||||||
MODE_TEXT_COLOR = 3u,
|
MODE_TEXT_COLOR = 4u,
|
||||||
MODE_TEXT_CURSOR = 4u,
|
MODE_TEXT_CURSOR = 8u,
|
||||||
MODE_TEXT_POWERLINE = 5u,
|
MODE_TEXT_POWERLINE = 16u,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellTextVertexIn {
|
struct CellTextVertexIn {
|
||||||
@ -257,7 +258,7 @@ vertex CellTextVertexOut cell_text_vertex(
|
|||||||
// If we're constrained then we need to scale the glyph.
|
// If we're constrained then we need to scale the glyph.
|
||||||
// We also always constrain colored glyphs since we should have
|
// We also always constrain colored glyphs since we should have
|
||||||
// their scaled cell size exactly correct.
|
// 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;
|
float max_width = uniforms.cell_size.x * in.constraint_width;
|
||||||
if (size.x > max_width) {
|
if (size.x > max_width) {
|
||||||
float new_y = size.y * (max_width / size.x);
|
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
|
// since we want color glyphs to appear in their original color
|
||||||
// and Powerline glyphs to be unaffected (else parts of the line would
|
// and Powerline glyphs to be unaffected (else parts of the line would
|
||||||
// have different colors as some parts are displayed via background colors).
|
// 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;
|
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);
|
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 this cell is the cursor cell, then we need to change the color.
|
||||||
if (
|
if (
|
||||||
in.mode != MODE_TEXT_CURSOR &&
|
!(in.mode & MODE_TEXT_CURSOR) &&
|
||||||
in.grid_pos.x == uniforms.cursor_pos.x &&
|
in.grid_pos.x == uniforms.cursor_pos.x &&
|
||||||
in.grid_pos.y == uniforms.cursor_pos.y
|
in.grid_pos.y == uniforms.cursor_pos.y
|
||||||
) {
|
) {
|
||||||
@ -305,7 +306,8 @@ vertex CellTextVertexOut cell_text_vertex(
|
|||||||
fragment float4 cell_text_fragment(
|
fragment float4 cell_text_fragment(
|
||||||
CellTextVertexOut in [[stage_in]],
|
CellTextVertexOut in [[stage_in]],
|
||||||
texture2d<float> textureGrayscale [[texture(0)]],
|
texture2d<float> textureGrayscale [[texture(0)]],
|
||||||
texture2d<float> textureColor [[texture(1)]]
|
texture2d<float> textureColor [[texture(1)]],
|
||||||
|
constant Uniforms& uniforms [[buffer(1)]]
|
||||||
) {
|
) {
|
||||||
constexpr sampler textureSampler(
|
constexpr sampler textureSampler(
|
||||||
coord::pixel,
|
coord::pixel,
|
||||||
@ -313,28 +315,23 @@ fragment float4 cell_text_fragment(
|
|||||||
filter::nearest
|
filter::nearest
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (in.mode) {
|
if (in.mode & MODE_TEXT_COLOR) {
|
||||||
default:
|
return textureColor.sample(textureSampler, in.tex_coord);
|
||||||
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_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
|
// Image Shader
|
||||||
|
Reference in New Issue
Block a user