From 8a8b4374379b1bd8fc6fdb0e9df5023d97132205 Mon Sep 17 00:00:00 2001 From: StaticSaga <61866965+StaticSaga@users.noreply.github.com> Date: Wed, 7 Jul 2021 20:29:14 +0200 Subject: [PATCH] gterm+bmp+image: Improve performance on TCG --- stage23/lib/bmp.c | 55 +++++------------------ stage23/lib/gterm.c | 103 +++++++++++++++++++++++++++++++++----------- stage23/lib/image.c | 3 -- stage23/lib/image.h | 8 +++- 4 files changed, 96 insertions(+), 73 deletions(-) diff --git a/stage23/lib/bmp.c b/stage23/lib/bmp.c index fb90149a..a299caac 100644 --- a/stage23/lib/bmp.c +++ b/stage23/lib/bmp.c @@ -29,44 +29,9 @@ 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; @@ -75,22 +40,22 @@ int bmp_open_image(struct image *image, struct file_handle *file) { if (memcmp(&header.bf_signature, "BM", 2) != 0) return -1; - // We don't support bpp lower than 8 - if (header.bi_bpp < 8) + if ((header.bi_bpp < 8) | ((header.bi_bpp % 8) != 0)) return -1; struct bmp_local *local = ext_mem_alloc(sizeof(struct bmp_local)); - local->image = ext_mem_alloc(header.bf_size); - fread(file, local->image, header.bf_offset, header.bf_size); + image->img = ext_mem_alloc(header.bf_size); + fread(file, image->img, 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->get_pixel = get_pixel; - image->local = local; - + 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; return 0; } diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 2fe93470..9c1e7655 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -74,17 +74,7 @@ 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 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; - +static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t hex) { int distance, x_distance, y_distance; if (x < frame_width) @@ -115,14 +105,78 @@ static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) { return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px); } +// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel +#define genloop(xstart, xend, ystart, yend, fn) \ + switch (background->type) { \ + case IMAGE_TILED: \ + for (int y = (ystart); y < (yend); y++) { \ + int yb = y % img_height, xb = (xstart) % img_width; \ + const size_t off = img_pitch * (img_height - 1 - yb), coff = gterm_width * y, goff = gterm_pitch / 4 * y; \ + for (int x = (xstart); x < (xend); x++) { \ + uint32_t i = *(uint32_t*)(img + xb * colsize + off); i = fn; /* xb = (x % img_width) */ \ + bg_canvas[coff + x] = i; gterm_framebuffer[goff + x] = i; \ + if (xb++ == img_width) xb = 0; \ + } \ + } \ + break; \ + case IMAGE_CENTERED: \ + for (int y = (ystart); y < (yend); y++) { \ + int yb = y - background->y_displacement; \ + const size_t off = img_pitch * (img_height - 1 - yb), coff = gterm_width * y, goff = gterm_pitch / 4 * y; \ + if ((yb < 0) || (yb > background->y_size)) { /* external part */ \ + for (int x = (xstart); x < (xend); x++) { \ + uint32_t i = background->back_colour; i = fn; \ + bg_canvas[coff + x] = i; gterm_framebuffer[goff + x] = i; \ + } \ + } \ + else { /* internal part */ \ + for (int x = (xstart); x < (xend); x++) { \ + int xb = (x - background->x_displacement); \ + uint32_t i = ((xb < 0) || (xb > background->x_size)) ? background->back_colour : *(uint32_t*)(img + xb * colsize + off); i = fn; \ + bg_canvas[coff + x] = i; gterm_framebuffer[goff + x] = i; \ + } \ + } \ + } \ + break; \ + case IMAGE_STRETCHED: \ + for (int y = (ystart); y < (yend); y++) { \ + int counter = x16_x_delta * (xstart); \ + const size_t imgy = (y * img_height) / gterm_height, off = img_pitch * (img_height - 1 - imgy), coff = gterm_width * y, goff = gterm_pitch / 4 * y; \ + for (int x = (xstart); x < (xend); x++) { \ + uint32_t i = *(uint32_t*)(img + (counter / 16) * colsize + off); i = fn; /* counter/16 = (x * img_width) / gterm_width */ \ + bg_canvas[coff + x] = i; gterm_framebuffer[goff + x] = i; \ + counter += x16_x_delta; \ + } \ + } \ + break; \ + } + void gterm_generate_canvas(void) { if (background) { - 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]); - } + // Instead of executing blend_gradient_from_box for every pixel in the fb, just run it for the margin + uint8_t *img = background->img; + const int img_width = background->img_width, x16_x_delta = (img_width * 16) / gterm_width, + img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8; + 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; + + // Draw the part of the image outside the margin + genloop(0, gterm_width, 0, fheight, i); + genloop(0, gterm_width, fheight_end, gterm_height, i); + genloop(0, fwidth, fheight, fheight_end, i); + genloop(fwidth_end, gterm_width, fheight, fheight_end, i); + + // Draw margin + if (margin_gradient) { + genloop(fwidth, fwidth_end, fheight, frame_height, blend_gradient_from_box(x, y, i, ansi_colours[8])); + genloop(fwidth, fwidth_end, frame_height_end, fheight_end, blend_gradient_from_box(x, y, i, ansi_colours[8])); + genloop(fwidth, frame_width, frame_height, frame_height_end, blend_gradient_from_box(x, y, i, ansi_colours[8])); + genloop(frame_width_end, fwidth_end, frame_height, frame_height_end, blend_gradient_from_box(x, y, i, ansi_colours[8])); } + + // Draw inner frame + genloop(frame_width, frame_width_end, frame_height, frame_height_end, colour_blend(ansi_colours[8], i)); } else { for (int y = 0; y < gterm_height; y++) { for (int x = 0; x < gterm_width; x++) { @@ -132,6 +186,7 @@ void gterm_generate_canvas(void) { } } } +#undef genloop struct gterm_char { uint32_t c; @@ -199,10 +254,9 @@ static void plot_char_grid(struct gterm_char *c, int x, int y) { 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]); + gterm_plot_px(x * VGA_FONT_WIDTH + frame_width + j, + y * VGA_FONT_HEIGHT + frame_height + i, + new_char[i * VGA_FONT_WIDTH + j]); } } } @@ -254,14 +308,15 @@ 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++) { - plot_char_grid(&empty, i % cols, i / cols); - } - + for (int i = 0; i < rows * cols; i++) grid[i] = empty; + if (move) { cursor_x = 0; cursor_y = 0; diff --git a/stage23/lib/image.c b/stage23/lib/image.c index fe0f08b4..a325cc70 100644 --- a/stage23/lib/image.c +++ b/stage23/lib/image.c @@ -17,9 +17,6 @@ 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 7e9cbd8f..717e6138 100644 --- a/stage23/lib/image.h +++ b/stage23/lib/image.h @@ -9,6 +9,13 @@ 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; @@ -20,7 +27,6 @@ struct image { }; }; uint32_t back_colour; - uint32_t (*get_pixel)(struct image *this, int x, int y); void *local; };