roxy_loader_api/
framebuffer.rs1use uefi::proto::console::gop::PixelFormat as UefiPixelFormat;
2
3#[derive(Clone, Copy)]
8#[repr(C)]
9pub struct Framebuffer {
10 ptr: usize,
11 pub size: usize,
13 pub stride: usize,
15 pub pixel_format: PixelFormat,
17 pub width: usize,
19 pub height: usize,
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24#[repr(C)]
25pub enum PixelFormat {
26 Rgb,
27 Bgr,
28 Bitmask,
29 BltOnly,
30}
31
32impl From<UefiPixelFormat> for PixelFormat {
33 fn from(value: UefiPixelFormat) -> Self {
34 match value {
35 UefiPixelFormat::Rgb => Self::Rgb,
36 UefiPixelFormat::Bgr => Self::Bgr,
37 UefiPixelFormat::Bitmask => Self::Bitmask,
38 UefiPixelFormat::BltOnly => Self::BltOnly,
39 }
40 }
41}
42
43type Resolution = (usize, usize);
44
45impl Framebuffer {
46 pub fn bytes_per_pixel(&self) -> usize {
48 self.size / (self.stride * self.height)
49 }
50
51 pub fn new(
53 ptr: *mut u8,
54 size: usize,
55 stride: usize,
56 pixel_format: impl Into<PixelFormat>,
57 resolution: Resolution,
58 ) -> Self {
59 let (width, height) = resolution;
60
61 Self {
62 ptr: ptr as usize,
63 size,
64 stride,
65 width,
66 height,
67 pixel_format: pixel_format.into(),
68 }
69 }
70
71 pub fn ptr(&self) -> *mut u8 {
73 self.ptr as *mut u8
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::{Framebuffer, PixelFormat};
80 use core::{
81 mem::{MaybeUninit, align_of, size_of},
82 ptr::addr_of,
83 };
84 use uefi::proto::console::gop::PixelFormat as UefiPixelFormat;
85
86 #[test]
87 fn layout_is_stable() {
88 assert_eq!(size_of::<Framebuffer>(), 48);
89 assert_eq!(align_of::<Framebuffer>(), align_of::<usize>());
90 assert_eq!(size_of::<PixelFormat>(), 4);
91 assert_eq!(align_of::<PixelFormat>(), 4);
92
93 let framebuffer = MaybeUninit::<Framebuffer>::uninit();
94 let base = framebuffer.as_ptr();
95
96 unsafe {
98 assert_eq!(addr_of!((*base).ptr) as usize - base as usize, 0);
99 assert_eq!(
100 addr_of!((*base).size) as usize - base as usize,
101 size_of::<usize>()
102 );
103 assert_eq!(
104 addr_of!((*base).stride) as usize - base as usize,
105 size_of::<usize>() * 2
106 );
107 assert_eq!(
108 addr_of!((*base).pixel_format) as usize - base as usize,
109 size_of::<usize>() * 3
110 );
111 assert_eq!(
112 addr_of!((*base).width) as usize - base as usize,
113 size_of::<usize>() * 4
114 );
115 assert_eq!(
116 addr_of!((*base).height) as usize - base as usize,
117 size_of::<usize>() * 5
118 );
119 }
120 }
121
122 #[test]
123 fn new_preserves_framebuffer_metadata() {
124 let ptr = 0x1000 as *mut u8;
125 let framebuffer = Framebuffer::new(ptr, 800 * 600 * 4, 800, PixelFormat::Bgr, (800, 600));
126
127 assert_eq!(framebuffer.ptr(), ptr);
128 assert_eq!(framebuffer.size, 800 * 600 * 4);
129 assert_eq!(framebuffer.stride, 800);
130 assert_eq!(framebuffer.pixel_format, PixelFormat::Bgr);
131 assert_eq!(framebuffer.width, 800);
132 assert_eq!(framebuffer.height, 600);
133 }
134
135 #[test]
136 fn bytes_per_pixel_uses_stride_height_and_size() {
137 let framebuffer = Framebuffer::new(
138 core::ptr::null_mut(),
139 1024 * 768 * 4,
140 1024,
141 PixelFormat::Rgb,
142 (800, 768),
143 );
144
145 assert_eq!(framebuffer.bytes_per_pixel(), 4);
146 }
147
148 #[test]
149 fn converts_uefi_pixel_formats() {
150 assert_eq!(PixelFormat::from(UefiPixelFormat::Rgb), PixelFormat::Rgb);
151 assert_eq!(PixelFormat::from(UefiPixelFormat::Bgr), PixelFormat::Bgr);
152 assert_eq!(
153 PixelFormat::from(UefiPixelFormat::Bitmask),
154 PixelFormat::Bitmask
155 );
156 assert_eq!(
157 PixelFormat::from(UefiPixelFormat::BltOnly),
158 PixelFormat::BltOnly
159 );
160 }
161}