framebuffer_free_lifetime/
framebuffer_free_lifetime.rs

1// Copyright (c) 2025 nytpu <alex [at] nytpu.com>
2// SPDX-License-Identifier: MPL-2.0
3// For more license details, see LICENSE or <https://www.mozilla.org/en-US/MPL/2.0/>.
4
5//! Example showing usage of using `FbDrawTarget::new_free_lifetime` to continue writing to a
6//! framebuffer after the protocol handle gets dropped.
7
8#![no_main]
9#![no_std]
10
11use core::time::Duration;
12use embedded_graphics::{pixelcolor::Rgb888, prelude::*, primitives::Rectangle};
13use embedded_graphics_gop::fb::FbDrawTarget;
14use uefi::{helpers, prelude::*, proto::console::gop::GraphicsOutput, runtime::ResetType};
15
16#[entry]
17fn main() -> Status {
18	helpers::init().unwrap();
19
20	let handle =
21		boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
22	let mut gop =
23		boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
24
25	let mode_800x600 = gop
26		.modes()
27		// one of the standard modes, although some systems may only provide 640×480
28		.find(|m| m.info().resolution() == (800, 600))
29		.expect("Unable to find 800x600 video mode");
30	gop.set_mode(&mode_800x600)
31		.expect("Couldn't switch to 800x600 video mode");
32
33	// SAFETY: see rules on `FbDrawTarget::new_free_lifetime` for caveats about invalidation,
34	// implementation-specific considerations, and complications with exiting boot services.
35	//
36	// This example does work on QEMU and should work on most real desktop implementations.
37	let mut target = unsafe { FbDrawTarget::new_free_lifetime(&mut gop) };
38	drop(gop);
39	// SAFETY: this is completely disregarding almost everything one needs to do after exiting boot
40	// services, just for demonstration purposes.  The example still works after uncommenting this.
41	// unsafe { drop(uefi::boot::exit_boot_services(None)) };
42
43	target
44		.fill_solid(
45			&Rectangle::new(Point::zero(), Size::new(266, 600)),
46			Rgb888::RED,
47		)
48		.expect("infallible");
49	target
50		.fill_solid(
51			&Rectangle::new(Point::new(266, 0), Size::new(267, 600)),
52			Rgb888::GREEN,
53		)
54		.expect("infallible");
55	target
56		.fill_solid(
57			&Rectangle::new(Point::new(533, 0), Size::new(267, 600)),
58			Rgb888::BLUE,
59		)
60		.expect("infallible");
61
62	boot::stall(Duration::from_secs(10));
63	runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
64}