eliminate sixel flicker #1493

This commit is contained in:
nick black 2021-04-01 20:01:04 -04:00
parent d4883d30f2
commit aa80af8f87
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
9 changed files with 90 additions and 57 deletions

View File

@ -550,7 +550,13 @@ ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file,
bargs.u.pixel.celldimx = n->tcache.cellpixx;
bargs.u.pixel.celldimy = n->tcache.cellpixy;
bargs.u.pixel.colorregs = n->tcache.color_registers;
bargs.u.pixel.sprixelid = n->tcache.sprixelnonce++;
int cols = lenx / bargs.u.pixel.celldimx + !!(lenx % bargs.u.pixel.celldimx);
int rows = leny / bargs.u.pixel.celldimy + !!(leny % bargs.u.pixel.celldimy);
if((bargs.u.pixel.spx = sprixel_alloc(ncdv, rows, cols)) == NULL){
ncvisual_destroy(ncv);
free_plane(ncdv);
return NULL;
}
}
if(ncvisual_blit(ncv, disprows, dispcols, ncdv, bset, leny, lenx, &bargs)){
ncvisual_destroy(ncv);

View File

@ -502,7 +502,7 @@ typedef struct {
int celldimx; // horizontal pixels per cell
int celldimy; // vertical pixels per cell
int colorregs; // number of color registers
int sprixelid; // unqie 24-bit id into sprixel cache
sprixel* spx; // sprixel object
} pixel; // for pixels
} u;
} blitterargs;
@ -811,9 +811,9 @@ int sprite_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
int kitty_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
int sixel_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
// dimy and dimx are cell geometry, not pixel. takes ownership of s on success.
sprixel* sprixel_create(ncplane* n, char* s, int bytes, int placey, int placex,
int sprixelid, int dimy, int dimx, int pixy, int pixx,
int parse_start);
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx);
int sprixel_load(sprixel* spx, char* s, int bytes, int placey, int placex,
int pixy, int pixx, int parse_start);
int sprite_wipe_cell(const notcurses* nc, sprixel* s, int y, int x);
int sixel_delete(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
@ -1216,14 +1216,13 @@ egc_rtl(const char* egc, int* bytes){
// a reference to the context-wide sprixel cache. this ought be an entirely
// new, purpose-specific plane.
static inline int
plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex,
int leny, int lenx, int sprixelid, int dimy, int dimx,
int parse_start, sprixcell_e * tacache){
sprixel* spx = sprixel_create(n, s, bytes, placey, placex, sprixelid,
leny, lenx, dimy, dimx, parse_start);
if(spx == NULL){
plane_blit_sixel(sprixel* spx, char* s, int bytes,
int placey, int placex, int leny, int lenx,
int parse_start, sprixcell_e* tacache){
if(sprixel_load(spx, s, bytes, placey, placex, leny, lenx, parse_start)){
return -1;
}
ncplane* n = spx->n;
uint32_t gcluster = htole(0x02000000ul) + htole(spx->id);
for(int y = placey ; y < placey + leny && y < ncplane_dim_y(n) ; ++y){
for(int x = placex ; x < placex + lenx && x < ncplane_dim_x(n) ; ++x){
@ -1232,13 +1231,12 @@ plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex,
c->width = lenx;
}
}
if(n->sprite){
sprixel_hide(n->sprite);
if(n){
n->tacache = tacache;
n->tacachey = leny;
n->tacachex = lenx;
n->sprite = spx;
}
n->tacache = tacache;
n->tacachey = leny;
n->tacachex = lenx;
n->sprite = spx;
return 0;
}

View File

@ -295,8 +295,8 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
// deflate-compressed) 24bit RGB. Returns -1 on error, 1 on success.
int kitty_blit(ncplane* n, int linesize, const void* data,
int leny, int lenx, const blitterargs* bargs){
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
int cols = bargs->u.pixel.spx->dimx;
int rows = bargs->u.pixel.spx->dimy;
char* buf = NULL;
size_t size = 0;
FILE* fp = open_memstream(&buf, &size);
@ -307,7 +307,6 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
bool reuse = false;
// if we have a sprixel attached to this plane, see if we can reuse it
// (we need the same dimensions) and thus immediately apply its T-A table.
int sprixelid;
if(n->tacache){
if(n->tacachey == rows && n->tacachex == cols){
tacache = n->tacache;
@ -324,11 +323,10 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
}
memset(tacache, 0, sizeof(*tacache) * rows * cols);
}
sprixelid = bargs->u.pixel.sprixelid;
// closes fp on all paths
if(write_kitty_data(fp, linesize, leny, lenx, cols, data,
bargs->u.pixel.celldimy, bargs->u.pixel.celldimx,
sprixelid, tacache, &parse_start)){
bargs->u.pixel.spx->id, tacache, &parse_start)){
if(!reuse){
free(tacache);
}
@ -336,9 +334,9 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
return -1;
}
// take ownership of |buf| and |tacache| on success
if(plane_blit_sixel(n, buf, size, bargs->placey, bargs->placex,
rows, cols, bargs->u.pixel.sprixelid, leny, lenx,
parse_start, tacache) < 0){
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size,
bargs->placey, bargs->placex,
leny, lenx, parse_start, tacache) < 0){
if(!reuse){
free(tacache);
}

View File

@ -1984,9 +1984,9 @@ void ncplane_yx(const ncplane* n, int* y, int* x){
}
void ncplane_erase(ncplane* n){
if(n->sprite){
/*if(n->sprite){
sprixel_hide(n->sprite);
}
}*/
// we must preserve the background, but a pure cell_duplicate() would be
// wiped out by the egcpool_dump(). do a duplication (to get the stylemask
// and channels), and then reload.

View File

@ -1085,16 +1085,19 @@ notcurses_rasterize_inner(notcurses* nc, const ncpile* p, FILE* out){
// we explicitly move the cursor at the beginning of each output line, so no
// need to home it expliticly.
update_palette(nc, out);
//fprintf(stderr, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->stdplane->absy, p->dimx + nc->stdplane->absx);
fprintf(stderr, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->stdplane->absy, p->dimx + nc->stdplane->absx);
if(clean_sprixels(nc, p, out) < 0){
return -1;
}
fprintf(stderr, "RASTERIZE CORE\n");
if(rasterize_core(nc, p, out)){
return -1;
}
fprintf(stderr, "RASTERIZE SPRIXELS\n");
if(rasterize_sprixels(nc, p, out) < 0){
return -1;
}
fprintf(stderr, "RASTERIZE CORE\n");
if(rasterize_core(nc, p, out)){
return -1;
}

View File

@ -386,7 +386,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab, int* parse_start){
// stacks. There is also a RLE component, handled in rasterization.
// A pixel block is indicated by setting cell_pixels_p().
static inline int
sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab,
sixel_blit_inner(int leny, int lenx, sixeltable* stab,
const blitterargs* bargs, sprixcell_e* tacache){
char* buf = NULL;
size_t size = 0;
@ -395,17 +395,15 @@ sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab,
return -1;
}
int parse_start = 0;
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
// calls fclose() on success
if(write_sixel_data(fp, lenx, stab, &parse_start)){
free(buf);
return -1;
}
// take ownership of buf on success
if(plane_blit_sixel(n, buf, size, bargs->placey, bargs->placex,
rows, cols, bargs->u.pixel.sprixelid, leny, lenx,
parse_start, tacache) < 0){
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size,
bargs->placey, bargs->placex,
leny, lenx, parse_start, tacache) < 0){
free(buf);
return -1;
}
@ -439,8 +437,8 @@ int sixel_blit(ncplane* n, int linesize, const void* data,
// stable.table doesn't need initializing; we start from the bottom
memset(stable.data, 0, sixelcount * colorregs);
memset(stable.deets, 0, sizeof(*stable.deets) * colorregs);
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
int cols = bargs->u.pixel.spx->dimx;
int rows = bargs->u.pixel.spx->dimy;
sprixcell_e* tacache = NULL;
bool reuse = false;
// if we have a sprixel attached to this plane, see if we can reuse it
@ -471,7 +469,7 @@ int sixel_blit(ncplane* n, int linesize, const void* data,
return -1;
}
refine_color_table(data, linesize, bargs->begy, bargs->begx, leny, lenx, &stable);
int r = sixel_blit_inner(n, leny, lenx, &stable, bargs, tacache);
int r = sixel_blit_inner(leny, lenx, &stable, bargs, tacache);
free(stable.data);
free(stable.deets);
free(stable.table);

View File

@ -1,5 +1,8 @@
#include "internal.h"
// FIXME needs be atomic
static uint32_t sprixelid_nonce;
void sprixel_free(sprixel* s){
if(s){
free(s->glyph);
@ -46,34 +49,42 @@ sprixel* sprixel_by_id(const notcurses* nc, uint32_t id){
return NULL;
}
// 'y' and 'x' are the cell geometry, not the pixel geometry. takes
// ownership of 's' on success.
sprixel* sprixel_create(ncplane* n, char* s, int bytes, int placey, int placex,
int sprixelid, int dimy, int dimx, int pixy, int pixx,
int parse_start){
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx){
sprixel* ret = malloc(sizeof(sprixel));
if(ret){
ret->glyph = s;
ret->glyphlen = bytes;
ret->invalidated = SPRIXEL_INVALIDATED;
fprintf(stderr, "LOADING UP %p with %p\n", ret, n);
memset(ret, 0, sizeof(*ret));
ret->n = n;
ret->dimy = dimy;
ret->dimx = dimx;
ret->pixx = pixx;
ret->pixy = pixy;
ret->y = placey;
ret->x = placex;
ret->parse_start = parse_start;
if(ncplane_pile(n)){
notcurses* nc = ncplane_notcurses(n);
ret->id = ++sprixelid_nonce;
//fprintf(stderr, "LOOKING AT %p (p->n = %p)\n", ret, ret->n);
if(ncplane_pile(ret->n)){
notcurses* nc = ncplane_notcurses(ret->n);
ret->next = nc->sprixelcache;
nc->sprixelcache = ret;
ret->id = sprixelid;
//fprintf(stderr, "%p %p %p\n", nc->sprixelcache, ret, nc->sprixelcache->next);
}
}
return ret;
}
// 'y' and 'x' are the cell geometry, not the pixel geometry. takes
// ownership of 's' on success.
int sprixel_load(sprixel* spx, char* s, int bytes, int placey, int placex,
int pixy, int pixx, int parse_start){
assert(spx->n);
spx->glyph = s;
spx->glyphlen = bytes;
spx->invalidated = SPRIXEL_INVALIDATED;
spx->pixx = pixx;
spx->pixy = pixy;
spx->y = placey;
spx->x = placex;
spx->parse_start = parse_start;
return 0;
}
int sprite_wipe_cell(const notcurses* nc, sprixel* s, int ycell, int xcell){
if(s->invalidated == SPRIXEL_HIDE){ // no need to do work if we're killing it
return 0;

View File

@ -12,6 +12,7 @@ extern "C" {
struct blitset;
struct ncplane;
struct sprixel;
struct ncvisual_details;
typedef struct ncvisual {
@ -21,6 +22,7 @@ typedef struct ncvisual {
// lines are sometimes padded. this many true bytes per row in data.
int rowstride;
bool owndata; // we own data iff owndata == true
struct sprixel* spx; // non-NULL if this is NCBLIT_PIXEL
} ncvisual;
static inline void

View File

@ -429,6 +429,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
int leny, int lenx, ncplane* n, ncscale_e scaling,
uint64_t flags){
int disprows, dispcols;
ncplane* createdn = NULL;
//fprintf(stderr, "INPUT N: %p\n", n);
if(n == NULL){ // create plane
if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
@ -462,6 +463,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
if((n = ncplane_create(notcurses_stdplane(nc), &nopts)) == NULL){
return NULL;
}
createdn = n;
placey = 0;
placex = 0;
}else{
@ -499,7 +501,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
bargs.placex = placex;
bargs.u.cell.blendcolors = flags & NCVISUAL_OPTION_BLEND;
if(ncvisual_blit(ncv, disprows, dispcols, n, bset, leny, lenx, &bargs)){
ncplane_destroy(n);
ncplane_destroy(createdn);
return NULL;
}
return n;
@ -524,6 +526,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
dispcols = ncv->cols;
disprows = ncv->rows;
}
ncplane* createdn = NULL;
//fprintf(stderr, "INPUT N: %p rows: %d cols: %d 0x%016lx\n", n ? n : NULL, disprows, dispcols, flags);
if(n == NULL){ // create plane
if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
@ -559,6 +562,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
}
placey = 0;
placex = 0;
createdn = n;
}else{
if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
ncplane_dim_yx(n, &disprows, &dispcols);
@ -598,12 +602,25 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
bargs.u.pixel.celldimx = nc->tcache.cellpixx;
bargs.u.pixel.celldimy = nc->tcache.cellpixy;
bargs.u.pixel.colorregs = nc->tcache.color_registers;
bargs.u.pixel.sprixelid = nc->tcache.sprixelnonce++;
if(ncv->spx == NULL){
int cols = dispcols / bargs.u.pixel.celldimx + !!(dispcols % bargs.u.pixel.celldimx);
int rows = disprows / bargs.u.pixel.celldimy + !!(disprows % bargs.u.pixel.celldimy);
if((ncv->spx = sprixel_alloc(n, rows, cols)) == NULL){
goto err;
}
}
bargs.u.pixel.spx = ncv->spx;
if(ncvisual_blit(ncv, disprows, dispcols, n, bset, disprows, dispcols, &bargs)){
ncplane_destroy(n);
return NULL;
goto err;
}
return n;
err:
if(ncv->spx){
sprixel_free(ncv->spx);
}
ncplane_destroy(createdn);
return NULL;
}
ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_options* vopts){