pub struct BltDrawTarget<'proto> { /* private fields */ }alloc only.Expand description
A DrawTarget using only BLT routines to write to the framebuffer.
Works on all UEFI implementations providing the GOP protocol—UEFI Specification 2.11 § 12.9.2; BLT is required to be provided, but drivers/hardware are allowed to not provide direct framebuffer access. However, it requires UEFI boot services to be active as it makes boot services function calls.
Offers single- and double-buffered modes, defaulting to single-buffer mode. In single-buffered mode, drawing is transferred to the framebuffer immediately. In double-buffered mode, drawing is saved to an internal back-buffer and are only transferred to the primary buffer after being explicitly committed.
Note that even in single-buffered mode, an internal framebuffer is still allocated for optimizing draw operations. This framebuffer is kept in sync with any drawing operations performed, so the canvas state stays consistent even when switching between single- and double-buffered mode.
In double-buffered mode, rudimentary damage tracking is performed to minimize the region that
gets transferred to the primary buffer. In double-buffered mode, any untransferred changes are
automatically transferred when the BltDrawTarget is dropped. Note that the routines in
the DrawTarget implementation will never return an error in double-buffered mode and can be
considered infallible; as only BltDrawTarget::commit calls UEFI routines.
§Examples
use embedded_graphics_gop::BltDrawTarget;
use uefi::{prelude::*, proto::console::gop::GraphicsOutput};
// Get the first available handle for the GOP.
let handle = boot::get_handle_for_protocol::<GraphicsOutput>().unwrap();
// Open the protocol in exclusive mode (exclusive mode is for applications, other modes are
// intended for drivers)
let mut protocol = boot::open_protocol_exclusive::<GraphicsOutput>(handle).unwrap();
// Configure protocol here if desired, for example
let mode = protocol.modes().find(|m| m.info().resolution() == (800, 600)).unwrap();
protocol.set_mode(&mode).unwrap();
// Create the draw target utilizing the configured protocol.
let mut target = BltDrawTarget::new(&mut protocol).unwrap();
// Make it double-buffered
target.double_buffer(true).unwrap();
// ...draw on it...
// Transfer changes to the framebuffer
target.commit().unwrap();Implementations§
Source§impl<'proto> BltDrawTarget<'proto>
impl<'proto> BltDrawTarget<'proto>
Sourcepub fn new(protocol: &'proto mut ScopedProtocol<GraphicsOutput>) -> Result<Self>
pub fn new(protocol: &'proto mut ScopedProtocol<GraphicsOutput>) -> Result<Self>
Create a new BltDrawTarget given a GOP protocol handle.
Fills the framebuffer and back-buffer with black.
Note that one should configure the desired graphics mode for the protocol prior to creating
the BltDrawTarget.
§Errors
Returns a uefi::Error if the BLT operation to black out the framebuffer fails.
§Panics
- If the reported resolution of the current graphics mode is ≥ 2^31 - 1 in either dimension.
- If the reported number of pixels addressed by the current graphics mode (width×height)
exceeds
isize::MAX / 4(i.e. largest possible size for an array ofu32s).
Examples found in repository?
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38 target.double_buffer(true).expect("no errors possible");
39
40 let center = Point::new(400, 300);
41
42 let white_fill = PrimitiveStyle::with_fill(Rgb888::WHITE);
43 let (red_outline, green_outline, blue_outline) = {
44 let base = PrimitiveStyleBuilder::new().stroke_width(10);
45 (
46 base.stroke_color(Rgb888::RED).build(),
47 base.stroke_color(Rgb888::GREEN).build(),
48 base.stroke_color(Rgb888::BLUE).build(),
49 )
50 };
51
52 Circle::with_center(center, 500)
53 .into_styled(red_outline)
54 .draw(&mut target)
55 .expect("infallible");
56
57 Circle::with_center(center, 400)
58 .into_styled(green_outline)
59 .draw(&mut target)
60 .expect("infallible");
61
62 target.commit().expect("failed to copy to framebuffer");
63
64 // Would cover circles
65 Rectangle::with_center(Point::new(50, 50), Size::new(700, 500))
66 .into_styled(white_fill)
67 .draw(&mut target)
68 .expect("infallible");
69
70 target
71 .discard_changes()
72 .expect("failed to reset from framebuffer");
73
74 Circle::with_center(center, 300)
75 .into_styled(blue_outline)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // should auto-commit
80 drop(target);
81
82 boot::stall(Duration::from_secs(10));
83 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
84}More examples
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38
39 target
40 .double_buffer(true)
41 .expect("failed to set double buffer");
42
43 let red_fill = PrimitiveStyle::with_fill(Rgb888::RED);
44 let blue_fill = PrimitiveStyle::with_fill(Rgb888::BLUE);
45
46 let mut ball_pos = Point::new(200, 300);
47 let mut ball_dir = Point::new(5, 5);
48 let ball_size = 10;
49 for _ in 0..1000 {
50 // Drawing over old position with blue instead of black to leave trail behind and
51 // demonstrate more colors
52 Rectangle::new(ball_pos, Size::new(ball_size, ball_size))
53 .into_styled(blue_fill)
54 .draw(&mut target)
55 .expect("infallible");
56
57 ball_pos += ball_dir;
58
59 if ball_pos.x <= 0 {
60 ball_pos.x = 0;
61 ball_dir.x = -ball_dir.x;
62 } else if ball_pos.x >= 790 {
63 ball_pos.x = 790;
64 ball_dir.x = -ball_dir.x;
65 }
66 if ball_pos.y <= 0 {
67 ball_pos.y = 0;
68 ball_dir.y = -ball_dir.y;
69 } else if ball_pos.y >= 590 {
70 ball_pos.y = 590;
71 ball_dir.y = -ball_dir.y;
72 }
73
74 Circle::new(ball_pos, ball_size)
75 .into_styled(red_fill)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // In real code would probably want to set up UEFI timer and commit in there?
80 target
81 .commit()
82 .expect("unable to commit changes to framebuffer");
83 boot::stall(Duration::from_millis(10));
84 }
85
86 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
87}Sourcepub fn double_buffer(&mut self, double_buffer: bool) -> Result<()>
pub fn double_buffer(&mut self, double_buffer: bool) -> Result<()>
Enable or disable the double-buffering mode.
If current in double-buffered mode and it is being disabled, then the buffer contents will be committed.
§Errors
Returns a uefi::Error if disabling double-buffering and an error occured when
committing current contents.
Examples found in repository?
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38 target.double_buffer(true).expect("no errors possible");
39
40 let center = Point::new(400, 300);
41
42 let white_fill = PrimitiveStyle::with_fill(Rgb888::WHITE);
43 let (red_outline, green_outline, blue_outline) = {
44 let base = PrimitiveStyleBuilder::new().stroke_width(10);
45 (
46 base.stroke_color(Rgb888::RED).build(),
47 base.stroke_color(Rgb888::GREEN).build(),
48 base.stroke_color(Rgb888::BLUE).build(),
49 )
50 };
51
52 Circle::with_center(center, 500)
53 .into_styled(red_outline)
54 .draw(&mut target)
55 .expect("infallible");
56
57 Circle::with_center(center, 400)
58 .into_styled(green_outline)
59 .draw(&mut target)
60 .expect("infallible");
61
62 target.commit().expect("failed to copy to framebuffer");
63
64 // Would cover circles
65 Rectangle::with_center(Point::new(50, 50), Size::new(700, 500))
66 .into_styled(white_fill)
67 .draw(&mut target)
68 .expect("infallible");
69
70 target
71 .discard_changes()
72 .expect("failed to reset from framebuffer");
73
74 Circle::with_center(center, 300)
75 .into_styled(blue_outline)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // should auto-commit
80 drop(target);
81
82 boot::stall(Duration::from_secs(10));
83 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
84}More examples
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38
39 target
40 .double_buffer(true)
41 .expect("failed to set double buffer");
42
43 let red_fill = PrimitiveStyle::with_fill(Rgb888::RED);
44 let blue_fill = PrimitiveStyle::with_fill(Rgb888::BLUE);
45
46 let mut ball_pos = Point::new(200, 300);
47 let mut ball_dir = Point::new(5, 5);
48 let ball_size = 10;
49 for _ in 0..1000 {
50 // Drawing over old position with blue instead of black to leave trail behind and
51 // demonstrate more colors
52 Rectangle::new(ball_pos, Size::new(ball_size, ball_size))
53 .into_styled(blue_fill)
54 .draw(&mut target)
55 .expect("infallible");
56
57 ball_pos += ball_dir;
58
59 if ball_pos.x <= 0 {
60 ball_pos.x = 0;
61 ball_dir.x = -ball_dir.x;
62 } else if ball_pos.x >= 790 {
63 ball_pos.x = 790;
64 ball_dir.x = -ball_dir.x;
65 }
66 if ball_pos.y <= 0 {
67 ball_pos.y = 0;
68 ball_dir.y = -ball_dir.y;
69 } else if ball_pos.y >= 590 {
70 ball_pos.y = 590;
71 ball_dir.y = -ball_dir.y;
72 }
73
74 Circle::new(ball_pos, ball_size)
75 .into_styled(red_fill)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // In real code would probably want to set up UEFI timer and commit in there?
80 target
81 .commit()
82 .expect("unable to commit changes to framebuffer");
83 boot::stall(Duration::from_millis(10));
84 }
85
86 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
87}Sourcepub fn get_double_buffer(&self) -> bool
pub fn get_double_buffer(&self) -> bool
Return whether double-buffering mode is currently enabled.
Sourcepub fn commit(&mut self) -> Result<()>
pub fn commit(&mut self) -> Result<()>
Transfer the backbuffer contents to the primary buffer.
If in single-buffering mode, has no effect.
§Errors
Returns a uefi::Error if an error occurs while transferring the backbuffer. Will never
return an error in single-buffered mode.
Examples found in repository?
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38 target.double_buffer(true).expect("no errors possible");
39
40 let center = Point::new(400, 300);
41
42 let white_fill = PrimitiveStyle::with_fill(Rgb888::WHITE);
43 let (red_outline, green_outline, blue_outline) = {
44 let base = PrimitiveStyleBuilder::new().stroke_width(10);
45 (
46 base.stroke_color(Rgb888::RED).build(),
47 base.stroke_color(Rgb888::GREEN).build(),
48 base.stroke_color(Rgb888::BLUE).build(),
49 )
50 };
51
52 Circle::with_center(center, 500)
53 .into_styled(red_outline)
54 .draw(&mut target)
55 .expect("infallible");
56
57 Circle::with_center(center, 400)
58 .into_styled(green_outline)
59 .draw(&mut target)
60 .expect("infallible");
61
62 target.commit().expect("failed to copy to framebuffer");
63
64 // Would cover circles
65 Rectangle::with_center(Point::new(50, 50), Size::new(700, 500))
66 .into_styled(white_fill)
67 .draw(&mut target)
68 .expect("infallible");
69
70 target
71 .discard_changes()
72 .expect("failed to reset from framebuffer");
73
74 Circle::with_center(center, 300)
75 .into_styled(blue_outline)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // should auto-commit
80 drop(target);
81
82 boot::stall(Duration::from_secs(10));
83 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
84}More examples
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38
39 target
40 .double_buffer(true)
41 .expect("failed to set double buffer");
42
43 let red_fill = PrimitiveStyle::with_fill(Rgb888::RED);
44 let blue_fill = PrimitiveStyle::with_fill(Rgb888::BLUE);
45
46 let mut ball_pos = Point::new(200, 300);
47 let mut ball_dir = Point::new(5, 5);
48 let ball_size = 10;
49 for _ in 0..1000 {
50 // Drawing over old position with blue instead of black to leave trail behind and
51 // demonstrate more colors
52 Rectangle::new(ball_pos, Size::new(ball_size, ball_size))
53 .into_styled(blue_fill)
54 .draw(&mut target)
55 .expect("infallible");
56
57 ball_pos += ball_dir;
58
59 if ball_pos.x <= 0 {
60 ball_pos.x = 0;
61 ball_dir.x = -ball_dir.x;
62 } else if ball_pos.x >= 790 {
63 ball_pos.x = 790;
64 ball_dir.x = -ball_dir.x;
65 }
66 if ball_pos.y <= 0 {
67 ball_pos.y = 0;
68 ball_dir.y = -ball_dir.y;
69 } else if ball_pos.y >= 590 {
70 ball_pos.y = 590;
71 ball_dir.y = -ball_dir.y;
72 }
73
74 Circle::new(ball_pos, ball_size)
75 .into_styled(red_fill)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // In real code would probably want to set up UEFI timer and commit in there?
80 target
81 .commit()
82 .expect("unable to commit changes to framebuffer");
83 boot::stall(Duration::from_millis(10));
84 }
85
86 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
87}Sourcepub fn discard_changes(&mut self) -> Result<()>
pub fn discard_changes(&mut self) -> Result<()>
Discard any uncommitted changes when in double-buffered mode.
The damaged portion of the backbuffer will have its contents overwritten with the current state of the primary buffer, truly discarding any changes since the last commit.
§Errors
Returns a uefi::Error if an error occurs while reading the primary buffer data into the
backbuffer.
Examples found in repository?
21fn main() -> Status {
22 helpers::init().unwrap();
23
24 let handle =
25 boot::get_handle_for_protocol::<GraphicsOutput>().expect("Unable to get GOP handle");
26 let mut gop =
27 boot::open_protocol_exclusive::<GraphicsOutput>(handle).expect("Unable to open GOP handle");
28
29 let mode_800x600 = gop
30 .modes()
31 // one of the standard modes, although some systems may only provide 640×480
32 .find(|m| m.info().resolution() == (800, 600))
33 .expect("Unable to find 800x600 video mode");
34 gop.set_mode(&mode_800x600)
35 .expect("Couldn't switch to 800x600 video mode");
36
37 let mut target = BltDrawTarget::new(&mut gop).expect("unable to open BLTDrawTarget");
38 target.double_buffer(true).expect("no errors possible");
39
40 let center = Point::new(400, 300);
41
42 let white_fill = PrimitiveStyle::with_fill(Rgb888::WHITE);
43 let (red_outline, green_outline, blue_outline) = {
44 let base = PrimitiveStyleBuilder::new().stroke_width(10);
45 (
46 base.stroke_color(Rgb888::RED).build(),
47 base.stroke_color(Rgb888::GREEN).build(),
48 base.stroke_color(Rgb888::BLUE).build(),
49 )
50 };
51
52 Circle::with_center(center, 500)
53 .into_styled(red_outline)
54 .draw(&mut target)
55 .expect("infallible");
56
57 Circle::with_center(center, 400)
58 .into_styled(green_outline)
59 .draw(&mut target)
60 .expect("infallible");
61
62 target.commit().expect("failed to copy to framebuffer");
63
64 // Would cover circles
65 Rectangle::with_center(Point::new(50, 50), Size::new(700, 500))
66 .into_styled(white_fill)
67 .draw(&mut target)
68 .expect("infallible");
69
70 target
71 .discard_changes()
72 .expect("failed to reset from framebuffer");
73
74 Circle::with_center(center, 300)
75 .into_styled(blue_outline)
76 .draw(&mut target)
77 .expect("infallible");
78
79 // should auto-commit
80 drop(target);
81
82 boot::stall(Duration::from_secs(10));
83 runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
84}Sourcepub fn discard_changes_no_reset(&mut self)
pub fn discard_changes_no_reset(&mut self)
When in double-buffered mode, discard any uncommitted changes without resetting the backbuffer contents.
Note that this leaves the backbuffer untouched but marked as not needing to be
transferred. This will make future drawing and committing very inconsistent and should
likely only be used to discard changes prior to dropping the BltDrawTarget.