:: commit 9cd21c6a30059dcc76325738ae3ca1c74a3851cc

mintsuki <mintsuki@protonmail.com> — 2020-11-20 18:55

parents: ed590257af

term: Add double buffering

diff --git a/limine-pxe.bin b/limine-pxe.bin
index 4bc1e3b8..0181e5a6 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index b2c29d4b..2bd8f53d 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2.map b/stage2.map
index 34fb9da4..b87a3cf2 100644
Binary files a/stage2.map and b/stage2.map differ
diff --git a/stage2/drivers/vbe.c b/stage2/drivers/vbe.c
index b1956e8b..602ae5c5 100644
--- a/stage2/drivers/vbe.c
+++ b/stage2/drivers/vbe.c
@@ -44,6 +44,9 @@ static int frame_height, frame_width;
 static struct image *background;
 
 static struct vbe_char *grid;
+static struct vbe_char *front_grid;
+
+static bool double_buffer_enabled = false;
 
 static bool cursor_status = true;
 
@@ -181,26 +184,27 @@ void vbe_plot_char(struct vbe_char *c, int x, int y) {
 }
 
 static void plot_char_grid(struct vbe_char *c, int x, int y) {
-    vbe_plot_char(c, x * VGA_FONT_WIDTH + frame_width,
-                     y * VGA_FONT_HEIGHT + frame_height);
+    if (!double_buffer_enabled) {
+        vbe_plot_char(c, x * VGA_FONT_WIDTH + frame_width,
+                         y * VGA_FONT_HEIGHT + frame_height);
+    }
     grid[x + y * cols] = *c;
 }
 
 static void clear_cursor(void) {
-    if (cursor_status) {
-        vbe_plot_char(&grid[cursor_x + cursor_y * cols],
-                      cursor_x * VGA_FONT_WIDTH + frame_width,
-                      cursor_y * VGA_FONT_HEIGHT + frame_height);
-    }
+    struct vbe_char c = grid[cursor_x + cursor_y * cols];
+    c.fg = text_fg;
+    c.bg = text_bg;
+    plot_char_grid(&c, cursor_x, cursor_y);
 }
 
 static void draw_cursor(void) {
-    struct vbe_char c = grid[cursor_x + cursor_y * cols];
-    c.fg = cursor_fg;
-    c.bg = cursor_bg;
-    if (cursor_status)
-        vbe_plot_char(&c, cursor_x * VGA_FONT_WIDTH + frame_width,
-                          cursor_y * VGA_FONT_HEIGHT + frame_height);
+    if (cursor_status) {
+        struct vbe_char c = grid[cursor_x + cursor_y * cols];
+        c.fg = cursor_fg;
+        c.bg = cursor_bg;
+        plot_char_grid(&c, cursor_x, cursor_y);
+    }
 }
 
 static void scroll(void) {
@@ -271,6 +275,35 @@ void vbe_set_text_bg(int bg) {
     text_bg = ansi_colours[bg];
 }
 
+void vbe_double_buffer_flush(void) {
+    for (size_t i = 0; i < (size_t)rows * cols; i++) {
+        struct vbe_char c = grid[i];
+
+        if (!memcmp(&c, &front_grid[i], sizeof(struct vbe_char)))
+            continue;
+
+        front_grid[i] = grid[i];
+
+        int x = i % cols;
+        int y = i / cols;
+
+        vbe_plot_char(&c, x * VGA_FONT_WIDTH + frame_width,
+                          y * VGA_FONT_HEIGHT + frame_height);
+    }
+}
+
+void vbe_double_buffer(bool state) {
+    double_buffer_enabled = state;
+    if (state) {
+        memset(grid, 0, rows * cols * sizeof(struct vbe_char));
+        memset(front_grid, 0, rows * cols * sizeof(struct vbe_char));
+        vbe_clear(true);
+        vbe_double_buffer_flush();
+    } else {
+        vbe_clear(true);
+    }
+}
+
 void vbe_putchar(char c) {
     switch (c) {
         case '\b':
@@ -352,6 +385,7 @@ bool vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _
     *_cols = cols = (vbe_width - _margin * 2) / VGA_FONT_WIDTH;
     *_rows = rows = (vbe_height - _margin * 2) / VGA_FONT_HEIGHT;
     grid = ext_mem_alloc(rows * cols * sizeof(struct vbe_char));
+    front_grid = ext_mem_alloc(rows * cols * sizeof(struct vbe_char));
     background = _background;
 
     if (background)
diff --git a/stage2/drivers/vbe.h b/stage2/drivers/vbe.h
index 48e6f9fd..3f595e1a 100644
--- a/stage2/drivers/vbe.h
+++ b/stage2/drivers/vbe.h
@@ -34,4 +34,7 @@ void vbe_get_cursor_pos(int *x, int *y);
 void vbe_set_text_fg(int fg);
 void vbe_set_text_bg(int bg);
 
+void vbe_double_buffer_flush(void);
+void vbe_double_buffer(bool state);
+
 #endif
diff --git a/stage2/drivers/vga_textmode.c b/stage2/drivers/vga_textmode.c
index 4271ff80..a6aa412a 100644
--- a/stage2/drivers/vga_textmode.c
+++ b/stage2/drivers/vga_textmode.c
@@ -1,28 +1,35 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
+#include <drivers/vga_textmode.h>
 #include <sys/cpu.h>
 #include <lib/real.h>
-#include <drivers/vga_textmode.h>
+#include <lib/libc.h>
+#include <mm/pmm.h>
 
 #define VIDEO_BOTTOM ((VD_ROWS * VD_COLS) - 1)
 #define VD_COLS (80 * 2)
 #define VD_ROWS 25
 
+static char *back_buffer = NULL;
+static char *front_buffer = NULL;
 static char *video_mem = (char *)0xb8000;
+
+static char *current_buffer;
+
 static size_t cursor_offset = 0;
 static int cursor_status = 1;
 static uint8_t text_palette = 0x07;
 static uint8_t cursor_palette = 0x70;
 
 static void clear_cursor(void) {
-    video_mem[cursor_offset + 1] = text_palette;
+    current_buffer[cursor_offset + 1] = text_palette;
     return;
 }
 
 static void draw_cursor(void) {
     if (cursor_status) {
-        video_mem[cursor_offset + 1] = cursor_palette;
+        current_buffer[cursor_offset + 1] = cursor_palette;
     }
     return;
 }
@@ -30,11 +37,11 @@ static void draw_cursor(void) {
 static void scroll(void) {
     // move the text up by one row
     for (size_t i = 0; i <= VIDEO_BOTTOM - VD_COLS; i++)
-        video_mem[i] = video_mem[i + VD_COLS];
+        current_buffer[i] = current_buffer[i + VD_COLS];
     // clear the last line of the screen
     for (size_t i = VIDEO_BOTTOM; i > VIDEO_BOTTOM - VD_COLS; i -= 2) {
-        video_mem[i] = text_palette;
-        video_mem[i - 1] = ' ';
+        current_buffer[i] = text_palette;
+        current_buffer[i - 1] = ' ';
     }
     return;
 }
@@ -42,8 +49,8 @@ static void scroll(void) {
 void text_clear(bool move) {
     clear_cursor();
     for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
-        video_mem[i] = ' ';
-        video_mem[i + 1] = text_palette;
+        current_buffer[i] = ' ';
+        current_buffer[i + 1] = text_palette;
     }
     if (move)
         cursor_offset = 0;
@@ -68,10 +75,39 @@ void text_disable_cursor(void) {
 void init_vga_textmode(int *_rows, int *_cols) {
     outb(0x3d4, 0x0a);
     outb(0x3d5, 0x20);
-    text_clear(true);
 
     *_rows = VD_ROWS;
     *_cols = VD_COLS / 2;
+
+    text_double_buffer(false);
+}
+
+void text_double_buffer(bool state) {
+    if (state) {
+        if (back_buffer == NULL)
+            back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
+        if (front_buffer == NULL)
+            front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
+        memset(video_mem, 0, VD_ROWS * VD_COLS);
+        memset(back_buffer, 0, VD_ROWS * VD_COLS);
+        memset(front_buffer, 0, VD_ROWS * VD_COLS);
+        current_buffer = back_buffer;
+        text_clear(true);
+        text_double_buffer_flush();
+    } else {
+        current_buffer = video_mem;
+        text_clear(true);
+    }
+}
+
+void text_double_buffer_flush(void) {
+    for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
+        if (back_buffer[i] == front_buffer[i])
+            continue;
+
+        front_buffer[i] = back_buffer[i];
+        video_mem[i]    = back_buffer[i];
+    }
 }
 
 static int text_get_cursor_pos_y(void) {
@@ -122,7 +158,7 @@ void text_putchar(char c) {
             break;
         default:
             clear_cursor();
-            video_mem[cursor_offset] = c;
+            current_buffer[cursor_offset] = c;
             if (cursor_offset >= (VIDEO_BOTTOM - 1)) {
                 scroll();
                 cursor_offset = VIDEO_BOTTOM - (VD_COLS - 1);
diff --git a/stage2/drivers/vga_textmode.h b/stage2/drivers/vga_textmode.h
index 7cc3cc97..6d06c438 100644
--- a/stage2/drivers/vga_textmode.h
+++ b/stage2/drivers/vga_textmode.h
@@ -14,4 +14,7 @@ void text_get_cursor_pos(int *x, int *y);
 void text_set_text_fg(int fg);
 void text_set_text_bg(int bg);
 
+void text_double_buffer(bool state);
+void text_double_buffer_flush(void);
+
 #endif
diff --git a/stage2/lib/term.c b/stage2/lib/term.c
index 64c8972a..1e4abbf5 100644
--- a/stage2/lib/term.c
+++ b/stage2/lib/term.c
@@ -22,6 +22,9 @@ void (*get_cursor_pos)(int *x, int *y);
 void (*set_text_fg)(int fg);
 void (*set_text_bg)(int bg);
 
+void (*term_double_buffer)(bool status);
+void (*term_double_buffer_flush)(void);
+
 int term_rows, term_cols;
 
 void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *background) {
@@ -41,6 +44,9 @@ void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *
     set_text_fg    = vbe_set_text_fg;
     set_text_bg    = vbe_set_text_bg;
 
+    term_double_buffer       = vbe_double_buffer;
+    term_double_buffer_flush = vbe_double_buffer_flush;
+
     term_backend = VBE;
 }
 
@@ -57,6 +63,9 @@ void term_textmode(void) {
     set_text_fg    = text_set_text_fg;
     set_text_bg    = text_set_text_bg;
 
+    term_double_buffer       = text_double_buffer;
+    term_double_buffer_flush = text_double_buffer_flush;
+
     term_backend = TEXTMODE;
 }
 
diff --git a/stage2/lib/term.h b/stage2/lib/term.h
index 4bde2c32..d63a12bb 100644
--- a/stage2/lib/term.h
+++ b/stage2/lib/term.h
@@ -14,6 +14,9 @@ extern void (*get_cursor_pos)(int *x, int *y);
 extern void (*set_text_fg)(int fg);
 extern void (*set_text_bg)(int bg);
 
+extern void (*term_double_buffer)(bool status);
+extern void (*term_double_buffer_flush)(void);
+
 void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *background);
 void term_textmode(void);
 void term_deinit(void);
diff --git a/stage2/menu.c b/stage2/menu.c
index 41e71e2c..b88d028d 100644
--- a/stage2/menu.c
+++ b/stage2/menu.c
@@ -135,6 +135,8 @@ refresh:
     set_cursor_pos(cursor_x, cursor_y);
     enable_cursor();
 
+    term_double_buffer_flush();
+
     int c = getchar();
     switch (c) {
         case 0:
@@ -324,6 +326,8 @@ char *menu(char **cmdline_ret) {
     if (menu_tree == NULL)
         panic("Config contains no entries.");
 
+    term_double_buffer(true);
+
 refresh:
     clear(true);
     print("\n\n  \e[36m Limine " LIMINE_VERSION " \e[37m\n\n\n");
@@ -341,6 +345,7 @@ refresh:
         print("\n\n");
         for (int i = timeout; i; i--) {
             print("\rBooting automatically in %u, press any key to stop the countdown...", i);
+            term_double_buffer_flush();
             if ((c = pit_sleep_and_quit_on_keypress(18))) {
                 skip_timeout = true;
                 print("\e[2K\r\e[2A");
@@ -350,6 +355,8 @@ refresh:
         goto autoboot;
     }
 
+    term_double_buffer_flush();
+
     for (;;) {
         c = getchar();
 timeout_aborted:
@@ -377,6 +384,7 @@ timeout_aborted:
                 }
                 clear(true);
                 *cmdline_ret = cmdline;
+                term_double_buffer(false);
                 return selected_menu_entry->body;
             case 'e': {
                 if (selected_menu_entry->sub != NULL)
diff --git a/test/limine.cfg b/test/limine.cfg
index c1cd3dd5..b52a6c0c 100644
--- a/test/limine.cfg
+++ b/test/limine.cfg
@@ -12,66 +12,6 @@ BACKGROUND_PATH=bios://:1/boot/bg.bmp
 
 :Legacy
 
-::12345
-PROTOCOL=stivale
-KERNEL_PATH=guid://@GUID@/boot/test.elf
-KERNEL_CMDLINE=Hi! This is an example!
-
-MODULE_PATH=bios://:1/boot/test.elf
-MODULE_STRING=yooooo
-
-::Stivale Test
-
-PROTOCOL=stivale
-KERNEL_PATH=bios://:1/boot/test.elf
-KERNEL_CMDLINE=Hi! This is an example!
-
-MODULE_PATH=bios://:1/boot/test.elf
-MODULE_STRING=yooooo
-
-MODULE_PATH=bios://:1/boot/bg.bmp
-MODULE_STRING=yooooo
-
-::123456
-
-:::Stivale Test
-
-PROTOCOL=stivale
-KERNEL_PATH=bios://:1/boot/test.elf
-KERNEL_CMDLINE=Hi! This is an example!
-
-MODULE_PATH=bios://:1/boot/test.elf
-MODULE_STRING=yooooo
-
-MODULE_PATH=bios://:1/boot/bg.bmp
-MODULE_STRING=yooooo
-
-:::123123123
-
-PROTOCOL=stivale
-KERNEL_PATH=bios://:1/boot/test.elf
-KERNEL_CMDLINE=Hi! This is an example!
-
-MODULE_PATH=bios://:1/boot/test.elf
-MODULE_STRING=yooooo
-
-MODULE_PATH=bios://:1/boot/bg.bmp
-MODULE_STRING=yooooo
-
-:::foo
-
-::::bar
-
-PROTOCOL=stivale
-KERNEL_PATH=bios://:1/boot/test.elf
-KERNEL_CMDLINE=Hi! This is an example!
-
-MODULE_PATH=bios://:1/boot/test.elf
-MODULE_STRING=yooooo
-
-MODULE_PATH=bios://:1/boot/bg.bmp
-MODULE_STRING=yooooo
-
 ::Stivale Test
 
 PROTOCOL=stivale
tab: 248 wrap: offon