mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-11 02:59:40 +02:00
Do color mapping on the GPU
This commit is contained in:
@@ -2,6 +2,8 @@ uniform uvec2 dimensions; // xnum, ynum
|
||||
uniform vec4 steps; // xstart, ystart, dx, dy
|
||||
uniform vec2 sprite_layout; // dx, dy
|
||||
uniform ivec2 color_indices; // which color to use as fg and which as bg
|
||||
uniform uvec2 default_colors; // The default foreground and background colors
|
||||
uniform uint color_table[256]; // The color table
|
||||
in uvec3 sprite_coords;
|
||||
in uvec3 colors;
|
||||
out vec3 sprite_pos;
|
||||
@@ -18,11 +20,12 @@ const uvec2 pos_map[] = uvec2[4](
|
||||
uvec2(0, 0) // left, top
|
||||
);
|
||||
|
||||
const uint BYTE_MASK = uint(255);
|
||||
const uint BYTE_MASK = uint(0xFF);
|
||||
const uint SHORT_MASK = uint(0xFFFF);
|
||||
const uint ZERO = uint(0);
|
||||
const uint SMASK = uint(3);
|
||||
|
||||
vec3 to_color(uint c) {
|
||||
vec3 color_to_vec(uint c) {
|
||||
uint r, g, b;
|
||||
r = (c >> 16) & BYTE_MASK;
|
||||
g = (c >> 8) & BYTE_MASK;
|
||||
@@ -30,6 +33,22 @@ vec3 to_color(uint c) {
|
||||
return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
|
||||
}
|
||||
|
||||
vec3 to_color(uint c, uint defval) {
|
||||
int t = int(c & BYTE_MASK);
|
||||
uint r;
|
||||
switch(t) {
|
||||
case 1:
|
||||
r = color_table[(c >> 8) & BYTE_MASK];
|
||||
break;
|
||||
case 2:
|
||||
r = c >> 8;
|
||||
break;
|
||||
default:
|
||||
r = defval;
|
||||
}
|
||||
return color_to_vec(r);
|
||||
}
|
||||
|
||||
vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
|
||||
vec2 s_xpos = vec2(x, float(x) + 1.0) * sprite_layout.x;
|
||||
vec2 s_ypos = vec2(y, float(y) + 1.0) * sprite_layout.y;
|
||||
@@ -47,13 +66,13 @@ void main() {
|
||||
uvec2 pos = pos_map[gl_VertexID];
|
||||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
||||
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z);
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK);
|
||||
uint fg = colors[color_indices[0]];
|
||||
uint bg = colors[color_indices[1]];
|
||||
uint decoration = colors[2];
|
||||
foreground = to_color(fg);
|
||||
background = to_color(bg);
|
||||
decoration_fg = to_color(decoration);
|
||||
underline_pos = to_sprite_pos(pos, (decoration >> 24) & SMASK, ZERO, ZERO);
|
||||
strike_pos = to_sprite_pos(pos, (decoration >> 26) & SMASK, ZERO, ZERO);
|
||||
foreground = to_color(fg, default_colors[0]);
|
||||
background = to_color(bg, default_colors[1]);
|
||||
decoration_fg = to_color(decoration, default_colors[0]);
|
||||
underline_pos = to_sprite_pos(pos, (sprite_coords.z >> 24) & SMASK, ZERO, ZERO);
|
||||
strike_pos = to_sprite_pos(pos, (sprite_coords.z >> 26) & SMASK, ZERO, ZERO);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ from .fast_data_types import (
|
||||
CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND,
|
||||
GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, glDrawArrays,
|
||||
glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, glUniform2i,
|
||||
glUniform2ui, glUniform4f
|
||||
glUniform2ui, glUniform4f, glUniform1uiv
|
||||
)
|
||||
from .rgb import to_color
|
||||
from .shaders import ShaderProgram, load_shaders
|
||||
@@ -124,6 +124,8 @@ def calculate_gl_geometry(window_geometry):
|
||||
def render_cells(vao_id, sg, cell_program, sprites, color_profile, invert_colors=False):
|
||||
ul = cell_program.uniform_location
|
||||
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||
glUniform2ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg)
|
||||
glUniform1uiv(ul('color_table'), 256, color_profile.color_table_address())
|
||||
glUniform2i(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1)
|
||||
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||
glUniform1i(ul('sprites'), sprites.sampler_num)
|
||||
@@ -200,7 +202,6 @@ class CharGrid:
|
||||
dirtied = True
|
||||
setattr(self.screen.color_profile, which.name, val)
|
||||
if dirtied:
|
||||
self.screen.color_profile.dirty = True
|
||||
self.screen.mark_as_dirty()
|
||||
|
||||
def scroll(self, amt, upwards=True):
|
||||
|
||||
@@ -351,7 +351,7 @@ void cursor_reset(Cursor*);
|
||||
Cursor* cursor_copy(Cursor*);
|
||||
void cursor_copy_to(Cursor *src, Cursor *dest);
|
||||
void cursor_reset_display_attrs(Cursor*);
|
||||
bool update_cell_range_data(ScreenModes *modes, SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, unsigned int *);
|
||||
bool update_cell_range_data(ScreenModes *modes, SpriteMap *, Line *, unsigned int, unsigned int, unsigned int *);
|
||||
|
||||
PyObject* line_text_at(char_type, combining_type);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch);
|
||||
|
||||
13
kitty/gl.h
13
kitty/gl.h
@@ -84,6 +84,18 @@ Uniform2ui(PyObject UNUSED *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Uniform1uiv(PyObject UNUSED *self, PyObject *args) {
|
||||
int location;
|
||||
unsigned int count;
|
||||
PyObject *value;
|
||||
if (!PyArg_ParseTuple(args, "iIO", &location, &count, &value)) return NULL;
|
||||
glUniform1uiv(location, count, (GLuint*)PyLong_AsVoidPtr(value));
|
||||
CHECK_ERROR;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
Uniform2i(PyObject UNUSED *self, PyObject *args) {
|
||||
int location;
|
||||
@@ -772,6 +784,7 @@ int add_module_gl_constants(PyObject *module) {
|
||||
METH(GetProgramiv, METH_VARARGS) \
|
||||
METH(GetShaderiv, METH_VARARGS) \
|
||||
METH(Uniform2ui, METH_VARARGS) \
|
||||
METH(Uniform1uiv, METH_VARARGS) \
|
||||
METH(Uniform2i, METH_VARARGS) \
|
||||
METH(Uniform1i, METH_VARARGS) \
|
||||
METH(Uniform2f, METH_VARARGS) \
|
||||
|
||||
@@ -1176,7 +1176,7 @@ screen_update_cell_data(Screen *self, PyObject *args) {
|
||||
PyObject *cursor_changed = self->change_tracker->cursor_changed ? Py_True : Py_False;
|
||||
unsigned int history_line_added_count = self->change_tracker->history_line_added_count;
|
||||
|
||||
if (!tracker_update_cell_data(&(self->modes), self->change_tracker, self->linebuf, spm, self->color_profile, data, (bool)force_screen_refresh)) return NULL;
|
||||
if (!tracker_update_cell_data(&(self->modes), self->change_tracker, self->linebuf, spm, data, (bool)force_screen_refresh)) return NULL;
|
||||
return Py_BuildValue("OI", cursor_changed, history_line_added_count);
|
||||
}
|
||||
|
||||
@@ -1194,7 +1194,7 @@ set_scroll_cell_data(Screen *self, PyObject *args) {
|
||||
for (index_type y = 0; y < MIN(self->lines, scrolled_by); y++) {
|
||||
historybuf_init_line(self->historybuf, scrolled_by - 1 - y, self->historybuf->line);
|
||||
self->historybuf->line->ynum = y;
|
||||
if (!update_cell_range_data(&(self->modes), spm, self->historybuf->line, 0, self->columns - 1, self->color_profile, data)) return NULL;
|
||||
if (!update_cell_range_data(&(self->modes), spm, self->historybuf->line, 0, self->columns - 1, data)) return NULL;
|
||||
}
|
||||
if (scrolled_by < self->lines) {
|
||||
// Less than a full screen has been scrolled, copy some lines from the screen buffer to the scroll buffer
|
||||
|
||||
@@ -139,14 +139,12 @@ position_for(SpriteMap *self, PyObject *args) {
|
||||
}
|
||||
|
||||
bool
|
||||
update_cell_range_data(ScreenModes *modes, SpriteMap *self, Line *line, unsigned int xstart, unsigned int xmax, ColorProfile *color_profile, unsigned int *data) {
|
||||
update_cell_range_data(ScreenModes *modes, SpriteMap *self, Line *line, unsigned int xstart, unsigned int xmax, unsigned int *data) {
|
||||
SpritePosition *sp;
|
||||
char_type previous_ch=0, ch;
|
||||
uint8_t previous_width = 0;
|
||||
int err = 0;
|
||||
const bool screen_reversed = modes->mDECSCNM;
|
||||
color_type fg = colorprofile_to_color(color_profile, color_profile->overridden.default_fg, color_profile->configured.default_fg);
|
||||
color_type bg = colorprofile_to_color(color_profile, color_profile->overridden.default_bg, color_profile->configured.default_bg);
|
||||
|
||||
size_t base = line->ynum * line->xnum * DATA_CELL_SIZE;
|
||||
for (size_t i = xstart, offset = base + xstart * DATA_CELL_SIZE; i <= xmax; i++, offset += DATA_CELL_SIZE) {
|
||||
@@ -160,11 +158,10 @@ update_cell_range_data(ScreenModes *modes, SpriteMap *self, Line *line, unsigned
|
||||
bool reverse = ((attrs >> REVERSE_SHIFT) & 1) ^ screen_reversed;
|
||||
data[offset] = sp->x;
|
||||
data[offset+1] = sp->y;
|
||||
data[offset+2] = sp->z;
|
||||
data[offset+(reverse ? 4 : 3)] = colorprofile_to_color(color_profile, line->cells[i].fg & COL_MASK, fg);
|
||||
data[offset+(reverse ? 3 : 4)] = colorprofile_to_color(color_profile, line->cells[i].bg & COL_MASK, bg);
|
||||
unsigned int decoration_fg = colorprofile_to_color(color_profile, line->cells[i].decoration_fg & COL_MASK, data[offset+3]);
|
||||
data[offset+5] = (decoration_fg & COL_MASK) | (decoration << 24) | (strikethrough << 26);
|
||||
data[offset+2] = sp->z | (decoration << 24) | (strikethrough << 26);
|
||||
data[offset+(reverse ? 4 : 3)] = line->cells[i].fg;
|
||||
data[offset+(reverse ? 3 : 4)] = line->cells[i].bg;
|
||||
data[offset+5] = line->cells[i].fg;
|
||||
previous_ch = ch; previous_width = (attrs) & WIDTH_MASK;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -97,13 +97,13 @@ update_cell_range(ChangeTracker *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
bool tracker_update_cell_data(ScreenModes *modes, ChangeTracker *self, LineBuf *lb, SpriteMap *spm, ColorProfile *color_profile, unsigned int *data, bool force_screen_refresh) {
|
||||
bool tracker_update_cell_data(ScreenModes *modes, ChangeTracker *self, LineBuf *lb, SpriteMap *spm, unsigned int *data, bool force_screen_refresh) {
|
||||
unsigned int y;
|
||||
Py_ssize_t start;
|
||||
|
||||
#define UPDATE_RANGE(xstart, xmax) \
|
||||
linebuf_init_line(lb, y); \
|
||||
if (!update_cell_range_data(modes, spm, lb->line, (xstart), (xmax), color_profile, data)) return false;
|
||||
if (!update_cell_range_data(modes, spm, lb->line, (xstart), (xmax), data)) return false;
|
||||
|
||||
if (self->screen_changed || force_screen_refresh) {
|
||||
for (y = 0; y < self->ynum; y++) {
|
||||
|
||||
@@ -52,4 +52,4 @@ static inline void tracker_reset(ChangeTracker *self) {
|
||||
|
||||
PyObject* tracker_consolidate_changes(ChangeTracker *self);
|
||||
bool tracker_resize(ChangeTracker *self, unsigned int ynum, unsigned int xnum);
|
||||
bool tracker_update_cell_data(ScreenModes*, ChangeTracker *, LineBuf *, SpriteMap *, ColorProfile *, unsigned int *, bool);
|
||||
bool tracker_update_cell_data(ScreenModes*, ChangeTracker *, LineBuf *, SpriteMap *, unsigned int *, bool);
|
||||
|
||||
Reference in New Issue
Block a user