:: commit f4dc6481f13da51f056bb16c7b656dd5c80aee65

mintsuki <mintsuki@protonmail.com> — 2021-07-11 02:50

parents: 9423860745

gterm: Revert recent changes as they make the terminal significantly slower on real hardware

diff --git a/stage23/lib/bmp.c b/stage23/lib/bmp.c
index a299caac..fb90149a 100644
--- a/stage23/lib/bmp.c
+++ b/stage23/lib/bmp.c
@@ -29,9 +29,44 @@ struct bmp_header {
 } __attribute__((packed));
 
 struct bmp_local {
+    uint8_t  *image;
+    uint32_t  pitch;
     struct bmp_header header;
 };
 
+static uint32_t get_pixel(struct image *this, int x, int y) {
+    struct bmp_local *local = this->local;
+    struct bmp_header *header = &local->header;
+
+    switch (this->type) {
+        case IMAGE_TILED: {
+            x %= header->bi_width;
+            y %= header->bi_height;
+            break;
+        }
+        case IMAGE_CENTERED: {
+            x -= this->x_displacement;
+            y -= this->y_displacement;
+            if (x < 0 || y < 0 || x >= this->x_size || y >= this->y_size)
+                return this->back_colour;
+            break;
+        }
+        case IMAGE_STRETCHED: {
+            x = (x * this->old_x_size) / this->x_size;
+            y = (y * this->old_y_size) / this->y_size;
+            break;
+        }
+    }
+
+    size_t pixel_offset = local->pitch * (header->bi_height - y - 1) + x * (header->bi_bpp / 8);
+
+    // TODO: Perhaps use masks here, they're there for a reason
+    uint32_t composite = 0;
+    for (int i = 0; i < header->bi_bpp / 8; i++)
+        composite |= (uint32_t)local->image[pixel_offset + i] << (i * 8);
+
+    return composite;
+}
 
 int bmp_open_image(struct image *image, struct file_handle *file) {
     struct bmp_header header;
@@ -40,22 +75,22 @@ int bmp_open_image(struct image *image, struct file_handle *file) {
     if (memcmp(&header.bf_signature, "BM", 2) != 0)
         return -1;
 
-    if ((header.bi_bpp < 8) | ((header.bi_bpp % 8) != 0))
+    // We don't support bpp lower than 8
+    if (header.bi_bpp < 8)
         return -1;
 
     struct bmp_local *local = ext_mem_alloc(sizeof(struct bmp_local));
 
-    image->img = ext_mem_alloc(header.bf_size);
-    fread(file, image->img, header.bf_offset, header.bf_size);
+    local->image = ext_mem_alloc(header.bf_size);
+    fread(file, local->image, header.bf_offset, header.bf_size);
 
+    local->pitch  = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8;
     local->header = header;
 
-    image->x_size     = header.bi_width;
-    image->y_size     = header.bi_height;
-    image->pitch      = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8;
-    image->local      = local;
-    image->bpp        = header.bi_bpp;
-    image->img_width  = header.bi_width;
-    image->img_height = header.bi_height;
+    image->x_size    = header.bi_width;
+    image->y_size    = header.bi_height;
+    image->get_pixel = get_pixel;
+    image->local     = local;
+
     return 0;
 }
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index 3feb3472..a8788b33 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -74,7 +74,17 @@ void gterm_plot_px(int x, int y, uint32_t hex) {
     gterm_framebuffer[fb_i] = hex;
 }
 
-static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t hex) {
+static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
+    if (x >= frame_width  && x < frame_width  + VGA_FONT_WIDTH  * cols
+     && y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) {
+        return colour_blend(hex, background->get_pixel(background, x, y));
+    }
+
+    uint32_t bg_px = background->get_pixel(background, x, y);
+
+    if (margin_gradient == 0)
+        return bg_px;
+
     int distance, x_distance, y_distance;
 
     if (x < frame_width)
@@ -105,100 +115,14 @@ static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t h
     return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
 }
 
