7fbcon_auxiliary_vector(
const sprixel* s){
8 int pixels = ncplane_pile(s->
n)->cellpxy * ncplane_pile(s->
n)->cellpxx;
9 uint8_t* ret = malloc(
sizeof(*ret) * pixels);
11 memset(ret, 0,
sizeof(*ret) * pixels);
17 uint8_t* auxvec = fbcon_auxiliary_vector(s);
21 const int cellpxy = ncplane_pile(s->
n)->cellpxy;
22 const int cellpxx = ncplane_pile(s->
n)->cellpxx;
24 for(
int y = 0 ;
y < cellpxy ; ++
y){
25 if(ycell * cellpxy +
y >= s->
pixy){
29 const size_t yoff = s->
pixx * (ycell * cellpxy +
y);
30 for(
int x = 0 ;
x < cellpxx ; ++
x){
31 if(xcell * cellpxx +
x >= s->
pixx){
34 size_t offset = (yoff + xcell * cellpxx +
x) * 4;
35 const int vyx = (
y % cellpxy) * cellpxx +
x;
36 auxvec[vyx] = glyph[offset + 3];
37 glyph[offset + 3] = 0;
45 int leny,
int lenx,
const struct blitterargs* bargs){
51 size_t flen = leny * lenx * 4;
52 if(fbuf_reserve(&s->
glyph, flen)){
55 for(
int l = 0 ; l < leny ; ++l){
56 int ycell = l / cdimy;
57 size_t soffset = l * linesize;
58 const uint8_t* src = (
const unsigned char*)data + soffset;
59 size_t toffset = l * lenx * 4;
60 char* dst = (
char *)s->
glyph.
buf + toffset;
61 for(
int c = 0 ;
c < lenx ; ++
c){
62 int xcell =
c / cdimx;
65 if(rgba_trans_p(*(uint32_t*)src, transcolor)){
66 ncpixel_set_a((uint32_t*)src, 0);
67 if(
c % cdimx == 0 && l % cdimy == 0){
74 const int vyx = (l % cdimy) * cdimx + (
c % cdimx);
75 ((uint8_t*)
n->tam[tyx].auxvector)[vyx] = src[3];
77 if(rgba_trans_p(*(uint32_t*)src, transcolor)){
78 ncpixel_set_a((uint32_t*)src, 0);
79 if(
c % cdimx == 0 && l % cdimy == 0){
86 if(
c % cdimx == 0 && l % cdimy == 0){
91 memcpy(dst + 3, src + 3, 1);
94 memcpy(dst, src + 2, 1);
95 memcpy(dst + 1, src + 1, 1);
96 memcpy(dst + 2, src, 1);
101 scrub_tam_boundaries(
n->tam, leny, lenx, cdimy, cdimx);
108 fbuf_free(&s->
glyph);
118#include <sys/types.h>
123#include <sys/ioctl.h>
129 const int cellpxy = ncplane_pile(s->
n)->cellpxy;
130 const int cellpxx = ncplane_pile(s->
n)->cellpxx;
132 for(
int y = 0 ;
y < cellpxy ; ++
y){
133 if(ycell * cellpxy +
y >= s->
pixy){
136 const size_t yoff = s->
pixx * (ycell * cellpxy +
y);
137 for(
int x = 0 ;
x < cellpxx ; ++
x){
138 if(xcell * cellpxx +
x >= s->
pixx){
141 size_t offset = (yoff + xcell * cellpxx +
x) * 4;
142 const int vyx = (
y % cellpxy) * cellpxx +
x;
143 if(
x == 0 &&
y == 0){
144 if(auxvec[vyx] == 0){
156 s->
glyph.
buf[offset + 3] = auxvec[vyx];
167 const int cellpxy = ncplane_pile(s->
n) ? ncplane_pile(s->
n)->cellpxy : ti->
cellpxy;
168 const int cellpxx = ncplane_pile(s->
n) ? ncplane_pile(s->
n)->cellpxx : ti->
cellpxx;
169 for(
unsigned l = 0 ; l < (unsigned)s->
pixy && l +
y * cellpxy < ti->pixy ; ++l){
171 size_t offset = ((l +
y * cellpxy) * ti->
pixx +
x * cellpxx) * 4;
172 uint8_t* tl = ti->linux_fbuffer + offset;
173 const char* src = (
char*)s->
glyph.
buf + (l * s->
pixx * 4);
174 for(
unsigned c = 0 ;
c < (unsigned)s->
pixx && c < ti->pixx ; ++
c){
176 memcpy(&pixel, src, 4);
177 if(!rgba_trans_p(pixel, 0)){
178 memcpy(tl, &pixel, 4);
195 const int cellpxy = p->
cellpxy;
196 const int cellpxx = p->
cellpxx;
201 const int rowbytes = cellpxx * p->
dimx * 4;
202 const int totalrows = cellpxy * p->
dimy;
203 int srows = rows * cellpxy;
204 if(srows > totalrows){
208 uint8_t* targ = ti->linux_fbuffer;
209 uint8_t* src = ti->linux_fbuffer + srows * rowbytes;
210 unsigned tocopy = rowbytes * (totalrows - srows);
212 memmove(targ, src, tocopy);
215 memset(targ, 0, (totalrows * rowbytes) - tocopy);
220row_bytes(
const struct console_font_op* cfo){
221 return (cfo->width + 7) / 8;
225glyph_bytes(
const struct console_font_op* cfo){
226 size_t minb = row_bytes(cfo) * cfo->height;
227 return (minb + 31) / 32 * 32;
231get_glyph(
struct console_font_op* cfo,
unsigned idx){
232 if(
idx >= cfo->charcount){
235 return (
unsigned char*)cfo->data + glyph_bytes(cfo) *
idx;
244shim_quad_block(
struct console_font_op* cfo,
unsigned idx,
unsigned qbits){
245 unsigned char* glyph = get_glyph(cfo,
idx);
250 for(
r = 0 ;
r < cfo->height / 2 ; ++
r){
251 unsigned char mask = 0x80;
252 unsigned char* row = glyph + row_bytes(cfo) *
r;
255 for(
x = 0 ;
x < cfo->width / 2 ; ++
x){
259 if((mask >>= 1) == 0){
264 while(x < cfo->width){
268 if((mask >>= 1) == 0){
275 while(r < cfo->height){
276 unsigned char mask = 0x80;
277 unsigned char* row = glyph + row_bytes(cfo) *
r;
280 for(
x = 0 ;
x < cfo->width / 2 ; ++
x){
284 if((mask >>= 1) == 0){
289 while(x < cfo->width){
293 if((mask >>= 1) == 0){
306shim_lower_eighths(
struct console_font_op* cfo,
unsigned idx,
int eighths){
307 unsigned char* glyph = get_glyph(cfo,
idx);
311 unsigned ten8ths = cfo->height * 10 / 8;
312 unsigned start = cfo->height - (eighths * ten8ths / 10);
314 for(
r = 0 ;
r < start ; ++
r){
315 unsigned char* row = glyph + row_bytes(cfo) *
r;
316 for(
unsigned x = 0 ;
x < cfo->width ;
x += 8){
320 while(r < cfo->height){
321 unsigned char* row = glyph + row_bytes(cfo) *
r;
322 for(
unsigned x = 0 ;
x < cfo->width ;
x += 8){
332add_to_map(
struct unimapdesc* map,
wchar_t w,
unsigned fidx){
333 logdebug(
"adding mapping U+%04x -> %03u", w, fidx);
334 struct unipair* tmp = realloc(map->entries,
sizeof(*map->entries) * (map->entry_ct + 1));
339 map->entries[map->entry_ct].unicode = w;
340 map->entries[map->entry_ct].fontpos = fidx;
346program_line_drawing_chars(
int fd,
struct unimapdesc* map){
367 .ws = L
"─━┄┅┈┉╌╍═╼╾",
369 .ws = L
"│┃┆┇┊┋╎╏║╽╿",
371 .ws = L
"├┝┞┟┠┡┢┣╞╟╠",
373 .ws = L
"┤┥┦┧┨┩┪┫╡╢╣",
375 .ws = L
"┬┭┮┯┰┱┲┳╤╥╦",
377 .ws = L
"┴┵┶┷┸┹┺┻╧╨╩",
379 .ws = L
"┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╪╫╬",
383 for(
size_t sidx = 0 ; sidx <
sizeof(sets) /
sizeof(*sets) ; ++sidx){
385 struct simset* s = &sets[sidx];
386 size_t fsize =
sizeof(bool) * wcslen(s->ws);
387 bool* found = malloc(fsize);
388 memset(found, 0, fsize);
389 for(
unsigned idx = 0 ;
idx < map->entry_ct ; ++
idx){
390 for(
size_t widx = 0 ; widx < wcslen(s->ws) ; ++widx){
391 if(map->entries[
idx].unicode == s->ws[widx]){
392 logtrace(
"found desired character U+%04x -> %03u",
393 map->entries[
idx].unicode, map->entries[
idx].fontpos);
396 fontidx = map->entries[
idx].fontpos;
402 for(
size_t widx = 0 ; widx < wcslen(s->ws) ; ++widx){
404 if(add_to_map(map, s->ws[widx], fontidx)){
412 logwarn(
"couldn't find any glyphs for set %zu", sidx);
419 if(ioctl(fd, PIO_UNIMAP, map)){
420 logwarn(
"error setting kernel unicode map (%s)", strerror(errno));
423 loginfo(
"added %d kernel unicode mapping%s",
424 toadd, toadd == 1 ?
"" :
"s");
429struct framebuffer_copy {
432 unsigned pixely, pixelx;
438copy_and_close_linux_fb(
tinfo* ti,
struct framebuffer_copy* fbdup){
439 if((fbdup->map = memdup(ti->linux_fbuffer, ti->linux_fb_len)) ==
NULL){
442 munmap(ti->linux_fbuffer, ti->linux_fb_len);
443 fbdup->maplen = ti->linux_fb_len;
444 ti->linux_fbuffer =
NULL;
445 ti->linux_fb_len = 0;
446 fbdup->pixely = ti->
pixy;
447 fbdup->pixelx = ti->
pixx;
452kill_fbcopy(
struct framebuffer_copy* fbdup){
457program_block_drawing_chars(
tinfo* ti,
int fd,
struct console_font_op* cfo,
458 struct unimapdesc* map,
unsigned no_font_changes,
459 bool* halfblocks,
bool* quadrants){
465 struct shimmer half[] = {
466 { .qbits = 0xc, .w = L
'▀', .found =
false, },
467 { .qbits = 0x3, .w = L
'▄', .found =
false, },
469 struct shimmer quads[] = {
471 { .qbits = 0xa, .w = L
'▌', .found =
false, },
472 { .qbits = 0x5, .w = L
'▐', .found =
false, },
473 { .qbits = 0x8, .w = L
'▘', .found =
false, },
474 { .qbits = 0x4, .w = L
'▝', .found =
false, },
475 { .qbits = 0x2, .w = L
'▖', .found =
false, },
476 { .qbits = 0x1, .w = L
'▗', .found =
false, },
477 { .qbits = 0x7, .w = L
'▟', .found =
false, },
478 { .qbits = 0xb, .w = L
'▙', .found =
false, },
479 { .qbits = 0xd, .w = L
'▜', .found =
false, },
480 { .qbits = 0xe, .w = L
'▛', .found =
false, },
481 { .qbits = 0x9, .w = L
'▚', .found =
false, },
482 { .qbits = 0x6, .w = L
'▞', .found =
false, },
484 struct shimmer eighths[] = {
485 { .qbits = 7, .w = L
'▇', .found =
false, },
486 { .qbits = 6, .w = L
'▆', .found =
false, },
487 { .qbits = 5, .w = L
'▅', .found =
false, },
488 { .qbits = 3, .w = L
'▃', .found =
false, },
489 { .qbits = 2, .w = L
'▂', .found =
false, },
490 { .qbits = 1, .w = L
'▁', .found =
false, },
494 size_t halvesfound = 0;
495 for(
unsigned i = 0 ; i < cfo->charcount ; ++i){
496 if(map->entries[i].unicode >= 0x2580 && map->entries[i].unicode <= 0x259f){
497 for(
size_t s = 0 ; s <
sizeof(half) /
sizeof(*half) ; ++s){
498 if(map->entries[i].unicode == half[s].w){
499 logdebug(
"found %lc at fontidx %u", half[s].w, i);
500 half[s].found =
true;
505 for(
size_t s = 0 ; s <
sizeof(quads) /
sizeof(*quads) ; ++s){
506 if(map->entries[i].unicode == quads[s].w){
507 logdebug(
"found %lc at fontidx %u", quads[s].w, i);
508 quads[s].found =
true;
513 for(
size_t s = 0 ; s <
sizeof(eighths) /
sizeof(*eighths) ; ++s){
514 if(map->entries[i].unicode == eighths[s].w){
515 logdebug(
"found %lc at fontidx %u", eighths[s].w, i);
516 eighths[s].found =
true;
523 if(halvesfound ==
sizeof(half) /
sizeof(*half)){
526 if(numfound + halvesfound == (
sizeof(half) +
sizeof(quads) +
sizeof(eighths)) /
sizeof(*quads)){
527 logdebug(
"all %zu desired glyphs were already present", numfound);
532 logdebug(
"not reprogramming kernel font per request");
537 unsigned candidate = cfo->charcount;
539 for(
size_t s = 0 ; s <
sizeof(half) /
sizeof(*half) ; ++s){
542 if(map->entries[candidate].unicode < 0x2580 || map->entries[candidate].unicode > 0x259f){
547 logwarn(
"ran out of replaceable glyphs for U+%04lx", (
long)half[s].w);
551 if(shim_quad_block(cfo, candidate, half[s].qbits)){
552 logwarn(
"error replacing glyph for U+%04lx at %u", (
long)half[s].w, candidate);
555 if(add_to_map(map, half[s].w, candidate)){
561 for(
size_t s = 0 ; s <
sizeof(quads) /
sizeof(*quads) ; ++s){
564 if(map->entries[candidate].unicode < 0x2580 || map->entries[candidate].unicode > 0x259f){
569 logwarn(
"ran out of replaceable glyphs for U+%04lx", (
long)quads[s].w);
573 if(shim_quad_block(cfo, candidate, quads[s].qbits)){
574 logwarn(
"error replacing glyph for U+%04lx at %u", (
long)quads[s].w, candidate);
577 if(add_to_map(map, quads[s].w, candidate)){
583 for(
size_t s = 0 ; s <
sizeof(eighths) /
sizeof(*eighths) ; ++s){
584 if(!eighths[s].found){
586 if(map->entries[candidate].unicode < 0x2580 || map->entries[candidate].unicode > 0x259f){
591 logwarn(
"ran out of replaceable glyphs for U+%04lx", (
long)eighths[s].w);
594 if(shim_lower_eighths(cfo, candidate, eighths[s].qbits)){
595 logwarn(
"error replacing glyph for U+%04lx at %u", (
long)eighths[s].w, candidate);
598 if(add_to_map(map, eighths[s].w, candidate)){
604 if(halvesadded == 0 && added == 0){
605 loginfo(
"didn't replace any glyphs, not calling ioctl");
608 struct framebuffer_copy fbdup;
609 if(copy_and_close_linux_fb(ti, &fbdup)){
612 cfo->op = KD_FONT_OP_SET;
613 if(ioctl(fd, KDFONTOP, cfo)){
614 logwarn(
"error programming kernel font (%s)", strerror(errno));
618 if(ioctl(fd, PIO_UNIMAP, map)){
619 logwarn(
"error setting kernel unicode map (%s)", strerror(errno));
623 if(halvesadded + halvesfound ==
sizeof(half) /
sizeof(*half)){
626 if(added + numfound == (
sizeof(quads) +
sizeof(eighths)) /
sizeof(*quads)){
629 added += halvesadded;
630 loginfo(
"successfully added %d kernel font glyph%s via %d", added, added == 1 ?
"" :
"s", ti->linux_fb_fd);
631 if(ti->linux_fb_fd < 0){
635 unsigned pixely, pixelx;
640 if(pixely != fbdup.pixely || pixelx != fbdup.pixelx || ti->linux_fb_len != fbdup.maplen){
641 logwarn(
"framebuffer changed size, not reblitting");
643 memcpy(ti->linux_fbuffer, fbdup.map, fbdup.maplen);
650reprogram_linux_font(
tinfo* ti,
int fd,
struct console_font_op* cfo,
651 struct unimapdesc* map,
unsigned no_font_changes,
652 bool* halfblocks,
bool* quadrants){
653 if(ioctl(fd, KDFONTOP, cfo)){
654 logwarn(
"error reading Linux kernelfont (%s)", strerror(errno));
657 loginfo(
"kernel font size (glyphcount): %u", cfo->charcount);
658 loginfo(
"kernel font character geometry: %ux%u", cfo->width, cfo->height);
659 if(cfo->charcount > 512){
660 logwarn(
"warning: kernel returned excess charcount");
663 if(ioctl(fd, GIO_UNIMAP, map)){
664 logwarn(
"error reading Linux unimap (%s)", strerror(errno));
667 loginfo(
"kernel unimap size: %u/%u", map->entry_ct, USHRT_MAX);
671 if(!no_font_changes){
672 if(program_line_drawing_chars(fd, map)){
676 if(program_block_drawing_chars(ti, fd, cfo, map, no_font_changes,
677 halfblocks, quadrants)){
684 bool* halfblocks,
bool* quadrants){
685 struct console_font_op cfo = {
686 .op = KD_FONT_OP_GET,
691 size_t totsize = 128 * cfo.charcount;
692 cfo.data = malloc(totsize);
693 if(cfo.data ==
NULL){
694 logwarn(
"error acquiring %zub for font descriptors (%s)", totsize, strerror(errno));
697 struct unimapdesc map = {0};
698 map.entry_ct = USHRT_MAX;
699 totsize = map.entry_ct *
sizeof(
struct unipair);
700 map.entries = malloc(totsize);
701 if(map.entries ==
NULL){
702 logwarn(
"error acquiring %zub for Unicode font map (%s)", totsize, strerror(errno));
706 int r = reprogram_linux_font(ti, ti->
ttyfd, &cfo, &map, no_font_changes,
707 halfblocks, quadrants);
721 if(ioctl(fd, KDGETMODE, &mode)){
722 logdebug(
"not a Linux console (no KDGETMODE)");
725 loginfo(
"verified Linux console, mode %d", mode);
730 unsigned fakey, fakex;
737 struct fb_var_screeninfo fbi = {0};
738 if(ioctl(ti->linux_fb_fd, FBIOGET_VSCREENINFO, &fbi)){
739 logerror(
"no framebuffer info from %s %d (%s?)", ti->linux_fb_dev,
740 ti->linux_fb_fd, strerror(errno));
743 loginfo(
"linux %s geometry: %dx%d", ti->linux_fb_dev, fbi.yres, fbi.xres);
746 size_t len = *ypix * *xpix * fbi.bits_per_pixel / 8;
747 if(ti->linux_fb_len !=
len){
748 if(ti->linux_fbuffer != MAP_FAILED){
749 munmap(ti->linux_fbuffer, ti->linux_fb_len);
750 ti->linux_fbuffer = MAP_FAILED;
751 ti->linux_fb_len = 0;
753 ti->linux_fbuffer = mmap(
NULL,
len, PROT_READ|PROT_WRITE,
754 MAP_SHARED, ti->linux_fb_fd, 0);
755 if(ti->linux_fbuffer == MAP_FAILED){
756 logerror(
"couldn't map %zuB on %s (%s?)",
len, ti->linux_fb_dev, strerror(errno));
759 ti->linux_fb_len =
len;
760 loginfo(
"mapped %zuB on %s",
len, ti->linux_fb_dev);
768 const char* dev =
"/dev/fb0";
769 loginfo(
"checking for Linux framebuffer at %s", dev);
770 int fd = open(dev, O_RDWR | O_CLOEXEC);
772 logdebug(
"couldn't open framebuffer device %s", dev);
775 ti->linux_fb_fd = fd;
776 if((ti->linux_fb_dev = strdup(dev)) ==
NULL){
777 close(ti->linux_fb_fd);
778 ti->linux_fb_fd = -1;
783 ti->linux_fb_fd = -1;
784 free(ti->linux_fb_dev);
785 ti->linux_fb_dev =
NULL;
int fbcon_scrub(const struct ncpile *p, sprixel *s)
int fbcon_draw(const tinfo *ti, sprixel *s, int y, int x)
int get_linux_fb_pixelgeom(tinfo *ti, unsigned *ypix, unsigned *xpix)
int fbcon_blit(struct ncplane *n, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
void fbcon_scroll(const struct ncpile *p, tinfo *ti, int rows)
int fbcon_wipe(sprixel *s, int ycell, int xcell)
int fbcon_rebuild(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
bool is_linux_console(int fd)
bool is_linux_framebuffer(struct tinfo *ti)
int reprogram_console_font(struct tinfo *ti, unsigned no_font_changes, bool *halfblocks, bool *quadrants)
#define logerror(fmt,...)
#define logtrace(fmt,...)
#define logdebug(fmt,...)
API int API int const nccell unsigned len
int sixel_scrub(const ncpile *p, sprixel *s)
@ SPRIXCELL_ANNIHILATED_TRANS
struct blitterargs::@3::@5 pixel