summaryrefslogtreecommitdiffstats
path: root/rsnix/src/gop.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src/gop.rs')
-rw-r--r--rsnix/src/gop.rs87
1 files changed, 86 insertions, 1 deletions
diff --git a/rsnix/src/gop.rs b/rsnix/src/gop.rs
index 9dedcb8..dad4505 100644
--- a/rsnix/src/gop.rs
+++ b/rsnix/src/gop.rs
@@ -4,7 +4,7 @@
4/// module is the low-level rasteriser: glyph blits and pixel shifts on the 4/// module is the low-level rasteriser: glyph blits and pixel shifts on the
5/// linear framebuffer. 5/// linear framebuffer.
6use crate::font; 6use crate::font;
7use crate::uefi::{GraphicsOutputProtocol, PIXEL_BGR, PIXEL_RGB}; 7use crate::uefi::{EFI_SUCCESS, GopModeInfo, GraphicsOutputProtocol, PIXEL_BGR, PIXEL_RGB};
8use alloc::boxed::Box; 8use alloc::boxed::Box;
9use alloc::vec; 9use alloc::vec;
10use alloc::vec::Vec; 10use alloc::vec::Vec;
@@ -37,8 +37,93 @@ static mut FB: Option<Framebuffer> = None;
37static mut SHADOW: *mut u32 = core::ptr::null_mut(); 37static mut SHADOW: *mut u32 = core::ptr::null_mut();
38static mut SHADOW_WORDS: usize = 0; 38static mut SHADOW_WORDS: usize = 0;
39 39
40/// The GUI canvas. Every display surface assumes this resolution:
41/// `vt` derives its text grid from it, the compositor's cursor clamps
42/// to it, and the future window manager lays out windows on it. We
43/// force it through GOP `SetMode` at boot — QEMU's std-vga offers it,
44/// and real GPUs list it as a standard mode — falling back to the
45/// smallest mode that fits, then to whatever the firmware chose.
46const WANTED_W: usize = 800;
47const WANTED_H: usize = 600;
48
49/// Pick a GOP mode: prefer an exact 800×600 (BGR/RGB 32-bit), else the
50/// smallest mode that fits the canvas, else leave the firmware's choice
51/// alone. Call before reading the framebuffer — `SetMode` may move
52/// both the mode info pointer and the framebuffer base.
53fn select_gop_mode(gop: &mut GraphicsOutputProtocol) {
54 let mode = unsafe { &*gop.mode };
55 let cur = mode.mode;
56 let info = unsafe { &*mode.info };
57 let cur_w = info.horizontal_resolution as usize;
58 let cur_h = info.vertical_resolution as usize;
59 if cur_w == WANTED_W && cur_h == WANTED_H {
60 crate::serial_println!("gop: mode {} — already {}x{}", cur, cur_w, cur_h);
61 return;
62 }
63
64 let mut best: Option<(u32, usize, usize)> = None; // (mode#, w, h)
65 for i in 0..mode.max_mode {
66 let mut size: usize = 0;
67 let mut info_ptr: *mut GopModeInfo = core::ptr::null_mut();
68 let st = unsafe { (gop.query_mode)(gop, i, &mut size, &mut info_ptr) };
69 if st != EFI_SUCCESS || info_ptr.is_null() {
70 continue;
71 }
72 let mi = unsafe { &*info_ptr };
73 if mi.pixel_format != PIXEL_BGR && mi.pixel_format != PIXEL_RGB {
74 continue; // 32-bit BGR/RGB only (the driver assumes 4 Bpp)
75 }
76 let w = mi.horizontal_resolution as usize;
77 let h = mi.vertical_resolution as usize;
78 if w == WANTED_W && h == WANTED_H {
79 best = Some((i, w, h));
80 break;
81 }
82 if w >= WANTED_W && h >= WANTED_H {
83 match best {
84 Some((_, bw, bh)) if bw * bh <= w * h => {}
85 _ => best = Some((i, w, h)),
86 }
87 }
88 }
89
90 match best {
91 Some((n, w, h)) => {
92 let st = unsafe { (gop.set_mode)(gop, n) };
93 if st != EFI_SUCCESS {
94 crate::serial_println!(
95 "gop: SetMode({}) failed 0x{:x} — keeping current {}x{}",
96 n,
97 st,
98 cur_w,
99 cur_h
100 );
101 return;
102 }
103 crate::serial_println!(
104 "gop: mode {} selected — {}x{} (was {}x{})",
105 n,
106 w,
107 h,
108 cur_w,
109 cur_h
110 );
111 }
112 None => crate::serial_println!(
113 "gop: no mode ≥ {}x{} — keeping current {}x{}",
114 WANTED_W,
115 WANTED_H,
116 cur_w,
117 cur_h
118 ),
119 }
120}
121
40/// Initialise the framebuffer from GOP. Call *before* ExitBootServices. 122/// Initialise the framebuffer from GOP. Call *before* ExitBootServices.
41pub fn init(gop: &mut GraphicsOutputProtocol) { 123pub fn init(gop: &mut GraphicsOutputProtocol) {
124 // Force the 800×600 canvas first; SetMode may move the info
125 // pointer and framebuffer base, so everything is re-read after.
126 select_gop_mode(gop);
42 let mode = unsafe { &*gop.mode }; 127 let mode = unsafe { &*gop.mode };
43 let info = unsafe { &*mode.info }; 128 let info = unsafe { &*mode.info };
44 let base = mode.framebuffer_base as *mut u8; 129 let base = mode.framebuffer_base as *mut u8;