From 8e120a5c7270fcf4a524dea404c0f2cdcdda3714 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Thu, 18 Feb 2021 14:44:06 -0500 Subject: making graphics double-buffered so there isn't flicker when windows paint --- src/kernel/window.c | 69 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/kernel/window.c b/src/kernel/window.c index 10c573f..9d3db28 100644 --- a/src/kernel/window.c +++ b/src/kernel/window.c @@ -41,17 +41,42 @@ static struct window { static struct window *bottom_window = 0; static struct window *top_window = 0; -uint32_t pix_clear_mask; - -static inline void put_pix(uint16_t y, uint16_t x, struct pixel px) { - uint32_t *const fbp = VBE_MODE_INFO->frame_buf + y * VBE_MODE_INFO->pitch + x * VBE_MODE_INFO->bpp / 8; -//logf(LOG_INFO, "-- fbp = 0x%h", fbp); -//logf(LOG_INFO, "-- *fbp -> 0x%h", *fbp); - *fbp &= pix_clear_mask; - *fbp |= (px.r >> (8 - VBE_MODE_INFO->red_len)) << VBE_MODE_INFO->red_off; - *fbp |= (px.g >> (8 - VBE_MODE_INFO->green_len)) << VBE_MODE_INFO->green_off; - *fbp |= (px.b >> (8 - VBE_MODE_INFO->blue_len)) << VBE_MODE_INFO->blue_off; -//logf(LOG_INFO, "-- *fbp <- 0x%h", *fbp); +static struct pixel *buffer; +static uint32_t buffer_pages; +static uint32_t pix_clear_mask; + +static void load_mode_params() { + if (buffer) + free_pages(buffer, buffer_pages); + + const uint32_t fb_len = VBE_MODE_INFO->width * VBE_MODE_INFO->height; + buffer_pages = (fb_len * sizeof(struct pixel) - 1) / 4096 + 1; + buffer = allocate_kernel_pages(buffer_pages); + + #define MASK(offset, length) ((~((1 << offset) - 1)) - (offset + length == 32 ? 0 : (~((1 << (offset + length)) - 1)))) + pix_clear_mask = ~( + MASK(VBE_MODE_INFO->red_off, VBE_MODE_INFO->red_len) | + MASK(VBE_MODE_INFO->green_off, VBE_MODE_INFO->green_len) | + MASK(VBE_MODE_INFO->blue_off, VBE_MODE_INFO->blue_len) | + MASK(VBE_MODE_INFO->alpha_off, VBE_MODE_INFO->alpha_len) + ); +} + +static void blit() { + void *row = VBE_MODE_INFO->frame_buf; + const struct pixel *from = buffer; + for (uint16_t y = 0; y < VBE_MODE_INFO->height; ++y) { + uint32_t *out_pix = row; + for (uint16_t x = 0; x < VBE_MODE_INFO->width; ++x) { + *out_pix &= pix_clear_mask; + *out_pix |= (from->r >> (8 - VBE_MODE_INFO->red_len)) << VBE_MODE_INFO->red_off; + *out_pix |= (from->g >> (8 - VBE_MODE_INFO->green_len)) << VBE_MODE_INFO->green_off; + *out_pix |= (from->b >> (8 - VBE_MODE_INFO->blue_len)) << VBE_MODE_INFO->blue_off; + out_pix = (uint32_t *)((void *)out_pix + VBE_MODE_INFO->bpp / 8); + ++from; + } + row += VBE_MODE_INFO->pitch; + } } static inline void draw_hz_line(uint16_t y, uint16_t xs, uint16_t xm, struct pixel color) { @@ -62,7 +87,7 @@ static inline void draw_hz_line(uint16_t y, uint16_t xs, uint16_t xm, struct pix if (xm > VBE_MODE_INFO->width) xm = VBE_MODE_INFO->width; for (uint16_t x = xs; x < xm; ++x) - put_pix(y, x, color); + buffer[y * VBE_MODE_INFO->width + x] = color; } static inline void draw_vt_line(uint16_t x, uint16_t ys, uint16_t ym, struct pixel color) { @@ -73,7 +98,7 @@ static inline void draw_vt_line(uint16_t x, uint16_t ys, uint16_t ym, struct pix if (ym > VBE_MODE_INFO->height) ym = VBE_MODE_INFO->height; for (uint16_t y = ys; y < ym; ++y) - put_pix(y, x, color); + buffer[y * VBE_MODE_INFO->width + x] = color; } static void paint_and_above(const struct window *w) { @@ -89,7 +114,7 @@ static void paint_and_above(const struct window *w) { for (uint16_t y = ys; y < ym; ++y) for (uint16_t x = xs; x < xm; ++x) - put_pix(y + i->ypos, x + i->xpos, i->pixel_buffer_pma[y * i->width + x]); + buffer[(y + i->ypos) * VBE_MODE_INFO->width + x + i->xpos] = i->pixel_buffer_pma[y * i->width + x]; draw_hz_line(i->ypos - 2, i->xpos - 2, i->xpos + i->width + 2, BORDER_COLOR); draw_hz_line(i->ypos - 1, i->xpos - 2, i->xpos + i->width + 2, BORDER_COLOR); @@ -100,15 +125,15 @@ static void paint_and_above(const struct window *w) { draw_vt_line(i->xpos + i->width, i->ypos, i->ypos + i->height, BORDER_COLOR); draw_vt_line(i->xpos + i->width + 1, i->ypos, i->ypos + i->height, BORDER_COLOR); } + + blit(); switch_to_task_cr3(); } static void paint_bg() { - switch_to_kernel_cr3(); for (uint16_t y = 0; y < VBE_MODE_INFO->height; ++y) for (uint16_t x = 0; x < VBE_MODE_INFO->width; ++x) - put_pix(y, x, BACKGROUND(x, y)); - switch_to_task_cr3(); + buffer[y * VBE_MODE_INFO->width + x] = BACKGROUND(x, y); } static void paint_all() { @@ -271,15 +296,11 @@ static char *run_command; static char *run_command_pass = ""; void init_win() { - #define MASK(offset, length) ((~((1 << offset) - 1)) - (offset + length == 32 ? 0 : (~((1 << (offset + length)) - 1)))) - pix_clear_mask = ~( - MASK(VBE_MODE_INFO->red_off, VBE_MODE_INFO->red_len) | - MASK(VBE_MODE_INFO->green_off, VBE_MODE_INFO->green_len) | - MASK(VBE_MODE_INFO->blue_off, VBE_MODE_INFO->blue_len) | - MASK(VBE_MODE_INFO->alpha_off, VBE_MODE_INFO->alpha_len) - ); + buffer = 0; + load_mode_params(); paint_bg(); + blit(); const file_id_t fid = drives->get_file(drives, RUN_COMMAND_FILE); if (!fid) -- cgit v1.2.3