Start work on using a struct for the cell

Should eventually allow the screen buf to be sent directly to the GPU
without a serialization step.

Migrates line-buf.c
This commit is contained in:
Kovid Goyal
2017-08-28 10:09:58 +05:30
parent af3c89d79f
commit 0cbd3a2820
4 changed files with 97 additions and 109 deletions

View File

@@ -36,8 +36,6 @@ typedef unsigned int index_type;
#define SGR_PROTOCOL 2
#define URXVT_PROTOCOL 3
#define CELL_FIELD_COUNT 5
#define CELL_SIZE (CELL_FIELD_COUNT * 4)
#define DATA_CELL_SIZE 6
#define CHAR_MASK 0xFFFFFF
@@ -73,12 +71,6 @@ typedef unsigned int index_type;
c->decoration = (a >> DECORATION_SHIFT) & 3; c->bold = (a >> BOLD_SHIFT) & 1; c->italic = (a >> ITALIC_SHIFT) & 1; \
c->reverse = (a >> REVERSE_SHIFT) & 1; c->strikethrough = (a >> STRIKE_SHIFT) & 1;
#define SET_ATTRIBUTE(chars, shift, val) \
mask = shift == DECORATION_SHIFT ? 3 : 1; \
val = (val & mask) << (ATTRS_SHIFT + shift); \
mask = ~(mask << (ATTRS_SHIFT + shift)); \
for (index_type i = 0; i < self->xnum; i++) (chars)[i] = ((chars)[i] & mask) | val;
#define COPY_CELL(src, s, dest, d) \
(dest)->chars[d] = (src)->chars[s]; \
(dest)->fg_colors[d] = (src)->fg_colors[s]; \
@@ -88,20 +80,6 @@ typedef unsigned int index_type;
#define COPY_SELF_CELL(s, d) COPY_CELL(self, s, self, d)
#define COPY_LINE(src, dest) \
memcpy((dest)->chars, (src)->chars, sizeof(char_type) * MIN((src)->xnum, (dest)->xnum)); \
memcpy((dest)->fg_colors, (src)->fg_colors, sizeof(color_type) * MIN((src)->xnum, (dest)->xnum)); \
memcpy((dest)->bg_colors, (src)->bg_colors, sizeof(color_type) * MIN((src)->xnum, (dest)->xnum)); \
memcpy((dest)->decoration_fg, (src)->decoration_fg, sizeof(color_type) * MIN((src)->xnum, (dest)->xnum)); \
memcpy((dest)->combining_chars, (src)->combining_chars, sizeof(combining_type) * MIN((src)->xnum, (dest)->xnum));
#define CLEAR_LINE(l, num) \
for (index_type i = 0; i < (num); i++) (l)->chars[i] = (1 << ATTRS_SHIFT) | 32; \
memset((l)->fg_colors, 0, (num) * sizeof(color_type)); \
memset((l)->bg_colors, 0, (num) * sizeof(color_type)); \
memset((l)->decoration_fg, 0, (num) * sizeof(color_type)); \
memset((l)->combining_chars, 0, (num) * sizeof(combining_type));
#define METHOD(name, arg_type) {#name, (PyCFunction)name, arg_type, name##_doc},
#define BOOL_GETSET(type, x) \
@@ -149,14 +127,16 @@ typedef unsigned int index_type;
#define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop")
#endif
typedef struct {
char_type ch;
color_type fg, bg, decoration_fg;
combining_type cc;
} Cell;
typedef struct {
PyObject_HEAD
char_type *chars;
color_type *fg_colors;
color_type *bg_colors;
color_type *decoration_fg;
combining_type *combining_chars;
Cell *cells;
index_type xnum, ynum;
bool continued;
bool needs_free;
@@ -167,21 +147,14 @@ PyTypeObject Line_Type;
typedef struct {
PyObject_HEAD
uint8_t *buf;
Cell *buf;
index_type xnum, ynum, *line_map, *scratch;
index_type block_size;
bool *continued_map;
Line *line;
// Pointers into buf
char_type *chars;
color_type *fg_colors;
color_type *bg_colors;
color_type *decoration_fg;
combining_type *combining_chars;
} LineBuf;
PyTypeObject LineBuf_Type;
typedef struct {
PyObject_HEAD

View File

@@ -6,16 +6,27 @@
*/
#include "data-types.h"
#include "lineops.h"
#include <structmember.h>
static inline Cell*
lineptr(LineBuf *linebuf, index_type y) {
return linebuf->buf + y * linebuf->xnum;
}
static inline void
clear_chars_in_line(Cell *cells, index_type xnum, char_type ch) {
char_type c = (1 << ATTRS_SHIFT) | ch;
for (index_type i = 0; i < xnum; i++) cells[i].ch = c;
}
static inline void
clear_chars_to(LineBuf* linebuf, index_type y, char_type ch) {
char_type *chars = linebuf->chars + linebuf->xnum * y;
for (index_type i = 0; i < linebuf->xnum; i++) chars[i] = (1 << ATTRS_SHIFT) | ch;
clear_chars_in_line(lineptr(linebuf, y), linebuf->xnum, ch);
}
void linebuf_clear(LineBuf *self, char_type ch) {
memset(self->buf, 0, self->block_size * CELL_SIZE);
memset(self->buf, 0, self->xnum * self->ynum * sizeof(Cell));
memset(self->continued_map, 0, self->ynum * sizeof(bool));
for (index_type i = 0; i < self->ynum; i++) {
clear_chars_to(self, i, ch);
@@ -51,8 +62,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
if (self != NULL) {
self->xnum = xnum;
self->ynum = ynum;
self->block_size = xnum * ynum;
self->buf = PyMem_Calloc(xnum * ynum, CELL_SIZE);
self->buf = PyMem_Calloc(xnum * ynum, sizeof(Cell));
self->line_map = PyMem_Calloc(ynum, sizeof(index_type));
self->scratch = PyMem_Calloc(ynum, sizeof(index_type));
self->continued_map = PyMem_Calloc(ynum, sizeof(bool));
@@ -62,11 +72,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
PyMem_Free(self->buf); PyMem_Free(self->line_map); PyMem_Free(self->continued_map); Py_CLEAR(self->line);
Py_CLEAR(self);
} else {
self->chars = (char_type*)self->buf;
self->fg_colors = (color_type*)(self->chars + self->block_size);
self->bg_colors = (color_type*)(self->fg_colors + self->block_size);
self->decoration_fg = (color_type*)(self->bg_colors + self->block_size);
self->combining_chars = (combining_type*)(self->decoration_fg + self->block_size);
self->line->xnum = xnum;
for(index_type i = 0; i < ynum; i++) {
self->line_map[i] = i;
@@ -88,18 +93,17 @@ dealloc(LineBuf* self) {
Py_TYPE(self)->tp_free((PyObject*)self);
}
#define INIT_LINE(lb, l, ynum) \
(l)->chars = (lb)->chars + (ynum) * (lb)->xnum; \
(l)->fg_colors = (lb)->fg_colors + (ynum) * (lb)->xnum; \
(l)->bg_colors = (lb)->bg_colors + (ynum) * (lb)->xnum; \
(l)->decoration_fg = (lb)->decoration_fg + (ynum) * (lb)->xnum; \
(l)->combining_chars = (lb)->combining_chars + (ynum) * (lb)->xnum;
static inline void
init_line(LineBuf *lb, Line *l, index_type ynum) {
l->cells = lineptr(lb, ynum);
}
void linebuf_init_line(LineBuf *self, index_type idx) {
void
linebuf_init_line(LineBuf *self, index_type idx) {
self->line->ynum = idx;
self->line->xnum = self->xnum;
self->line->continued = self->continued_map[idx];
INIT_LINE(self, self->line, self->line_map[idx]);
init_line(self, self->line, self->line_map[idx]);
}
static PyObject*
@@ -115,15 +119,15 @@ line(LineBuf *self, PyObject *y) {
return (PyObject*)self->line;
}
unsigned int linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
char_type *chars = self->chars + self->line_map[y] * self->xnum;
return (chars[x] >> ATTRS_SHIFT) & WIDTH_MASK;
unsigned int
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
return (lineptr(self, y)[x].ch >> ATTRS_SHIFT) & WIDTH_MASK;
}
void linebuf_set_attribute(LineBuf *self, unsigned int shift, unsigned int val) {
char_type mask;
void
linebuf_set_attribute(LineBuf *self, unsigned int shift, unsigned int val) {
for (index_type y = 0; y < self->ynum; y++) {
SET_ATTRIBUTE(self->chars + y * self->xnum, shift, val);
set_attribute_on_line(lineptr(self, y), shift, val, self->xnum);
}
}
@@ -148,36 +152,22 @@ set_continued(LineBuf *self, PyObject *args) {
Py_RETURN_NONE;
}
static inline int
static inline bool
allocate_line_storage(Line *line, bool initialize) {
if (initialize) {
line->chars = PyMem_Calloc(line->xnum, sizeof(char_type));
line->fg_colors = PyMem_Calloc(line->xnum, sizeof(color_type));
line->bg_colors = PyMem_Calloc(line->xnum, sizeof(color_type));
line->decoration_fg = PyMem_Calloc(line->xnum, sizeof(color_type));
line->combining_chars = PyMem_Calloc(line->xnum, sizeof(combining_type));
for (index_type i = 0; i < line->xnum; i++) line->chars[i] = (1 << ATTRS_SHIFT) | 32;
line->cells = PyMem_Calloc(line->xnum, sizeof(Cell));
if (line->cells == NULL) { PyErr_NoMemory(); return false; }
clear_chars_in_line(line->cells, line->xnum, ' ');
} else {
line->chars = PyMem_Malloc(line->xnum * sizeof(char_type));
line->fg_colors = PyMem_Malloc(line->xnum * sizeof(color_type));
line->bg_colors = PyMem_Malloc(line->xnum * sizeof(color_type));
line->decoration_fg = PyMem_Malloc(line->xnum * sizeof(color_type));
line->combining_chars = PyMem_Malloc(line->xnum * sizeof(combining_type));
}
if (line->chars == NULL || line->fg_colors == NULL || line->bg_colors == NULL || line->decoration_fg == NULL || line->combining_chars == NULL) {
PyMem_Free(line->chars); line->chars = NULL;
PyMem_Free(line->fg_colors); line->fg_colors = NULL;
PyMem_Free(line->bg_colors); line->bg_colors = NULL;
PyMem_Free(line->decoration_fg); line->decoration_fg = NULL;
PyMem_Free(line->combining_chars); line->combining_chars = NULL;
PyErr_NoMemory();
return 0;
line->cells = PyMem_Malloc(line->xnum * sizeof(Cell));
if (line->cells == NULL) { PyErr_NoMemory(); return false; }
}
line->needs_free = 1;
return 1;
return true;
}
static inline PyObject* create_line_copy_inner(LineBuf* self, index_type y) {
static inline PyObject*
create_line_copy_inner(LineBuf* self, index_type y) {
Line src, *line;
line = alloc_line();
if (line == NULL) return PyErr_NoMemory();
@@ -185,8 +175,8 @@ static inline PyObject* create_line_copy_inner(LineBuf* self, index_type y) {
if (!allocate_line_storage(line, 0)) { Py_CLEAR(line); return PyErr_NoMemory(); }
line->ynum = y;
line->continued = self->continued_map[y];
INIT_LINE(self, &src, self->line_map[y]);
COPY_LINE(&src, line);
init_line(self, &src, self->line_map[y]);
copy_line(&src, line);
return (PyObject*)line;
}
@@ -207,15 +197,20 @@ copy_line_to(LineBuf *self, PyObject *args) {
src.xnum = self->xnum; dest->xnum = self->xnum;
dest->ynum = y;
dest->continued = self->continued_map[y];
INIT_LINE(self, &src, self->line_map[y]);
COPY_LINE(&src, dest);
init_line(self, &src, self->line_map[y]);
copy_line(&src, dest);
Py_RETURN_NONE;
}
static inline void
clear_line_(Line *l, index_type xnum) {
memset(l->cells, 0, xnum * sizeof(Cell));
}
void linebuf_clear_line(LineBuf *self, index_type y) {
Line l;
INIT_LINE(self, &l, self->line_map[y]);
CLEAR_LINE(&l, self->xnum);
init_line(self, &l, self->line_map[y]);
clear_line_(&l, self->xnum);
self->continued_map[y] = 0;
}
@@ -299,8 +294,8 @@ void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsig
}
Line l;
for (i = y; i < y + num; i++) {
INIT_LINE(self, &l, self->line_map[i]);
CLEAR_LINE(&l, self->xnum);
init_line(self, &l, self->line_map[i]);
clear_line_(&l, self->xnum);
self->continued_map[i] = 0;
}
}
@@ -334,8 +329,8 @@ linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bot
}
Line l;
for (i = ylimit - num; i < ylimit; i++) {
INIT_LINE(self, &l, self->line_map[i]);
CLEAR_LINE(&l, self->xnum);
init_line(self, &l, self->line_map[i]);
clear_line_(&l, self->xnum);
self->continued_map[i] = 0;
}
}
@@ -356,7 +351,7 @@ as_ansi(LineBuf *self, PyObject *callback) {
Line l = {.xnum=self->xnum};
for(index_type i = 0; i < self->ynum; i++) {
l.continued = (i < self->ynum - 1) ? self->continued_map[i+1] : self->continued_map[i];
INIT_LINE(self, (&l), self->line_map[i]);
init_line(self, (&l), self->line_map[i]);
index_type num = line_as_ansi(&l, t, 5120);
if (!(l.continued) && num < 5119) t[num++] = 10; // 10 = \n
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, t, num);
@@ -430,8 +425,8 @@ copy_old(LineBuf *self, PyObject *y) {
index_type s = self->ynum - 1 - i, o = other->ynum - 1 - i;
self->continued_map[s] = other->continued_map[o];
s = self->line_map[s]; o = other->line_map[o];
INIT_LINE(self, &sl, s); INIT_LINE(other, &ol, o);
COPY_LINE(&ol, &sl);
init_line(self, &sl, s); init_line(other, &ol, o);
copy_line(&ol, &sl);
}
Py_RETURN_NONE;
}
@@ -448,7 +443,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *his
Py_BEGIN_ALLOW_THREADS;
memcpy(other->line_map, self->line_map, sizeof(index_type) * self->ynum);
memcpy(other->continued_map, self->continued_map, sizeof(bool) * self->ynum);
memcpy(other->buf, self->buf, self->xnum * self->ynum * CELL_SIZE);
memcpy(other->buf, self->buf, self->xnum * self->ynum * sizeof(Cell));
Py_END_ALLOW_THREADS;
return;
}
@@ -456,9 +451,9 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *his
// Find the first line that contains some content
Py_BEGIN_ALLOW_THREADS;
for (first = self->ynum - 1; true; first--) {
char_type *chars = self->chars + self->xnum * first;
Cell *cells = lineptr(self, first);
for(i = 0; i < self->xnum; i++) {
if ((chars[i] & CHAR_MASK) != 32) { is_empty = false; break; }
if ((cells[i].ch & CHAR_MASK) != 32) { is_empty = false; break; }
}
if (!is_empty || !first) break;
}

22
kitty/lineops.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include "data-types.h"
static inline void
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
uint32_t mask = shift == DECORATION_SHIFT ? 3 : 1;
uint32_t aval = (val & mask) << (ATTRS_SHIFT + shift);
mask = ~(mask << (ATTRS_SHIFT + shift));
for (index_type i = 0; i < xnum; i++) cells[i].ch = (cells[i].ch & mask) | aval;
}
static inline void
copy_line(Line *src, Line *dest) {
memcpy(dest->cells, src->cells, sizeof(Cell) * (MIN(src->xnum, dest->xnum)));
}

View File

@@ -12,11 +12,11 @@
#endif
#ifndef init_src_line
#define init_src_line(src_y) INIT_LINE(src, src->line, src->line_map[src_y]);
#define init_src_line(src_y) init_line(src, src->line, src->line_map[src_y]);
#endif
#ifndef init_dest_line
#define init_dest_line(dest_y) INIT_LINE(dest, dest->line, dest->line_map[dest_y]);
#define init_dest_line(dest_y) init_line(dest, dest->line, dest->line_map[dest_y]);
#endif
#ifndef first_dest_line
@@ -41,16 +41,14 @@
#define is_src_line_continued(src_y) (src_y < src->ynum - 1 ? src->continued_map[src_y + 1] : false)
#endif
static inline void copy_range(Line *src, index_type src_at, Line* dest, index_type dest_at, index_type num) {
memcpy(dest->chars + dest_at, src->chars + src_at, num * sizeof(char_type));
memcpy(dest->fg_colors + dest_at, src->fg_colors + src_at, num * sizeof(color_type));
memcpy(dest->bg_colors + dest_at, src->bg_colors + src_at, num * sizeof(color_type));
memcpy(dest->decoration_fg + dest_at, src->decoration_fg + src_at, num * sizeof(color_type));
memcpy(dest->combining_chars + dest_at, src->combining_chars + src_at, num * sizeof(combining_type));
static inline void
copy_range(Line *src, index_type src_at, Line* dest, index_type dest_at, index_type num) {
memcpy(dest->cells + dest_at, src->cells + src_at, num * sizeof(Cell));
}
static void rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf UNUSED *historybuf) {
static void
rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf UNUSED *historybuf) {
bool src_line_is_continued = false;
index_type src_y = 0, src_x = 0, dest_x = 0, dest_y = 0, num = 0, src_x_limit = 0;
Py_BEGIN_ALLOW_THREADS;
@@ -62,7 +60,7 @@ static void rewrap_inner(BufType *src, BufType *dest, const index_type src_limit
src_x_limit = src->xnum;
if (!src_line_is_continued) {
// Trim trailing white-space since there is a hard line break at the end of this line
while(src_x_limit && (src->line->chars[src_x_limit - 1] & CHAR_MASK) == 32) src_x_limit--;
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch & CHAR_MASK) == 32) src_x_limit--;
}
while (src_x < src_x_limit) {