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