diff options
Diffstat (limited to 'rsnix/src/gop.rs')
| -rw-r--r-- | rsnix/src/gop.rs | 86 |
1 files changed, 67 insertions, 19 deletions
diff --git a/rsnix/src/gop.rs b/rsnix/src/gop.rs index cddad22..61cc78d 100644 --- a/rsnix/src/gop.rs +++ b/rsnix/src/gop.rs | |||
| @@ -104,25 +104,6 @@ pub fn qr_locked() -> bool { | |||
| 104 | QR_LOCKED.load(Ordering::Relaxed) | 104 | QR_LOCKED.load(Ordering::Relaxed) |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /// Hook invoked after the console scrolls, so the window manager can | ||
| 108 | /// re-composite GUI windows (which sit above the console layer in the | ||
| 109 | /// shadow and must not scroll with it). | ||
| 110 | fn scroll_hook_noop() {} | ||
| 111 | |||
| 112 | static mut SCROLL_HOOK: fn() = scroll_hook_noop; | ||
| 113 | |||
| 114 | pub fn set_scroll_hook(f: fn()) { | ||
| 115 | unsafe { | ||
| 116 | SCROLL_HOOK = f; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | pub(crate) fn call_scroll_hook() { | ||
| 121 | unsafe { | ||
| 122 | SCROLL_HOOK(); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | #[inline] | 107 | #[inline] |
| 127 | fn stall_display() { | 108 | fn stall_display() { |
| 128 | let n = DISPLAY_STALL.load(Ordering::Relaxed); | 109 | let n = DISPLAY_STALL.load(Ordering::Relaxed); |
| @@ -630,6 +611,71 @@ pub(crate) fn shadow_glyph_px(x: usize, y: usize, ch: u16, fg: (u8, u8, u8), bg: | |||
| 630 | } | 611 | } |
| 631 | } | 612 | } |
| 632 | 613 | ||
| 614 | /// Render one 8×16 glyph into a caller-owned pixel buffer (row-major, `w` | ||
| 615 | /// pixels per row). No push — the caller composites the buffer. | ||
| 616 | pub(crate) fn buffer_glyph_px( | ||
| 617 | buf: *mut u32, | ||
| 618 | w: usize, | ||
| 619 | h: usize, | ||
| 620 | x: usize, | ||
| 621 | y: usize, | ||
| 622 | ch: u16, | ||
| 623 | fg: (u8, u8, u8), | ||
| 624 | bg: (u8, u8, u8), | ||
| 625 | ) { | ||
| 626 | if buf.is_null() { | ||
| 627 | return; | ||
| 628 | } | ||
| 629 | let glyph = font::GLYPH_8X16; | ||
| 630 | let data = if ch < 256 { | ||
| 631 | match glyph.get(ch as usize) { | ||
| 632 | Some(d) => *d, | ||
| 633 | None => return, | ||
| 634 | } | ||
| 635 | } else if let Some(bits) = unicode_glyph_bits(ch) { | ||
| 636 | bits | ||
| 637 | } else { | ||
| 638 | match glyph.get(32) { | ||
| 639 | Some(d) => *d, | ||
| 640 | None => return, | ||
| 641 | } | ||
| 642 | }; | ||
| 643 | let fgc = rgb(fg.0, fg.1, fg.2); | ||
| 644 | let bgc = rgb(bg.0, bg.1, bg.2); | ||
| 645 | unsafe { | ||
| 646 | for cy in 0..16 { | ||
| 647 | let py = y + cy; | ||
| 648 | if py >= h { | ||
| 649 | break; | ||
| 650 | } | ||
| 651 | let row_bits = data[cy]; | ||
| 652 | for cx in 0..8 { | ||
| 653 | let px = x + cx; | ||
| 654 | if px >= w { | ||
| 655 | break; | ||
| 656 | } | ||
| 657 | let on = row_bits & (0x80 >> cx) != 0; | ||
| 658 | *buf.add(py * w + px) = if on { fgc } else { bgc }; | ||
| 659 | } | ||
| 660 | } | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | /// Shift a caller-owned pixel buffer up by `px` rows, clearing the exposed | ||
| 665 | /// bottom. No push — the caller composites the buffer. | ||
| 666 | pub(crate) fn buffer_shift_up(buf: *mut u32, w: usize, h: usize, px: usize) { | ||
| 667 | if buf.is_null() || px == 0 || px >= h { | ||
| 668 | return; | ||
| 669 | } | ||
| 670 | unsafe { | ||
| 671 | let n = (h - px) * w; | ||
| 672 | core::ptr::copy(buf.add(px * w), buf, n); // memmove (overlap ok) | ||
| 673 | for i in n..(h * w) { | ||
| 674 | *buf.add(i) = 0; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | } | ||
| 678 | |||
| 633 | /// Print crash/fault lines directly to the framebuffer, bypassing the vt | 679 | /// Print crash/fault lines directly to the framebuffer, bypassing the vt |
| 634 | /// entirely (the vt state may be corrupt when an exception fires). | 680 | /// entirely (the vt state may be corrupt when an exception fires). |
| 635 | /// | 681 | /// |
| @@ -958,6 +1004,7 @@ impl Framebuffer { | |||
| 958 | /// With the RAM backbuffer, this is a cached shadow memcpy + a | 1004 | /// With the RAM backbuffer, this is a cached shadow memcpy + a |
| 959 | /// write-only push to the display — the display itself is never read | 1005 | /// write-only push to the display — the display itself is never read |
| 960 | /// (reads are uncached on real hardware and dominate the old path). | 1006 | /// (reads are uncached on real hardware and dominate the old path). |
| 1007 | #[allow(dead_code)] | ||
| 961 | pub(crate) fn shift_up_n(&self, n: usize) { | 1008 | pub(crate) fn shift_up_n(&self, n: usize) { |
| 962 | let n = n.max(1).min(self.height / 16); // sanity | 1009 | let n = n.max(1).min(self.height / 16); // sanity |
| 963 | let row_bytes = self.pitch * 16; | 1010 | let row_bytes = self.pitch * 16; |
| @@ -1225,6 +1272,7 @@ pub(crate) fn blit_glyph(col: usize, row: usize, ch: u16, fg: (u8, u8, u8), bg: | |||
| 1225 | 1272 | ||
| 1226 | /// Shift the framebuffer content up `n` text rows and clear the exposed | 1273 | /// Shift the framebuffer content up `n` text rows and clear the exposed |
| 1227 | /// bottom rows. `n` batches deferred scrolls into one push. | 1274 | /// bottom rows. `n` batches deferred scrolls into one push. |
| 1275 | #[allow(dead_code)] | ||
| 1228 | pub(crate) fn shift_up_n(n: usize) { | 1276 | pub(crate) fn shift_up_n(n: usize) { |
| 1229 | if let Some(fb) = fb().as_ref() { | 1277 | if let Some(fb) = fb().as_ref() { |
| 1230 | fb.shift_up_n(n); | 1278 | fb.shift_up_n(n); |
