From 7232760fd9fb8fa5bc2863fd1622f67ea7d73a7b Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 23 Oct 2013 15:31:03 +0200 Subject: [PATCH] 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 --- src/libtsm.h | 6 ++++-- src/tsm_screen.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 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 @@ -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; + } } -- 2.7.4