-typedef int fixedp6; // the last 6 bits are the fixed point part
-static int fixedp6_to_int(fixedp6 value) { return value / 64; }
-static fixedp6 int_to_fixedp6(int value) { return value * 64; }
-
-// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel
-__attribute__((always_inline)) static inline void genloop(int xstart, int xend, int ystart, int yend, uint32_t (*blend)(int x, int y, uint32_t orig)) {
-    uint8_t *img = background->img;
-    const int img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8;
-
-    switch (background->type) {
-    case IMAGE_TILED:
-        for (int y = ystart; y < yend; y++) {
-            int image_y = y % img_height, image_x = xstart % img_width;
-            const size_t off = img_pitch * (img_height - 1 - image_y);
-            int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
-            for (int x = xstart; x < xend; x++) {
-                uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
-                uint32_t i = blend(x, y, img_pixel);
-                bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
-                if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive
-            }
-        }
-        break;
-
-    case IMAGE_CENTERED:
-        for (int y = ystart; y < yend; y++) {
-            int image_y = y - background->y_displacement;
-            const size_t off = img_pitch * (img_height - 1 - image_y);
-            int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
-            if ((image_y < 0) || (image_y >= background->y_size)) { /* external part */
-                for (int x = xstart; x < xend; x++) {
-                    uint32_t i = blend(x, y, background->back_colour);
-                    bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
-                }
-            }
-            else { /* internal part */
-                for (int x = xstart; x < xend; x++) {
-                    int image_x = (x - background->x_displacement);
-                    bool x_external = (image_x < 0) || (image_x >= background->x_size);
-                    uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
-                    uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel);
-                    bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
-                }
-            }
-        }
-        break;
-    // For every pixel, ratio = img_width / gterm_width, img_x = x * ratio, x = (xstart + i)
-    // hence x = xstart * ratio + i * ratio
-    // so you can set x = xstart * ratio, and increment by ratio at each iteration
-    case IMAGE_STRETCHED:
-        for (int y = ystart; y < yend; y++) {
-            int img_y = (y * img_height) / gterm_height; // calculate Y with full precision
-            int off = img_pitch * (img_height - 1 - img_y);
-            int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
-
-            size_t ratio = int_to_fixedp6(img_width) / gterm_width;
-            fixedp6 img_x = ratio * xstart;
-            for (int x = xstart; x < xend; x++) {
-                uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off);
-                uint32_t i = blend(x, y, img_pixel);
-                bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
-                img_x += ratio;
-            }
-        }
-        break;
-    }
-}
-static uint32_t blend_external(int x, int y, uint32_t orig) { (void)x; (void)y; return orig; }
-static uint32_t blend_internal(int x, int y, uint32_t orig) { (void)x; (void)y; return colour_blend(ansi_colours[8], orig); }
-static uint32_t blend_margin(int x, int y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, ansi_colours[8]); }
-
-static void loop_external(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_external); }
-static void loop_margin(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_margin); }
-static void loop_internal(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_internal); }
-
 void gterm_generate_canvas(void) {
     if (background) {
-        const int frame_height_end = frame_height + VGA_FONT_HEIGHT * rows, frame_width_end = frame_width + VGA_FONT_WIDTH * cols;
-        const int fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient,
-            fwidth = frame_width - margin_gradient, fwidth_end = frame_width_end + margin_gradient;
-
-        loop_external(0, gterm_width, 0, fheight);
-        loop_external(0, gterm_width, fheight_end, gterm_height);
-        loop_external(0, fwidth, fheight, fheight_end);
-        loop_external(fwidth_end, gterm_width, fheight, fheight_end);
-
-        if (margin_gradient) {
-            loop_margin(fwidth, fwidth_end, fheight, frame_height);
-            loop_margin(fwidth, fwidth_end, frame_height_end, fheight_end);
-            loop_margin(fwidth, frame_width, frame_height, frame_height_end);
-            loop_margin(frame_width_end, fwidth_end, frame_height, frame_height_end);
+        for (int y = 0; y < gterm_height; y++) {
+            for (int x = 0; x < gterm_width; x++) {
+                bg_canvas[y * gterm_width + x] = blend_gradient_from_box(x, y, ansi_colours[8]);
+                gterm_plot_px(x, y, bg_canvas[y * gterm_width + x]);
+            }
         }
-
-        loop_internal(frame_width, frame_width_end, frame_height, frame_height_end);
     } else {
         for (int y = 0; y < gterm_height; y++) {
             for (int x = 0; x < gterm_width; x++) {
@@ -208,7 +132,6 @@ void gterm_generate_canvas(void) {
         }
     }
 }
-#undef genloop
 
 struct gterm_char {
     uint32_t c;
@@ -216,30 +139,74 @@ struct gterm_char {
     int bg;
 };
 
+static void plot_char_mem(uint32_t *buf, struct gterm_char *c, int x, int y) {
+    uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT];
+
+    for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+        for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+            if ((glyph[i] & (0x80 >> j))) {
+                buf[i * VGA_FONT_WIDTH + j] = ansi_colours[c->fg];
+            } else {
+                if (c->bg == 8)
+                    buf[i * VGA_FONT_WIDTH + j] = bg_canvas[(y + i) * gterm_width + (x + j)];
+                else
+                    buf[i * VGA_FONT_WIDTH + j] = ansi_colours[c->bg];
+            }
+        }
+    }
+}
+
 void gterm_plot_char(struct gterm_char *c, int x, int y) {
     uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT];
 
     for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
-        uint32_t *line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4), *canvas_line = bg_canvas + x + (y + i) * gterm_width;
         for (int j = 0; j < VGA_FONT_WIDTH; j++) {
             if ((glyph[i] & (0x80 >> j))) {
-                line[j] = ansi_colours[c->fg];
+                gterm_plot_px(x + j, y + i, ansi_colours[c->fg]);
             } else {
                 if (c->bg == 8)
-                    line[j] = canvas_line[j];
+                    gterm_plot_px(x + j, y + i, bg_canvas[(y + i) * gterm_width + (x + j)]);
                 else
-                    line[j] = ansi_colours[c->bg];
+                    gterm_plot_px(x + j, y + i, ansi_colours[c->bg]);
             }
         }
     }
 }
 
 static void plot_char_grid_force(struct gterm_char *c, int x, int y) {
-    gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT);
+    uint32_t new_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT];
+    plot_char_mem(new_char, c,
+                  x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height);
+
+    for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+        for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+            gterm_plot_px(x * VGA_FONT_WIDTH + frame_width + j,
+                          y * VGA_FONT_HEIGHT + frame_height + i,
+                          new_char[i * VGA_FONT_WIDTH + j]);
+        }
+    }
 }
 
 static void plot_char_grid(struct gterm_char *c, int x, int y) {
-    if (!double_buffer_enabled) gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT);
+    uint32_t old_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT];
+    uint32_t new_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT];
+
+    plot_char_mem(old_char, &grid[x + y * cols],
+                  x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height);
+    plot_char_mem(new_char, c,
+                  x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height);
+
+    if (!double_buffer_enabled) {
+        for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+            for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+                if (old_char[i * VGA_FONT_WIDTH + j] != new_char[i * VGA_FONT_WIDTH + j])
+                    gterm_plot_px(x * VGA_FONT_WIDTH + frame_width + j,
+                                  y * VGA_FONT_HEIGHT + frame_height + i,
+                                  new_char[i * VGA_FONT_WIDTH + j]);
+            }
+        }
+    }
+
     grid[x + y * cols] = *c;
 }
 
