-
Notifications
You must be signed in to change notification settings - Fork 154
/
gop.rs
107 lines (94 loc) · 3.47 KB
/
gop.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::{send_request_to_host, HostRequest};
use uefi::prelude::*;
use uefi::proto::console::gop::{BltOp, BltPixel, FrameBuffer, GraphicsOutput, PixelFormat};
use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams};
pub unsafe fn test(image: Handle, bt: &BootServices) {
info!("Running graphics output protocol test");
let handle = bt
.get_handle_for_protocol::<GraphicsOutput>()
.expect("missing GraphicsOutput protocol");
let gop = &mut bt
.open_protocol::<GraphicsOutput>(
OpenProtocolParams {
handle,
agent: image,
controller: None,
},
// For this test, don't open in exclusive mode. That
// would break the connection between stdout and the
// video console.
OpenProtocolAttributes::GetProtocol,
)
.expect("failed to open Graphics Output Protocol");
set_graphics_mode(gop);
fill_color(gop);
draw_fb(gop);
// `draw_fb` is skipped on aarch64, so the screenshot doesn't match.
if cfg!(not(target_arch = "aarch64")) {
send_request_to_host(bt, HostRequest::Screenshot("gop_test"));
}
}
// Set a larger graphics mode.
fn set_graphics_mode(gop: &mut GraphicsOutput) {
// We know for sure QEMU has a 1024x768 mode.
let mode = gop
.modes()
.find(|mode| {
let info = mode.info();
info.resolution() == (1024, 768)
})
.unwrap();
gop.set_mode(&mode).expect("Failed to set graphics mode");
}
// Fill the screen with color.
fn fill_color(gop: &mut GraphicsOutput) {
let op = BltOp::VideoFill {
// Cornflower blue.
color: BltPixel::new(100, 149, 237),
dest: (0, 0),
dims: (1024, 768),
};
gop.blt(op).expect("Failed to fill screen with color");
}
// Draw directly to the frame buffer.
fn draw_fb(gop: &mut GraphicsOutput) {
// The `virtio-gpu-pci` graphics device we use on aarch64 doesn't
// support `PixelFormat::BltOnly`.
if cfg!(target_arch = "aarch64") {
return;
}
let mi = gop.current_mode_info();
let stride = mi.stride();
let (width, height) = mi.resolution();
let mut fb = gop.frame_buffer();
type PixelWriter = unsafe fn(&mut FrameBuffer, usize, [u8; 3]);
unsafe fn write_pixel_rgb(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) {
fb.write_value(pixel_base, rgb);
}
unsafe fn write_pixel_bgr(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) {
fb.write_value(pixel_base, [rgb[2], rgb[1], rgb[0]]);
}
let write_pixel: PixelWriter = match mi.pixel_format() {
PixelFormat::Rgb => write_pixel_rgb,
PixelFormat::Bgr => write_pixel_bgr,
_ => {
info!("This pixel format is not supported by the drawing demo");
return;
}
};
let mut fill_rectangle = |(x1, y1), (x2, y2), color| {
assert!((x1 < width) && (x2 < width), "Bad X coordinate");
assert!((y1 < height) && (y2 < height), "Bad Y coordinate");
for row in y1..y2 {
for column in x1..x2 {
unsafe {
let pixel_index = (row * stride) + column;
let pixel_base = 4 * pixel_index;
write_pixel(&mut fb, pixel_base, color);
}
}
}
};
fill_rectangle((50, 30), (150, 600), [250, 128, 64]);
fill_rectangle((400, 120), (750, 450), [16, 128, 255]);
}