summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-10-23 15:31:03 +0200
committerDavid Herrmann <dh.herrmann@gmail.com>2013-10-23 15:35:00 +0200
commit7232760fd9fb8fa5bc2863fd1622f67ea7d73a7b (patch)
tree9b246ec2e0087da539cfb407d5c81864d7e1fc24
parent936c62af024089c614e7dca10d6d123c48892300 (diff)
screen: add screen-age to API
This adds the "ageing"-concept to the screen API. Each cell now has an integer attached which describes its age. Furthermore, the whole screen has an age-counter which is increased on every change we do on the screen. Whenever we modify a cell, we increase the age-counter and set the age of the cell to the current value of the age-counter. During rendering, we pass the age of the cell to the cell-renderer. Furthermore, once rendering is done, we return the current screen age. This allows renderers to save the age of the screen with a framebuffer. Once a specific framebuffer is redrawn, only cells with a newer age need to be updated. Everything else can be skipped. By saving the age with the framebuffer, this even allows multi-buffered applications to make use of this (also see the EGL buffer-age ext for a similar feature). Note that the age-counter might overflow. We return 0 in that case (which is an invalid age). Applications need to reset *all* their framebuffer ages if that happens. Note that non-ageing-aware applications can simply ignore the new feature (apart from changing the draw-cb) and it'll work as before. This does _not_ implement the real ageing feature. It only adds the API. We currently always return 1 as age, which is wrong.. We need to fix the whole code to increase ages correctly, which can get quite tricky if we want the scrollback-buffer to work, too. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r--src/libtsm.h6
-rw-r--r--src/tsm_screen.c51
2 files changed, 50 insertions, 7 deletions
diff --git a/src/libtsm.h b/src/libtsm.h
index d8a238e..98d8fcd 100644
--- a/src/libtsm.h
+++ b/src/libtsm.h
@@ -115,6 +115,7 @@ void tsm_utf8_mach_reset(struct tsm_utf8_mach *mach);
/* screen objects */
struct tsm_screen;
+typedef uint_fast32_t tsm_age_t;
#define TSM_SCREEN_INSERT_MODE 0x01
#define TSM_SCREEN_AUTO_WRAP 0x02
@@ -148,6 +149,7 @@ typedef int (*tsm_screen_draw_cb) (struct tsm_screen *con,
unsigned int posx,
unsigned int posy,
const struct tsm_screen_attr *attr,
+ tsm_age_t age,
void *data);
int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data);
@@ -231,8 +233,8 @@ void tsm_screen_selection_target(struct tsm_screen *con,
unsigned int posy);
int tsm_screen_selection_copy(struct tsm_screen *con, char **out);
-void tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
- void *data);
+tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
+ void *data);
/* available character sets */
diff --git a/src/tsm_screen.c b/src/tsm_screen.c
index fc95242..deb2010 100644
--- a/src/tsm_screen.c
+++ b/src/tsm_screen.c
@@ -42,6 +42,18 @@
* accessing the real screen data. However, terminal emulators should have no
* reason to access the data directly. The screen API should provide everything
* they need.
+ *
+ * AGEING:
+ * Each cell, line and screen has an "age" field. This field describes when it
+ * was changed the last time. After drawing a screen, the current screen age is
+ * returned. This allows users to skip drawing specific cells, if their
+ * framebuffer was already drawn with a newer age than a given cell.
+ * However, the screen-age might overflow. This is properly detected and causes
+ * drawing functions to return "0" as age. Users must reset all their
+ * framebuffer ages then. Otherwise, further drawing operations might
+ * incorrectly skip cells.
+ * Furthermore, if a cell has age "0", it means it _has_ to be drawn. No ageing
+ * information is available.
*/
#include <errno.h>
@@ -59,6 +71,7 @@ struct cell {
tsm_symbol_t ch;
unsigned int width;
struct tsm_screen_attr attr;
+ tsm_age_t age;
};
struct line {
@@ -68,6 +81,7 @@ struct line {
unsigned int size;
struct cell *cells;
uint64_t sb_id;
+ tsm_age_t age;
};
#define SELECTION_TOP -1
@@ -87,6 +101,10 @@ struct tsm_screen {
/* default attributes for new cells */
struct tsm_screen_attr def_attr;
+ /* ageing */
+ tsm_age_t age_cnt;
+ unsigned int age_reset : 1;
+
/* current buffer */
unsigned int size_x;
unsigned int size_y;
@@ -96,6 +114,7 @@ struct tsm_screen {
struct line **lines;
struct line **main_lines;
struct line **alt_lines;
+ tsm_age_t age;
/* scroll-back buffer */
unsigned int sb_count; /* number of lines in sb */
@@ -122,6 +141,7 @@ static void cell_init(struct tsm_screen *con, struct cell *cell)
{
cell->ch = 0;
cell->width = 1;
+ cell->age = con->age_cnt;
memcpy(&cell->attr, &con->def_attr, sizeof(cell->attr));
}
@@ -140,6 +160,7 @@ static int line_new(struct tsm_screen *con, struct line **out,
line->next = NULL;
line->prev = NULL;
line->size = width;
+ line->age = con->age_cnt;
line->cells = malloc(sizeof(struct cell) * width);
if (!line->cells) {
@@ -466,6 +487,8 @@ int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data)
con->ref = 1;
con->llog = log;
con->llog_data = log_data;
+ con->age_cnt = 1;
+ con->age = con->age_cnt;
con->def_attr.fr = 255;
con->def_attr.fg = 255;
con->def_attr.fb = 255;
@@ -1775,8 +1798,8 @@ int tsm_screen_selection_copy(struct tsm_screen *con, char **out)
}
SHL_EXPORT
-void tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
- void *data)
+tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
+ void *data)
{
unsigned int cur_x, cur_y;
unsigned int i, j, k;
@@ -1789,9 +1812,10 @@ void tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
size_t len;
bool in_sel = false, sel_start = false, sel_end = false;
bool was_sel = false;
+ tsm_age_t age;
if (!con || !draw_cb)
- return;
+ return 0;
cur_x = con->cursor_x;
if (con->cursor_x >= con->size_x)
@@ -1881,11 +1905,21 @@ void tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
attr.inverse = !attr.inverse;
}
+ if (con->age_reset) {
+ age = 0;
+ } else {
+ age = cell->age;
+ if (line->age > age)
+ age = line->age;
+ if (con->age > age)
+ age = con->age;
+ }
+
ch = tsm_symbol_get(NULL, &cell->ch, &len);
if (cell->ch == ' ' || cell->ch == 0)
len = 0;
ret = draw_cb(con, cell->ch, ch, len, cell->width,
- j, i, &attr, data);
+ j, i, &attr, age, data);
if (ret && warned++ < 3) {
llog_debug(con,
"cannot draw glyph at %ux%u via text-renderer",
@@ -1902,8 +1936,15 @@ void tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
if (!(con->flags & TSM_SCREEN_INVERSE))
attr.inverse = !attr.inverse;
draw_cb(con, 0, NULL, 0, 1,
- cur_x, i, &attr, data);
+ cur_x, i, &attr, 0, data);
}
}
}
+
+ if (con->age_reset) {
+ con->age_reset = 0;
+ return 0;
+ } else {
+ return con->age_cnt;
+ }
}