:: commit 2e2fc63628d95644c0065c265b4cde2a3f3bc1da

Mintsuki <mintsuki@protonmail.com> — 2026-03-23 03:43

parents: 89d653a659

lib/fb: Add preserve_screen option to skip fb_clear on init

diff --git a/common/drivers/gop.c b/common/drivers/gop.c
index 59fa374c..2f4726be 100644
--- a/common/drivers/gop.c
+++ b/common/drivers/gop.c
@@ -127,7 +127,7 @@ bool gop_force_16 = false;
 static bool try_mode(struct fb_info *ret, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
                      size_t mode, uint64_t width, uint64_t height, int bpp,
                      struct fb_info *fbs, size_t fbs_count,
-                     bool *setmode_called) {
+                     bool *setmode_called, bool preserve_screen) {
     EFI_STATUS status;
 
     if (!mode_to_fb_info(ret, gop, mode)) {
@@ -181,7 +181,9 @@ static bool try_mode(struct fb_info *ret, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
 
     ret->framebuffer_addr = gop->Mode->FrameBufferBase;
 
-    fb_clear(ret);
+    if (!preserve_screen) {
+        fb_clear(ret);
+    }
 
     return true;
 }
@@ -214,7 +216,8 @@ no_unwind static bool setmode_called[MAX_PRESET_MODES];
 no_unwind static bool preset_modes_initialised = false;
 
 void init_gop(struct fb_info **ret, size_t *_fbs_count,
-              uint64_t target_width, uint64_t target_height, uint16_t target_bpp) {
+              uint64_t target_width, uint64_t target_height, uint16_t target_bpp,
+              bool preserve_screen) {
     if (preset_modes_initialised == false) {
         for (size_t i = 0; i < MAX_PRESET_MODES; i++) {
             preset_modes[i] = -1;
@@ -319,7 +322,7 @@ void init_gop(struct fb_info **ret, size_t *_fbs_count,
 
 retry:
         for (size_t j = 0; j < modes_count; j++) {
-            if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count, &setmode_called[i])) {
+            if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count, &setmode_called[i], preserve_screen)) {
                 goto success;
             }
         }
@@ -346,7 +349,7 @@ fallback:
         if (current_fallback == 1) {
             current_fallback++;
 
-            if (try_mode(fb, gop, preset_modes[i], 0, 0, 0, *ret, fbs_count, &setmode_called[i])) {
+            if (try_mode(fb, gop, preset_modes[i], 0, 0, 0, *ret, fbs_count, &setmode_called[i], preserve_screen)) {
                 goto success;
             }
         }
diff --git a/common/drivers/gop.h b/common/drivers/gop.h
index 24a463ab..bf0c41de 100644
--- a/common/drivers/gop.h
+++ b/common/drivers/gop.h
@@ -9,7 +9,8 @@
 #include <lib/fb.h>
 
 void init_gop(struct fb_info **ret, size_t *_fbs_count,
-              uint64_t target_width, uint64_t target_height, uint16_t target_bpp);
+              uint64_t target_width, uint64_t target_height, uint16_t target_bpp,
+              bool preserve_screen);
 
 extern bool gop_force_16;
 
diff --git a/common/drivers/vbe.c b/common/drivers/vbe.c
index 735d16bf..eff5c000 100644
--- a/common/drivers/vbe.c
+++ b/common/drivers/vbe.c
@@ -231,7 +231,8 @@ struct fb_info *vbe_get_mode_list(size_t *count) {
 }
 
 bool init_vbe(struct fb_info *ret,
-              uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp,
+              bool preserve_screen) {
     printv("vbe: Initialising...\n");
 
     size_t current_fallback = 0;
@@ -343,7 +344,9 @@ retry:
                 continue;
             }
 
-            fb_clear(ret);
+            if (!preserve_screen) {
+                fb_clear(ret);
+            }
 
             return true;
         }
diff --git a/common/drivers/vbe.h b/common/drivers/vbe.h
index f5da1f88..fbbdf937 100644
--- a/common/drivers/vbe.h
+++ b/common/drivers/vbe.h
@@ -7,7 +7,8 @@
 #include <lib/fb.h>
 
 bool init_vbe(struct fb_info *ret,
-              uint16_t target_width, uint16_t target_height, uint16_t target_bpp);
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp,
+              bool preserve_screen);
 
 struct fb_info *vbe_get_mode_list(size_t *count);
 
diff --git a/common/lib/fb.c b/common/lib/fb.c
index 38ec277d..4c64a81a 100644
--- a/common/lib/fb.c
+++ b/common/lib/fb.c
@@ -12,10 +12,11 @@ struct fb_info *fb_fbs;
 size_t fb_fbs_count = 0;
 
 void fb_init(struct fb_info **ret, size_t *_fbs_count,
-             uint64_t target_width, uint64_t target_height, uint16_t target_bpp) {
+             uint64_t target_width, uint64_t target_height, uint16_t target_bpp,
+             bool preserve_screen) {
 #if defined (BIOS)
     *ret = ext_mem_alloc(sizeof(struct fb_info));
-    if (init_vbe(*ret, target_width, target_height, target_bpp)) {
+    if (init_vbe(*ret, target_width, target_height, target_bpp, preserve_screen)) {
         *_fbs_count = 1;
 
         (*ret)->edid = get_edid_info();
@@ -27,7 +28,7 @@ void fb_init(struct fb_info **ret, size_t *_fbs_count,
         pmm_free(*ret, sizeof(struct fb_info));
     }
 #elif defined (UEFI)
-    init_gop(ret, _fbs_count, target_width, target_height, target_bpp);
+    init_gop(ret, _fbs_count, target_width, target_height, target_bpp, preserve_screen);
 #endif
 
     fb_fbs = *ret;
diff --git a/common/lib/fb.h b/common/lib/fb.h
index b34c6e1a..fd46ff59 100644
--- a/common/lib/fb.h
+++ b/common/lib/fb.h
@@ -3,6 +3,7 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <stdbool.h>
 #include <drivers/edid.h>
 
 struct resolution {
@@ -36,7 +37,8 @@ extern struct fb_info *fb_fbs;
 extern size_t fb_fbs_count;
 
 void fb_init(struct fb_info **ret, size_t *_fbs_count,
-             uint64_t target_width, uint64_t target_height, uint16_t target_bpp);
+             uint64_t target_width, uint64_t target_height, uint16_t target_bpp,
+             bool preserve_screen);
 
 void fb_clear(struct fb_info *fb);
 
diff --git a/common/lib/gterm.c b/common/lib/gterm.c
index 1f096b48..975184ff 100644
--- a/common/lib/gterm.c
+++ b/common/lib/gterm.c
@@ -769,7 +769,7 @@ bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
     term_notready();
 
     // We force bpp to 32
-    fb_init(&fbs, &fbs_count, width, height, 32);
+    fb_init(&fbs, &fbs_count, width, height, 32, false);
 
     if (_fbs != NULL) {
         *_fbs = fbs;
diff --git a/common/protos/chainload.c b/common/protos/chainload.c
index a5512f46..6dbfc8f2 100644
--- a/common/protos/chainload.c
+++ b/common/protos/chainload.c
@@ -293,7 +293,7 @@ noreturn void chainload(char *config, char *cmdline) {
 
     struct fb_info *fbinfo;
     size_t fb_count;
-    fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp);
+    fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp, false);
 
     size_t cmdline_len = strlen(cmdline);
     CHAR16 *new_cmdline;
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 6344667c..8cc17bdd 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1299,7 +1299,8 @@ FEAT_END
 
     term_notready();
 
-    fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+    bool preserve_screen = get_request(LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID) != NULL;
+    fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, preserve_screen);
     if (fbs_count == 0) {
         goto no_fb;
     }
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index 43875d5c..c53f1dd7 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -245,7 +245,7 @@ static void prepare_efi_tables(struct boot_param *p, char *config) {
 
         term_notready();
 
-        fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+        fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false);
 
         // TODO(qookie): Let the user pick a framebuffer if there's > 1
         if (fbs_count > 0) {
diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index ec5520ce..cce595ec 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -542,7 +542,7 @@ no_modules:;
 #if defined (UEFI)
     gop_force_16 = true;
 #endif
-    fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+    fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false);
     if (fbs_count == 0) {
 #if defined (UEFI)
         goto no_fb;
diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index d7c5c201..5e95e292 100644
--- a/common/protos/multiboot1.c
+++ b/common/protos/multiboot1.c
@@ -399,7 +399,7 @@ modeset:;
 
             struct fb_info *fbs;
             size_t fbs_count;
-            fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+            fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false);
             if (fbs_count == 0) {
 #if defined (UEFI)
                 goto skip_modeset;
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index 3acbdba6..18721cd3 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -736,7 +736,7 @@ modeset:;
 
             struct fb_info *fbs;
             size_t fbs_count;
-            fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+            fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false);
             if (fbs_count == 0) {
 #if defined (BIOS)
 textmode:
tab: 248 wrap: offon