@@ -299,14 +266,13 @@ static void scroll(void) {
 void gterm_clear(bool move) {
     clear_cursor();
 
-    if (!double_buffer_enabled)
-        for (int y = frame_height; y < frame_height + VGA_FONT_HEIGHT * rows; y++)
-            memcpy(gterm_framebuffer + y * (gterm_pitch / 4) + frame_width, bg_canvas + y * gterm_width + frame_width, VGA_FONT_WIDTH * cols * 4);
     struct gterm_char empty;
     empty.c  = ' ';
     empty.fg = 9;
     empty.bg = 8;
-    for (int i = 0; i < rows * cols; i++) grid[i] = empty;
+    for (int i = 0; i < rows * cols; i++) {
+        plot_char_grid(&empty, i % cols, i / cols);
+    }
 
     if (move) {
         cursor_x = 0;
diff --git a/stage23/lib/image.c b/stage23/lib/image.c
index a325cc70..fe0f08b4 100644
--- a/stage23/lib/image.c
+++ b/stage23/lib/image.c
@@ -17,6 +17,9 @@ void image_make_centered(struct image *image, int frame_x_size, int frame_y_size
 void image_make_stretched(struct image *image, int new_x_size, int new_y_size) {
     image->type = IMAGE_STRETCHED;
 
+    image->old_x_size = image->x_size;
+    image->old_y_size = image->y_size;
+
     image->x_size = new_x_size;
     image->y_size = new_y_size;
 }
diff --git a/stage23/lib/image.h b/stage23/lib/image.h
index 717e6138..7e9cbd8f 100644
--- a/stage23/lib/image.h
+++ b/stage23/lib/image.h
@@ -9,13 +9,6 @@ struct image {
     int x_size;
     int y_size;
     int type;
-
-
-    uint8_t *img;
-    int bpp;
-    int pitch;
-    int img_width; // x_size = scaled size, img_width = bitmap size 
-    int img_height;
     union {
         struct {
             int x_displacement;
@@ -27,6 +20,7 @@ struct image {
         };
     };
     uint32_t back_colour;
+    uint32_t (*get_pixel)(struct image *this, int x, int y);
     void *local;
 };
 
tab: 248 wrap: offon