mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-13 07:48:30 +00:00
The `ManagedMem` thing for the suspend/resume crate is simply a disaster. It tries to be fancy and Rusty and really it just fails in non-obvious ways. This is one of the places where it simply does not pay to make things seem so simple. Why? because in reality, memory is complicated. It comes in pages. There's initialization. There's caching. There's volatility. I haven't encountered a single situation where the assumptions of page-alignment and memory layout have really lined up well enough for this primitive to make sense. The "idea" was hey, since you allocate a peripheral MemoryRegion, why not just use its attributes as a marker to a suspend/resume thing that automatically handled stashing that MemoryRegion to a backing store inside RAM? Seems simple right? wrong. Every time I've tried to use it, it's failed in non-obvious ways. In this most recent incarnation, it turns out that for whatever reason, it seems to be just stashing about the first 4-8k of the framebuffer to the SR backup region, and then somehow grabbing a future(?) copy of the memory? or maybe just a wrong copy? I don't know. The code seems simple enough but it goes through some traits and some type transformations and then there's some unsafe code to make it volatile and it doesn't work. Instead, we just use a damn [u32; FB_SIZE] slice to store the frame buffer. This is so obvious and easy. The only price is you have an "ugly" `fb[..FB_SIZE].copy_from_slice(&self.srfb)` line instead of an "elegant" `srfb.suspend()` invocation. Stashing into it is a bit uglier, because we have to cast the slice to an unsafe pointer in order to access the `write_volatile()` method. But, it works! It. Just. Works. And you can see what's going on. Really, I should stop trying to be fancy and just be readable. OK anyways, that was that rant. This commit also adds some calls that allow us to re-use the suspend/resume frame buffer during "normal" times as a stash/pop for the application image. This is nice because the memory is normally idle/overhead when not in suspend, so now we're repurposing some already-allocated memory to accelerate some drawing operations, and it also makes, crucially, a multi-step blocking modal dialog interaction less cosmetically jarring, because the application thread can be fully blocked and not responding to redraw commands but the stash/pop mechanism creates the illusion of "everything is moving along".
192 lines
4.8 KiB
Rust
192 lines
4.8 KiB
Rust
#![allow(dead_code)]
|
|
|
|
/*
|
|
Primitives needed:
|
|
|
|
- clipping rectangles (for drawing)
|
|
- rounded rectangles
|
|
- inverse text
|
|
- icons/sprites
|
|
- width of a text string with a given font (to compute alignments)
|
|
- untrusted backgrounds
|
|
- bitmaps
|
|
|
|
*/
|
|
|
|
//////////////// primitives
|
|
pub mod points;
|
|
pub use points::Point;
|
|
pub mod styles;
|
|
pub use styles::*;
|
|
pub mod shapes;
|
|
pub use shapes::*;
|
|
pub mod text;
|
|
pub use text::*;
|
|
pub mod glyphstyle;
|
|
pub use glyphstyle::*;
|
|
pub mod blitstr2;
|
|
pub use blitstr2::*;
|
|
#[cfg(feature="ditherpunk")]
|
|
pub mod tile;
|
|
#[cfg(feature="ditherpunk")]
|
|
pub use tile::*;
|
|
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
pub const LINES: i16 = 536;
|
|
pub const WIDTH: i16 = 336;
|
|
|
|
//////////////// IPC APIs
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
|
pub struct Gid {
|
|
/// a 128-bit random identifier for graphical objects
|
|
gid: [u32; 4],
|
|
}
|
|
impl Gid {
|
|
pub fn new(id: [u32; 4]) -> Self {
|
|
Gid { gid: id }
|
|
}
|
|
pub fn gid(&self) -> [u32; 4] {
|
|
self.gid
|
|
}
|
|
}
|
|
impl Hash for Gid {
|
|
fn hash<H>(&self, state: &mut H)
|
|
where
|
|
H: Hasher,
|
|
{
|
|
Hash::hash(&self.gid[..], state);
|
|
}
|
|
}
|
|
|
|
pub const SERVER_NAME_GFX: &str = "_Graphics_";
|
|
|
|
#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)]
|
|
pub(crate) enum Opcode {
|
|
/// Flush the buffer to the screen
|
|
Flush,
|
|
|
|
/// Clear the buffer to "light" colored pixels
|
|
Clear,
|
|
|
|
/// Draw a line at the specified area
|
|
Line, //(Line),
|
|
|
|
/// Draw a rectangle or square at the specified coordinates
|
|
Rectangle, //(Rectangle),
|
|
|
|
/// Draw a rounded rectangle
|
|
RoundedRectangle, //(RoundedRectangle),
|
|
|
|
/// Paint a Bitmap Tile
|
|
#[cfg(feature="ditherpunk")]
|
|
Tile,
|
|
|
|
/// Draw a circle with a specified radius
|
|
Circle, //(Circle),
|
|
|
|
/// Retrieve the X and Y dimensions of the screen
|
|
ScreenSize,
|
|
|
|
/// gets info about the current glyph to assist with layout
|
|
QueryGlyphProps, //(GlyphStyle),
|
|
|
|
/// draws a textview
|
|
DrawTextView, //(TextView),
|
|
|
|
/// draws an object that requires clipping
|
|
DrawClipObject, //(ClipObject),
|
|
DrawClipObjectList,
|
|
|
|
/// draws the sleep screen; assumes requests are vetted by GAM/xous-names
|
|
DrawSleepScreen,
|
|
|
|
/// permanently turns on the Devboot mark
|
|
Devboot,
|
|
|
|
/// bulk read for signature verifications
|
|
BulkReadFonts,
|
|
RestartBulkRead,
|
|
|
|
/// sling the framebuffer into and out of the suspend/resume area, abusing this
|
|
/// to help accelerate redraws between modal swaps.
|
|
Stash,
|
|
Pop,
|
|
|
|
/// generates a test pattern
|
|
TestPattern,
|
|
|
|
/// SuspendResume callback
|
|
SuspendResume,
|
|
|
|
Quit,
|
|
}
|
|
|
|
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
|
pub enum ClipObjectType {
|
|
Line(Line),
|
|
Circ(Circle),
|
|
Rect(Rectangle),
|
|
RoundRect(RoundedRectangle),
|
|
XorLine(Line),
|
|
#[cfg(feature="ditherpunk")]
|
|
Tile(Tile),
|
|
}
|
|
|
|
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
|
pub struct ClipObject {
|
|
pub clip: Rectangle,
|
|
pub obj: ClipObjectType,
|
|
}
|
|
|
|
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
|
pub struct ClipObjectList {
|
|
// ClipObject is 28 bytes, so 32 of these takes 896 bytes, which is less than a 4k page (the minimum amount that gets remapped)
|
|
// we limit the length to 32 so we can use the Default initializer to set the None's on the array, otherwise it gets a bit painful.
|
|
pub list: [Option::<ClipObject>; 32],
|
|
free: usize,
|
|
}
|
|
impl ClipObjectList {
|
|
pub fn default() -> ClipObjectList {
|
|
ClipObjectList {
|
|
list: Default::default(),
|
|
free: 0,
|
|
}
|
|
}
|
|
pub fn push(&mut self, item: ClipObjectType, clip: Rectangle) -> Result<(), ClipObjectType> {
|
|
if self.free < self.list.len() {
|
|
self.list[self.free] = Some(ClipObject {clip, obj: item});
|
|
self.free += 1;
|
|
Ok(())
|
|
} else {
|
|
Err(item)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
|
pub struct TokenClaim {
|
|
pub token: Option<[u32; 4]>,
|
|
pub name: xous_ipc::String<128>,
|
|
}
|
|
|
|
/// the buffer length of this equal to the internal length passed by the
|
|
/// engine-sha512 implementation times 2 (a small amount of overhead is required
|
|
/// out of an even 4096 page for bookkeeping). We could make this a neat power of 2,
|
|
/// but then you'd end up doing an extra memory message for the overhead bits that
|
|
/// are left over.
|
|
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
|
pub struct BulkRead {
|
|
pub buf: [u8; 7936],
|
|
pub from_offset: u32,
|
|
pub len: u32, // used to return the length read out of the font map
|
|
}
|
|
impl BulkRead {
|
|
pub fn default() -> BulkRead {
|
|
BulkRead {
|
|
buf: [0; 7936],
|
|
from_offset: 0,
|
|
len: 7936,
|
|
}
|
|
}
|
|
}
|