Elide unnecessary sprixel invalidations

When the damaged cell of a sprixel is actually entirely
transparent (or annihilated), there's no need to invalidate
it. Check for this in the TAM in sprixel_invalidate(). Good
optimization, and eliminates a lot of the flicker in `xray`
on Kitty described in #1522.
This commit is contained in:
nick black 2021-04-14 16:34:43 -04:00 committed by Nick Black
parent 9d516d8c8c
commit 529972d16b
4 changed files with 25 additions and 8 deletions

View File

@ -56,7 +56,8 @@ typedef enum {
typedef enum {
SPRIXCELL_NORMAL, // no transparent pixels in this cell
SPRIXCELL_CONTAINS_TRANS, // this cell has transparent pixels
SPRIXCELL_ANNIHILATED, // this cell has been wiped
SPRIXCELL_ALL_TRANS, // all pixels are naturally transparent
SPRIXCELL_ANNIHILATED, // this cell has been wiped (all trans)
} sprixcell_e;
// there is a context-wide set of displayed pixel glyphs ("sprixels"); i.e.
@ -831,7 +832,7 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int y, int x);
int sixel_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell);
int sprite_destroy(const struct notcurses* nc, const struct ncpile* p, FILE* out, sprixel* s);
void sprixel_free(sprixel* s);
void sprixel_invalidate(sprixel* s);
void sprixel_invalidate(sprixel* s, int y, int x);
void sprixel_movefrom(sprixel* s, int y, int x);
void sprixel_hide(sprixel* s);
int sprite_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
@ -848,7 +849,6 @@ int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, spr
int sprite_kitty_init(int fd);
int sprite_sixel_init(int fd);
int sprite_init(const notcurses* nc);
void sprixel_invalidate(sprixel* s);
int kitty_shutdown(int fd);
int sixel_shutdown(int fd);
sprixel* sprixel_by_id(const notcurses* nc, uint32_t id);

View File

@ -153,6 +153,7 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell
//fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell);
return 0; // already annihilated, needn't draw glyph in kitty
}
//fprintf(stderr, "NEW WIPE %d %d/%d\n", s->id, ycell, xcell);
const int totalpixels = s->pixy * s->pixx;
const int xpixels = nc->tcache.cellpixx;
const int ypixels = nc->tcache.cellpixy;
@ -271,13 +272,21 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
const uint32_t* line = data + (linesize / sizeof(*data)) * y;
source[e] = line[x];
//fprintf(stderr, "%u/%u/%u -> %c%c%c%c %u %u %u %u\n", r, g, b, b64[0], b64[1], b64[2], b64[3], b64[0], b64[1], b64[2], b64[3]);
int tyx = (x / cdimx) + (y / cdimy) * cols;
int xcell = x / cdimx;
int ycell = y / cdimy;
int tyx = xcell + ycell * cols;
//fprintf(stderr, "Tyx: %d y: %d (%d) * %d x: %d (%d)\n", tyx, y, y / cdimy, cols, x, x / cdimx);
if(tacache[tyx] == SPRIXCELL_ANNIHILATED){
wipe[e] = 1;
}else{
wipe[e] = 0;
if(rgba_trans_p(source[e], transcolor)){
if(x % cdimx == 0 && y % cdimy == 0){
tacache[tyx] = SPRIXCELL_ALL_TRANS;
}else if(tacache[tyx] == SPRIXCELL_NORMAL){
tacache[tyx] = SPRIXCELL_CONTAINS_TRANS;
}
}else if(tacache[tyx] == SPRIXCELL_ALL_TRANS){
tacache[tyx] = SPRIXCELL_CONTAINS_TRANS;
}
}

View File

@ -1084,7 +1084,7 @@ rasterize_core(notcurses* nc, const ncpile* p, FILE* out, unsigned phase){
}
//fprintf(stderr, "RAST %08x [%s] to %d/%d cols: %u %016lx\n", srccell->gcluster, pool_extended_gcluster(&nc->pool, srccell), y, x, srccell->width, srccell->channels);
if(rvec[damageidx].sprixel){
sprixel_invalidate(rvec[damageidx].sprixel);
sprixel_invalidate(rvec[damageidx].sprixel, y, x);
}
if(term_putc(out, &nc->pool, srccell)){
return -1;

View File

@ -60,9 +60,17 @@ void sprixel_hide(sprixel* s){
}
}
void sprixel_invalidate(sprixel* s){
if(s->invalidated != SPRIXEL_HIDE){
s->invalidated = SPRIXEL_INVALIDATED;
// y and x are absolute coordinates
void sprixel_invalidate(sprixel* s, int y, int x){
//fprintf(stderr, "INVALIDATING AT %d/%d\n", y, x);
if(s->invalidated != SPRIXEL_HIDE && s->n){
int localy = y - s->n->absy;
int localx = x - s->n->absx;
//fprintf(stderr, "INVALIDATING AT %d/%d (%d/%d) TAM: %d\n", y, x, localy, localx, s->n->tacache[localy * s->dimx + localx]);
if(s->n->tacache[localy * s->dimx + localx] != SPRIXCELL_ALL_TRANS &&
s->n->tacache[localy * s->dimx + localx] != SPRIXCELL_ALL_TRANS){
s->invalidated = SPRIXEL_INVALIDATED;
}
}
}