From e5fdbde0ddc0d53fb96ab336556c22178a6cb16f Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Mon, 22 May 2023 00:34:58 +0200 Subject: [PATCH] uefi(gop): add a embedded_graphics_core::DrawTarget for (a wrapper of) GraphicsOutput Given that PixelFormat for UEFI is dynamic and DrawTarget needs it to be static. We (anyway) need to bridge the gap by asserting this dynamically and providing API to create the best wrapper. In some cases, we might even need to convert the pixel to the target format by relying on Blt or similar. --- Cargo.lock | 18 +++++++++ uefi/Cargo.toml | 5 ++- uefi/src/proto/console/draw_target.rs | 54 +++++++++++++++++++++++++++ uefi/src/proto/console/mod.rs | 2 + 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 uefi/src/proto/console/draw_target.rs diff --git a/Cargo.lock b/Cargo.lock index d9b163fe4..55ced166a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "basic-toml" version = "0.1.2" @@ -135,6 +141,16 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "embedded-graphics-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba9ecd261f991856250d2207f6d8376946cd9f412a2165d3b75bc87a0bc7a044" +dependencies = [ + "az", + "byteorder", +] + [[package]] name = "errno" version = "0.3.1" @@ -550,6 +566,7 @@ name = "uefi" version = "0.21.0" dependencies = [ "bitflags 2.3.1", + "embedded-graphics-core", "log", "ptr_meta", "ucs2", @@ -583,6 +600,7 @@ name = "uefi-services" version = "0.18.0" dependencies = [ "cfg-if", + "embedded-graphics-core", "log", "qemu-exit", "uefi", diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml index 4f6858ade..4d7985d4e 100644 --- a/uefi/Cargo.toml +++ b/uefi/Cargo.toml @@ -12,7 +12,7 @@ license = "MPL-2.0" rust-version = "1.68" [features] -default = ["panic-on-logger-errors"] +default = ["panic-on-logger-errors", "draw_target"] alloc = [] global_allocator = [] logger = [] @@ -20,11 +20,14 @@ logger = [] # were observed on the VirtualBox UEFI implementation (see uefi-rs#121). # In those cases, this feature can be excluded by removing the default features. panic-on-logger-errors = [] +# DrawTarget for GOP protocol +draw_target = ["embedded-graphics-core"] # Generic gate to code that uses unstable features of Rust. You usually need a nightly toolchain. unstable = [] [dependencies] bitflags = "2.0.0" +embedded-graphics-core = { version = "0.4.0", optional = true } log = { version = "0.4.5", default-features = false } ptr_meta = { version = "0.2.0", default-features = false } ucs2 = "0.3.2" diff --git a/uefi/src/proto/console/draw_target.rs b/uefi/src/proto/console/draw_target.rs new file mode 100644 index 000000000..4dd033e8c --- /dev/null +++ b/uefi/src/proto/console/draw_target.rs @@ -0,0 +1,54 @@ +use embedded_graphics_core::prelude::{DrawTarget, OriginDimensions, Size, PixelColor, Pixel, IntoStorage}; + +use super::gop::GraphicsOutput; + +// FIXME: offer conversions from C to current pixel color format? +struct GraphicsDisplay { + color: C, + gop: GraphicsOutput +} + +impl OriginDimensions for GraphicsOutput { + fn size(&self) -> embedded_graphics_core::prelude::Size { + let (width, height) = self.current_mode_info().resolution(); + + Size::from((width as u32, height as u32)) + } +} + +impl OriginDimensions for GraphicsDisplay { + fn size(&self) -> Size { + self.gop.size() + } +} + +impl DrawTarget for GraphicsDisplay { + type Color = C; + type Error = uefi::Error; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator> { + let stride = self.gop.current_mode_info().stride() as u64; + for Pixel(point, color) in pixels.into_iter() { + let bytes = color.into_storage(); + let (x, y) = (point.x as u64, point.y as u64); + let index: usize = (((y * stride) + x) * 4) + .try_into() + .map_err(|_| + uefi::Error::from( + uefi::Status::UNSUPPORTED + ) + )?; + + unsafe { + self.gop.frame_buffer().write_value(index, bytes); + } + } + + Ok(()) + } + + // FIXME: provide a blt technique for fill_solid + // FIXME: fallback to blt when pixelformat is blt-only. +} diff --git a/uefi/src/proto/console/mod.rs b/uefi/src/proto/console/mod.rs index 636eb77b4..b7a37f662 100644 --- a/uefi/src/proto/console/mod.rs +++ b/uefi/src/proto/console/mod.rs @@ -7,3 +7,5 @@ pub mod gop; pub mod pointer; pub mod serial; pub mod text; +#[cfg(feature = "draw_target")] +pub mod draw_target;