Hello, Applied, thanks!
Samuel Zhang Boyang, le mer. 08 juin 2022 17:09:29 +0900, a ecrit: > Hi, > > Changes in [PATCH v5]: > > Fix-incorrect-signal-handling.patch: > Fix compiler warnings about implicit declaration of bogl_signal(). > > Font-scaler.patch > Use a lookup table to speed up font scaling. > > ======= > > I'm sorry for sending a lot of emails to you, but I think this email is > probably the last one of this email series. :-) > > Best Regards, > Zhang Boyang > From 7d399b7223bc194c0b61aab8c6bd252fd0d43ded Mon Sep 17 00:00:00 2001 > From: Zhang Boyang <zhangboyang...@gmail.com> > Date: Tue, 24 May 2022 12:58:01 +0800 > Subject: [PATCH v5 2/4] Fix incorrect signal handling > > There are problems in signal handlers. Signal handlers must not call any > non-async-signal-safe functions, and they must save-restore errno if > errno is modified inside signal handlers. This patch fixes these > problems by deferring real tasks to main loop. This patch also > introduces bogl_signal(), which wraps around sigaction() thus signal > handlers can be installed in a portable way. Since signal related > problems are fixed, the previously temporarily disabled font unmapping > is now re-enabled. > --- > bogl.c | 50 +++++++++++++++++++++++++------------------------- > bogl.h | 2 ++ > boglP.h | 2 ++ > bterm.c | 36 ++++++++++++++++++++++++++---------- > 4 files changed, 55 insertions(+), 35 deletions(-) > > diff --git a/bogl.c b/bogl.c > index 6b9996b..86bc1e0 100644 > --- a/bogl.c > +++ b/bogl.c > @@ -65,6 +65,7 @@ > /* Global variables. */ > int bogl_xres, bogl_yres, bogl_bpp; /* bogl.h */ > int bogl_refresh; > +volatile int vt_switch_pending = 0; > volatile char *bogl_frame; /* boglP.h */ > int bogl_drawing; > int bogl_line_len; > @@ -120,7 +121,7 @@ static void draw_disable (void); > static void kbd_init (void); > static void kbd_done (void); > > -static void vt_switch (int); > +static void sigusr2 (int); > > static struct fb_fix_screeninfo fb_fix; > /* Initialize BOGL. */ > @@ -181,7 +182,7 @@ bogl_init (void) > mode.relsig = SIGUSR2; > mode.acqsig = SIGUSR2; > > - signal (SIGUSR2, vt_switch); > + bogl_signal (SIGUSR2, sigusr2); > > if (-1 == ioctl (tty, VT_SETMODE, &mode)) > return bogl_fail ("can't set VT mode: %s", strerror (errno)); > @@ -295,7 +296,7 @@ bogl_done (void) > > munmap ((void *) bogl_frame, fb_fix.smem_len); > > - signal (SIGUSR2, SIG_DFL); > + bogl_signal (SIGUSR2, SIG_DFL); > > ioctl (tty, KDSETMODE, KD_TEXT); > > @@ -583,32 +584,18 @@ draw_disable (void) > /* Signal handler called whenever the kernel wants to switch to or > from our tty. */ > static void > -vt_switch (int sig unused) > +sigusr2 (int sig unused) > { > - signal (SIGUSR2, vt_switch); > + vt_switch_pending = 1; > +} > +void > +vt_switch (void) > +{ > + vt_switch_pending = 0; > > - /* If a BOGL drawing function is in progress then we cannot mode > - switch right now because the drawing function would continue to > - scribble on the screen after the switch. So disable further > - drawing and schedule an alarm to try again in .1 second. */ > if (bogl_drawing) > { > - draw_disable (); > - > - signal (SIGALRM, vt_switch); > - > - { > - struct itimerval duration; > - > - duration.it_interval.tv_sec = 0; > - duration.it_interval.tv_usec = 0; > - duration.it_value.tv_sec = 0; > - duration.it_value.tv_usec = 100000; > - if (-1 == setitimer (ITIMER_REAL, &duration, NULL)) > - bogl_fail ("can't set timer: %s", strerror (errno)); > - } > - > - return; > + abort(); > } > > if (visible) > @@ -666,3 +653,16 @@ bogl_cloexec(int fd) > > return 0; > } > + > +/* Install signal handler in a portable way (i.e. sigaction wrapper) */ > +int > +bogl_signal(int signum, void (*handler) (int)) > +{ > + struct sigaction sa; > + > + sa.sa_handler = handler; > + sigemptyset (&sa.sa_mask); > + sa.sa_flags = SA_RESTART; > + > + return sigaction (signum, &sa, NULL); > +} > diff --git a/bogl.h b/bogl.h > index 3b2cb83..4d99788 100644 > --- a/bogl.h > +++ b/bogl.h > @@ -69,6 +69,8 @@ extern int bogl_xres, bogl_yres, bogl_ncols; > > /* 1=Must refresh screen due to tty change. */ > extern int bogl_refresh; > +extern volatile int vt_switch_pending; > +extern void vt_switch (void); > > /* Generic routines. */ > int bogl_init (void); > diff --git a/boglP.h b/boglP.h > index be99979..9a2b4aa 100644 > --- a/boglP.h > +++ b/boglP.h > @@ -27,4 +27,6 @@ int bogl_fail (const char *, ...); > > int bogl_cloexec (int fd); > > +int bogl_signal (int signum, void (*handler) (int)); > + > #endif /* boglP_h */ > diff --git a/bterm.c b/bterm.c > index dfae8b9..e86a748 100644 > --- a/bterm.c > +++ b/bterm.c > @@ -39,6 +39,7 @@ > #include <unistd.h> > > #include "bogl.h" > +#include "boglP.h" > #include "bogl-bgf.h" > #include "bogl-term.h" > > @@ -160,7 +161,6 @@ void sigchld(int sig) > quit_status = status; > quit = 1; > } > - signal(SIGCHLD, sigchld); > errno = errsv; > } > > @@ -176,7 +176,7 @@ void spawn_shell(int ptyfd, int ttyfd, char * const > *command_args) > child_pid = fork(); > if (child_pid) { > /* Change ownership and permissions of ttyfd device! */ > - signal(SIGCHLD, sigchld); > + bogl_signal(SIGCHLD, sigchld); > return; > } > > @@ -212,10 +212,16 @@ void set_window_size(int ttyfd, int x, int y) > > static char *font_name; > static struct bogl_term *term; > +static volatile int reload_font_pending = 0; > > -void reload_font(int sig) > +void sighup(int sig) > +{ > + reload_font_pending = 1; > +} > +void reload_font(void) > { > struct bogl_font *font; > + reload_font_pending = 0; > > font = bogl_mmap_font (font_name); > if (font == NULL) > @@ -224,14 +230,14 @@ void reload_font(int sig) > return; > } > > - /* BUG: Unmapping old font in this signal handler may cause crash if > - drawing is in progress, so disable this temporarily until we fix > - async-signal-safety problems completely. */ > - //bogl_munmap_font(term->font); > + bogl_munmap_font(term->font); > > term->font = font; > term->xstep = bogl_font_glyph(term->font, ' ', 0); > term->ystep = bogl_font_height(term->font); > + > + /* Request redraw */ > + bogl_refresh = 2; > } > > /* > @@ -243,6 +249,7 @@ int main(int argc, char *argv[]) > { > struct termios ntio; > int ret; > + int errsv; > char buf[8192]; > struct timeval tv; > int ptyfd, ttyfd; > @@ -342,8 +349,8 @@ int main(int argc, char *argv[]) > } > spawn_shell(ptyfd, ttyfd, command_args); > > - signal(SIGHUP, reload_font); > - signal(SIGTERM, sigterm); > + bogl_signal(SIGHUP, sighup); > + bogl_signal(SIGTERM, sigterm); > > ntio = ttysave; > ntio.c_lflag &= ~(ECHO|ISIG|ICANON|XCASE); > @@ -363,6 +370,10 @@ int main(int argc, char *argv[]) > > if (quit) > break; > + if (reload_font_pending) > + reload_font(); > + if (vt_switch_pending) > + vt_switch(); > > if(pending) > { > @@ -380,9 +391,14 @@ int main(int argc, char *argv[]) > if (ptyfd > max) > max = ptyfd; > ret = select(max+1, &fds, NULL, NULL, &tv); > + errsv = errno; > > if (quit) > break; > + if (reload_font_pending) > + reload_font(); > + if (vt_switch_pending) > + vt_switch(); > > if (bogl_refresh) { > /* Handle VT switching. */ > @@ -397,7 +413,7 @@ int main(int argc, char *argv[]) > bogl_refresh = 0; > bogl_term_redraw(term); > } > - if (ret == 0 || (ret < 0 && errno == EINTR)) > + if (ret == 0 || (ret < 0 && errsv == EINTR)) > { > if(pending) > { > -- > 2.30.2 > > From c190ef6d7afed6539ed4de0d9e61522a72251d05 Mon Sep 17 00:00:00 2001 > From: Zhang Boyang <zhangboyang...@gmail.com> > Date: Tue, 24 May 2022 23:49:31 +0800 > Subject: [PATCH v5 3/4] Font scaler > > Current fonts is too small to see on HiDPI displays. This patch > introduces a BGF font scaler, which can scale font glyphs on the fly > when loading. The scale factor can be automatically determined by screen > resolution or specified by a new command line argument '-s'. This patch > also adds support for BGF fonts wider than 32 pixels. > --- > bogl-bgf.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++--- > bogl-bgf.h | 2 +- > bogl-pcfb.c | 8 +-- > bogl-tcfb.c | 8 +-- > bogl-vga16.c | 33 ++++++++----- > bterm.1 | 4 ++ > bterm.c | 34 ++++++++++--- > 7 files changed, 191 insertions(+), 35 deletions(-) > > diff --git a/bogl-bgf.c b/bogl-bgf.c > index beed3c8..4cc36e2 100644 > --- a/bogl-bgf.c > +++ b/bogl-bgf.c > @@ -6,12 +6,23 @@ > #include <sys/types.h> > #include <unistd.h> > #include <stddef.h> > +#include <endian.h> > > #include "bogl.h" > #include "boglP.h" > #include "bogl-font.h" > #include "bogl-bgf.h" > > +/* Set font struct, let it point to font data in the given memory region */ > +static inline void set_font(struct bogl_font *font, void *mem) > +{ > + memcpy(font, mem + 4, sizeof(*font)); > + font->name = ((void *)font->name - (void *)0) + mem; > + font->offset = ((void *)font->offset - (void *)0) + mem; > + font->index = ((void *)font->index - (void *)0) + mem; > + font->content = ((void *)font->content - (void *)0) + mem; > +} > + > struct bogl_bgf { > void *f; /* mmap area */ > off_t size; /* size of mmap area */ > @@ -20,7 +31,122 @@ struct bogl_bgf { > #define bgf_of(font) \ > ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font))) > > -struct bogl_font *bogl_mmap_font(char *file) > +/* Scale the font (both width and height) > + Declare as inline function, will run faster if scale factor is constant */ > +static inline void __attribute__((always_inline)) > +bgf_scale_inline(struct bogl_bgf *bgf, int scale) > +{ > + u_int8_t *lut = NULL; > + const u_int32_t bo = be32toh(0x00010203); > + const u_int8_t b0 = bo >> 24, b1 = bo >> 16, b2 = bo >> 8, b3 = bo; > + void *new_f = MAP_FAILED; > + off_t new_size; > + struct bogl_font new_font; > + > + /* old_size*pow(scale,2) should enough and have some waste here */ > + new_size = bgf->size * scale * scale; > + > + /* Allocate new memory */ > + new_f = mmap(0, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | > MAP_ANONYMOUS, -1, 0); > + if (new_f == MAP_FAILED) { > + /* If memory allocation failed, skip scaling silently */ > + goto fail; > + } > + > + /* Copy old font data to new memory */ > + memcpy(new_f, bgf->f, bgf->size); > + > + /* Set font metadata */ > + struct bogl_font *font = &new_font; > + set_font(font, new_f); > + font->height = bgf->font.height * scale; > + > + /* Generate lookup table for scaling */ > + lut = calloc(0x100, scale); > + if (!lut) > + goto fail; > + for (int i = 0; i < 0x100; i++) > + for (int j = 0; j < 8 * scale; j++) > + lut[i * scale + j / 8] |= ((i >> (7 - j / scale % 8)) & 1) << (7 - j % > 8); > + > + /* Scale each glyph */ > + int mask = font->index_mask; > + for (int j = 0; j <= mask; j++) { > + for (int i = font->offset[j]; font->index[i]; i += 2) { > + int old_height = bgf->font.height; > + int old_width = (font->index[i] & mask); > + if (old_width * scale > mask) { > + /* Scaled glyph width can't fit in mask, fail */ > + goto fail; > + } > + font->index[i] = (font->index[i] & ~mask) | (old_width * scale); > + font->index[i + 1] *= scale * scale; > + u_int32_t *in_bitmap = &bgf->font.content[bgf->font.index[i + 1]]; > + int in_pitch = (old_width + 31) / 32; > + u_int32_t *out_bitmap = &font->content[font->index[i + 1]]; > + int out_pitch = (old_width * scale + 31) / 32; > + for (int y = 0; y < old_height; y++, in_bitmap += in_pitch) { > + u_int8_t *in_u8 = (u_int8_t *) in_bitmap; > + u_int8_t *out_u8 = (u_int8_t *) out_bitmap; > + /* If (in_pitch * scale) > out_pitch, this loop will overwrite next > + scanline a little bit. Fortunately, we reserved (in_pitch * > scale) > + for each scanline, and next scanline is not processed yet, so this > + will not cause memory errors or glyph corruption. */ > + for (int x = 0; x < in_pitch * 4; x += 4) { > + memcpy(&out_u8[(x + 0) * scale], &lut[in_u8[x + b0] * scale], > scale); > + memcpy(&out_u8[(x + 1) * scale], &lut[in_u8[x + b1] * scale], > scale); > + memcpy(&out_u8[(x + 2) * scale], &lut[in_u8[x + b2] * scale], > scale); > + memcpy(&out_u8[(x + 3) * scale], &lut[in_u8[x + b3] * scale], > scale); > + } > + for (int xx = 0; xx < out_pitch; xx++, out_bitmap++) > + *out_bitmap = be32toh(*out_bitmap); > + for (int yy = 1; yy < scale; yy++, out_bitmap += out_pitch) > + memcpy(out_bitmap, out_u8, sizeof(u_int32_t) * out_pitch); > + } > + } > + } > + > + /* Replace old font with new font */ > + munmap(bgf->f, bgf->size); > + bgf->f = new_f; > + bgf->size = new_size; > + bgf->font = new_font; > + free(lut); > + return; > +fail: > + if (new_f != MAP_FAILED) > + munmap(new_f, new_size); > +} > +static void __attribute__((noinline)) > +bgf_scale_noinline(struct bogl_bgf *bgf, int scale) > +{ > + bgf_scale_inline(bgf, scale); > +} > +static void __attribute__((noinline)) bgf_scale_2x(struct bogl_bgf *bgf) > +{ > + bgf_scale_inline(bgf, 2); > +} > +static void __attribute__((noinline)) bgf_scale_4x(struct bogl_bgf *bgf) > +{ > + bgf_scale_inline(bgf, 4); > +} > +static void __attribute__((noinline)) bgf_scale_8x(struct bogl_bgf *bgf) > +{ > + bgf_scale_inline(bgf, 8); > +} > +static void bgf_scale(struct bogl_bgf *bgf, int scale) > +{ > + switch (scale) { > + /* Use fast implementation if possible */ > + case 2: bgf_scale_2x(bgf); return; > + case 4: bgf_scale_4x(bgf); return; > + case 8: bgf_scale_8x(bgf); return; > + /* Universal implementation as fallback */ > + default: bgf_scale_noinline(bgf, scale); return; > + } > +} > + > +struct bogl_font *bogl_mmap_font(char *file, int scale) > { > struct bogl_bgf *bgf = NULL; > struct bogl_font *font = NULL; > @@ -55,11 +181,10 @@ struct bogl_font *bogl_mmap_font(char *file) > if (memcmp("BGF1", f, 4)) > goto fail; > > - memcpy(font, f + 4, sizeof(*font)); > - font->name = ((void *)font->name - (void *)0) + f; > - font->offset = ((void *)font->offset - (void *)0) + f; > - font->index = ((void *)font->index - (void *)0) + f; > - font->content = ((void *)font->content - (void *)0) + f; > + set_font(font, f); > + > + if (scale >= 2) > + bgf_scale(bgf, scale); > > done: > if (fd != -1) > diff --git a/bogl-bgf.h b/bogl-bgf.h > index f14a260..978da61 100644 > --- a/bogl-bgf.h > +++ b/bogl-bgf.h > @@ -1,3 +1,3 @@ > > -struct bogl_font *bogl_mmap_font(char *file); > +struct bogl_font *bogl_mmap_font(char *file, int scale); > void bogl_munmap_font(struct bogl_font *font); > diff --git a/bogl-pcfb.c b/bogl-pcfb.c > index c737d38..b16c804 100644 > --- a/bogl-pcfb.c > +++ b/bogl-pcfb.c > @@ -142,6 +142,7 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, int > fg, int bg, int ul, > > u_int32_t *character = NULL; > int w = bogl_font_glyph (font, wc, &character); > + int pitch = (w + 31) / 32; > > int x, y, h1 = ul ? h - 1 : h; > > @@ -153,16 +154,15 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, > int fg, int bg, int ul, > > for (y = 0; y < h1; y++) > { > - u_int32_t c = *character++; > + u_int32_t *c = character; > + character += pitch; > > for (x = 0; x < w; x++) > { > - if (c & 0x80000000) > + if ((c[x / 32] & (1 << (31 - x % 32)))) > put_var (dst, xx+x, cmap_lookup(fg), bpp); > else if (bg != -1) > put_var (dst, xx+x, cmap_lookup(bg), bpp); > - > - c <<= 1; > } > > dst += bogl_line_len; > diff --git a/bogl-tcfb.c b/bogl-tcfb.c > index 76f44da..5e14892 100644 > --- a/bogl-tcfb.c > +++ b/bogl-tcfb.c > @@ -169,6 +169,7 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, int > fg, int bg, int ul, > > u_int32_t *character = NULL; > int w = bogl_font_glyph (font, wc, &character); > + int pitch = (w + 31) / 32; > > int x, y, h1 = ul ? h - 1 : h; > unsigned cfg = cmap_lookup (fg), cbg = cmap_lookup (bg); > @@ -181,16 +182,15 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, > int fg, int bg, int ul, > > for (y = 0; y < h1; y++) > { > - u_int32_t c = *character++; > + u_int32_t *c = character; > + character += pitch; > > for (x = 0; x < w; x++) > { > - if (c & 0x80000000) > + if ((c[x / 32] & (1 << (31 - x % 32)))) > put_var (dst, xx+x, cfg, bpp); > else if (bg != -1) > put_var (dst, xx+x, cbg, bpp); > - > - c <<= 1; > } > > dst += bogl_line_len; > diff --git a/bogl-vga16.c b/bogl-vga16.c > index 6e7f0b0..3fcbe51 100644 > --- a/bogl-vga16.c > +++ b/bogl-vga16.c > @@ -394,25 +394,34 @@ bogl_vga16_text (int xx, int yy, const char *s, int n, > int fg, int bg, int ul, > { > u_int32_t *character = NULL; > int width = bogl_font_glyph (font, wc, &character); > + int pitch = (width + ul_bits - 1) / ul_bits; > > if (character == NULL) > continue; > > - for (y = 0; y < h; y++) > - bits[y] |= character[y] >> x; > - x += width; > - > - if (x >= (int) ul_bits) > - { > - plot (bg); > + int i, w; > + for (i = 0; i < pitch; i++) > + { > + w = width - i * ul_bits; > + if (w > ul_bits) > + w = ul_bits; > > - x -= ul_bits; > for (y = 0; y < h; y++) > - bits[y] = character[y] << (width - x); > + bits[y] |= character[y * pitch + i] >> x; > + x += w; > > - xx += ul_bits; > - if (xx >= bogl_xres) > - goto done; > + if (x >= (int) ul_bits) > + { > + plot (bg); > + > + x -= ul_bits; > + for (y = 0; y < h; y++) > + bits[y] = character[y * pitch + i] << (w - x - 1) << 1; > + > + xx += ul_bits; > + if (xx >= bogl_xres) > + goto done; > + } > } > } > plot (bg); > diff --git a/bterm.1 b/bterm.1 > index 8b96b99..e62d3ee 100644 > --- a/bterm.1 > +++ b/bterm.1 > @@ -21,6 +21,7 @@ bterm - framebuffer terminal emulator > .B bterm > .B -f > .RI font.bgf > +.RI "[-s " scale "]" > .RI "[-l " locale "]" > .RI "[" program "]" > .SH DESCRIPTION > @@ -36,6 +37,9 @@ Specify the font. BGF fonts are produced by > .BR bdftobogl (1) > from standard BDF font files. > .TP > +.B -s scale > +Specify the font scale factor, 0 for auto. > +.TP > .B -l locale > Specify a locale for > .B bterm > diff --git a/bterm.c b/bterm.c > index e86a748..b552b6e 100644 > --- a/bterm.c > +++ b/bterm.c > @@ -211,6 +211,7 @@ void set_window_size(int ttyfd, int x, int y) > } > > static char *font_name; > +static int font_scale; > static struct bogl_term *term; > static volatile int reload_font_pending = 0; > > @@ -223,7 +224,7 @@ void reload_font(void) > struct bogl_font *font; > reload_font_pending = 0; > > - font = bogl_mmap_font (font_name); > + font = bogl_mmap_font (font_name, font_scale); > if (font == NULL) > { > fprintf(stderr, "Bad font\n"); > @@ -242,7 +243,7 @@ void reload_font(void) > > /* > * The usage is very simple: > - * bterm -f font.bgf [ -l locale ] [ program ] > + * bterm -f font.bgf [ -s scale ] [ -l locale ] [ program ] > */ > > int main(int argc, char *argv[]) > @@ -266,6 +267,7 @@ int main(int argc, char *argv[]) > switch (argv[i][1]) > { > case 'f': > + case 's': > case 'l': > o = argv[i][1]; > break; > @@ -289,6 +291,11 @@ int main(int argc, char *argv[]) > o = ' '; > break; > > + case 's': > + font_scale = atoi(argv[i]); > + o = ' '; > + break; > + > case 'l': > locale = argv[i]; > o = ' '; > @@ -302,16 +309,11 @@ int main(int argc, char *argv[]) > setlocale(LC_CTYPE, locale); > > if (font_name == NULL) { > - fprintf(stderr, "Usage: %s -f font.bgf [ -l locale ] [ program ]\n", > argv[0]); > + fprintf(stderr, "Usage: %s -f font.bgf [ -s scale ] [ -l locale ] [ > program ]\n", argv[0]); > > return 1; > } > > - if ((font = bogl_mmap_font(font_name)) == NULL) { > - fprintf(stderr, "Bad font\n"); > - return 1; > - } > - > tcgetattr(0, &ttysave); > > if (!bogl_init()) { > @@ -319,6 +321,22 @@ int main(int argc, char *argv[]) > return 1; > } > > + if (font_scale == 0) { > + if (bogl_xres > 7680 && bogl_yres > 4320) > + font_scale = 8; > + else if (bogl_xres > 3840 && bogl_yres > 2160) > + font_scale = 4; > + else if (bogl_xres > 1920 && bogl_yres > 1080) > + font_scale = 2; > + else > + font_scale = 1; > + } > + > + if ((font = bogl_mmap_font(font_name, font_scale)) == NULL) { > + fprintf(stderr, "Bad font\n"); > + return 1; > + } > + > term = bogl_term_new(font); > if (!term) > exit(1); > -- > 2.30.2 > -- Samuel --- Pour une évaluation indépendante, transparente et rigoureuse ! Je soutiens la Commission d'Évaluation de l'Inria.