1use core::{convert::Infallible, marker::PhantomData};
16
17use crate::{Color, FrameBuffer, FrameBufferOperations, MutableFrameBuffer, WordSize};
18use embedded_dma::ReadBuffer;
19use embedded_graphics::prelude::{DrawTarget, OriginDimensions, PixelColor, Point, Size};
20
21#[must_use]
32pub const fn compute_tiled_cols(
33 cols: usize,
34 num_panels_wide: usize,
35 num_panels_high: usize,
36) -> usize {
37 cols * num_panels_wide * num_panels_high
38}
39
40pub trait PixelRemapper {
52 const VIRT_ROWS: usize;
54 const VIRT_COLS: usize;
56 const FB_ROWS: usize;
58 const FB_COLS: usize;
60
61 #[inline]
63 fn remap<C: PixelColor>(mut pixel: embedded_graphics::Pixel<C>) -> embedded_graphics::Pixel<C> {
64 pixel.0 = Self::remap_point(pixel.0);
65 pixel
66 }
67
68 #[inline]
70 #[must_use]
71 fn remap_point(mut point: Point) -> Point {
72 if point.x < 0 || point.y < 0 {
73 return point;
75 }
76 let (re_x, re_y) = Self::remap_xy(point.x as usize, point.y as usize);
77 point.x = i32::from(re_x as u16);
79 point.y = i32::from(re_y as u16);
80 point
81 }
82
83 fn remap_xy(x: usize, y: usize) -> (usize, usize);
85
86 #[inline]
88 #[must_use]
89 fn virtual_size() -> (usize, usize) {
90 (Self::VIRT_ROWS, Self::VIRT_COLS)
91 }
92
93 #[inline]
95 #[must_use]
96 fn fb_size() -> (usize, usize) {
97 (Self::FB_ROWS, Self::FB_COLS)
98 }
99}
100
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118#[derive(core::fmt::Debug)]
119pub struct ChainTopRightDown<
120 const PANEL_ROWS: usize,
121 const PANEL_COLS: usize,
122 const TILE_ROWS: usize,
123 const TILE_COLS: usize,
124> {}
125
126impl<
127 const PANEL_ROWS: usize,
128 const PANEL_COLS: usize,
129 const TILE_ROWS: usize,
130 const TILE_COLS: usize,
131 > PixelRemapper for ChainTopRightDown<PANEL_ROWS, PANEL_COLS, TILE_ROWS, TILE_COLS>
132{
133 const VIRT_ROWS: usize = PANEL_ROWS * TILE_ROWS;
134 const VIRT_COLS: usize = PANEL_COLS * TILE_COLS;
135 const FB_ROWS: usize = PANEL_ROWS;
136 const FB_COLS: usize = PANEL_COLS * TILE_ROWS * TILE_COLS;
137
138 fn remap_xy(x: usize, y: usize) -> (usize, usize) {
139 let row = y / PANEL_ROWS;
141 let base = (TILE_ROWS - 1 - row) * Self::VIRT_COLS;
142
143 if row % 2 == 1 {
144 (
146 base + Self::VIRT_COLS - 1 - x, PANEL_ROWS - 1 - (y % PANEL_ROWS), )
149 } else {
150 (base + x, y % PANEL_ROWS) }
152 }
153}
154
155#[cfg_attr(feature = "defmt", derive(defmt::Format))]
182#[derive(core::fmt::Debug)]
183pub struct QuarterScan<const PANEL_ROWS: usize, const PANEL_COLS: usize> {}
184
185impl<const PANEL_ROWS: usize, const PANEL_COLS: usize> PixelRemapper
186 for QuarterScan<PANEL_ROWS, PANEL_COLS>
187{
188 const VIRT_ROWS: usize = PANEL_ROWS;
189 const VIRT_COLS: usize = PANEL_COLS;
190 const FB_ROWS: usize = PANEL_ROWS / 4;
191 const FB_COLS: usize = PANEL_COLS * 4;
192
193 fn remap_xy(_x: usize, _y: usize) -> (usize, usize) {
194 todo!("implement for your panel's specific row interleaving pattern")
195 }
196}
197
198#[deprecated(
249 since = "0.11.0",
250 note = "use RemappedFrameBuffer<F, M> instead -- it works with all framebuffer types and has a simpler signature"
251)]
252#[derive(core::fmt::Debug)]
253pub struct TiledFrameBuffer<
254 F,
255 M: PixelRemapper,
256 const PANEL_ROWS: usize,
257 const PANEL_COLS: usize,
258 const NROWS: usize,
259 const BITS: u8,
260 const FRAME_COUNT: usize,
261 const TILE_ROWS: usize,
262 const TILE_COLS: usize,
263 const FB_COLS: usize,
264>(F, PhantomData<M>);
265
266#[allow(deprecated)]
267impl<
268 F: Default,
269 M: PixelRemapper,
270 const PANEL_ROWS: usize,
271 const PANEL_COLS: usize,
272 const NROWS: usize,
273 const BITS: u8,
274 const FRAME_COUNT: usize,
275 const TILE_ROWS: usize,
276 const TILE_COLS: usize,
277 const FB_COLS: usize,
278 >
279 TiledFrameBuffer<
280 F,
281 M,
282 PANEL_ROWS,
283 PANEL_COLS,
284 NROWS,
285 BITS,
286 FRAME_COUNT,
287 TILE_ROWS,
288 TILE_COLS,
289 FB_COLS,
290 >
291{
292 #[must_use]
296 pub fn new() -> Self {
297 Self(F::default(), PhantomData)
298 }
299}
300
301#[allow(deprecated)]
302impl<
303 F: Default,
304 M: PixelRemapper,
305 const PANEL_ROWS: usize,
306 const PANEL_COLS: usize,
307 const NROWS: usize,
308 const BITS: u8,
309 const FRAME_COUNT: usize,
310 const TILE_ROWS: usize,
311 const TILE_COLS: usize,
312 const FB_COLS: usize,
313 > Default
314 for TiledFrameBuffer<
315 F,
316 M,
317 PANEL_ROWS,
318 PANEL_COLS,
319 NROWS,
320 BITS,
321 FRAME_COUNT,
322 TILE_ROWS,
323 TILE_COLS,
324 FB_COLS,
325 >
326{
327 fn default() -> Self {
328 Self::new()
329 }
330}
331
332#[allow(deprecated)]
333impl<
334 F: DrawTarget<Error = Infallible, Color = Color>,
335 M: PixelRemapper,
336 const PANEL_ROWS: usize,
337 const PANEL_COLS: usize,
338 const NROWS: usize,
339 const BITS: u8,
340 const FRAME_COUNT: usize,
341 const TILE_ROWS: usize,
342 const TILE_COLS: usize,
343 const FB_COLS: usize,
344 > DrawTarget
345 for TiledFrameBuffer<
346 F,
347 M,
348 PANEL_ROWS,
349 PANEL_COLS,
350 NROWS,
351 BITS,
352 FRAME_COUNT,
353 TILE_ROWS,
354 TILE_COLS,
355 FB_COLS,
356 >
357{
358 type Color = Color;
359 type Error = Infallible;
360
361 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
362 where
363 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
364 {
365 self.0.draw_iter(pixels.into_iter().map(M::remap))
366 }
367}
368
369#[allow(deprecated)]
370impl<
371 F: DrawTarget<Error = Infallible, Color = Color>,
372 M: PixelRemapper,
373 const PANEL_ROWS: usize,
374 const PANEL_COLS: usize,
375 const NROWS: usize,
376 const BITS: u8,
377 const FRAME_COUNT: usize,
378 const TILE_ROWS: usize,
379 const TILE_COLS: usize,
380 const FB_COLS: usize,
381 > OriginDimensions
382 for TiledFrameBuffer<
383 F,
384 M,
385 PANEL_ROWS,
386 PANEL_COLS,
387 NROWS,
388 BITS,
389 FRAME_COUNT,
390 TILE_ROWS,
391 TILE_COLS,
392 FB_COLS,
393 >
394{
395 fn size(&self) -> Size {
396 Size::new(M::virtual_size().1 as u32, M::virtual_size().0 as u32)
397 }
398}
399
400#[allow(deprecated)]
401impl<
402 F: FrameBufferOperations + FrameBuffer,
403 M: PixelRemapper,
404 const PANEL_ROWS: usize,
405 const PANEL_COLS: usize,
406 const NROWS: usize,
407 const BITS: u8,
408 const FRAME_COUNT: usize,
409 const TILE_ROWS: usize,
410 const TILE_COLS: usize,
411 const FB_COLS: usize,
412 > FrameBufferOperations
413 for TiledFrameBuffer<
414 F,
415 M,
416 PANEL_ROWS,
417 PANEL_COLS,
418 NROWS,
419 BITS,
420 FRAME_COUNT,
421 TILE_ROWS,
422 TILE_COLS,
423 FB_COLS,
424 >
425{
426 #[inline]
427 fn erase(&mut self) {
428 self.0.erase();
429 }
430
431 #[inline]
432 fn set_pixel(&mut self, p: Point, color: Color) {
433 self.0.set_pixel(M::remap_point(p), color);
434 }
435}
436
437#[allow(deprecated)]
438unsafe impl<
439 T,
440 F: ReadBuffer<Word = T>,
441 M: PixelRemapper,
442 const PANEL_ROWS: usize,
443 const PANEL_COLS: usize,
444 const NROWS: usize,
445 const BITS: u8,
446 const FRAME_COUNT: usize,
447 const TILE_ROWS: usize,
448 const TILE_COLS: usize,
449 const FB_COLS: usize,
450 > ReadBuffer
451 for TiledFrameBuffer<
452 F,
453 M,
454 PANEL_ROWS,
455 PANEL_COLS,
456 NROWS,
457 BITS,
458 FRAME_COUNT,
459 TILE_ROWS,
460 TILE_COLS,
461 FB_COLS,
462 >
463{
464 type Word = T;
465
466 unsafe fn read_buffer(&self) -> (*const T, usize) {
467 self.0.read_buffer()
468 }
469}
470
471#[allow(deprecated)]
472impl<
473 F: FrameBuffer,
474 M: PixelRemapper,
475 const PANEL_ROWS: usize,
476 const PANEL_COLS: usize,
477 const NROWS: usize,
478 const BITS: u8,
479 const FRAME_COUNT: usize,
480 const TILE_ROWS: usize,
481 const TILE_COLS: usize,
482 const FB_COLS: usize,
483 > FrameBuffer
484 for TiledFrameBuffer<
485 F,
486 M,
487 PANEL_ROWS,
488 PANEL_COLS,
489 NROWS,
490 BITS,
491 FRAME_COUNT,
492 TILE_ROWS,
493 TILE_COLS,
494 FB_COLS,
495 >
496{
497 type Word = F::Word;
498
499 fn get_word_size(&self) -> WordSize {
500 self.0.get_word_size()
501 }
502
503 fn plane_count(&self) -> usize {
504 self.0.plane_count()
505 }
506
507 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
508 self.0.plane_ptr_len(plane_idx)
509 }
510}
511
512#[allow(deprecated)]
513impl<
514 F: MutableFrameBuffer,
515 M: PixelRemapper,
516 const PANEL_ROWS: usize,
517 const PANEL_COLS: usize,
518 const NROWS: usize,
519 const BITS: u8,
520 const FRAME_COUNT: usize,
521 const TILE_ROWS: usize,
522 const TILE_COLS: usize,
523 const FB_COLS: usize,
524 > MutableFrameBuffer
525 for TiledFrameBuffer<
526 F,
527 M,
528 PANEL_ROWS,
529 PANEL_COLS,
530 NROWS,
531 BITS,
532 FRAME_COUNT,
533 TILE_ROWS,
534 TILE_COLS,
535 FB_COLS,
536 >
537{
538}
539
540#[cfg(feature = "defmt")]
541#[allow(deprecated)]
542impl<
543 F: defmt::Format,
544 M: PixelRemapper,
545 const PANEL_ROWS: usize,
546 const PANEL_COLS: usize,
547 const NROWS: usize,
548 const BITS: u8,
549 const FRAME_COUNT: usize,
550 const TILE_ROWS: usize,
551 const TILE_COLS: usize,
552 const FB_COLS: usize,
553 > defmt::Format
554 for TiledFrameBuffer<
555 F,
556 M,
557 PANEL_ROWS,
558 PANEL_COLS,
559 NROWS,
560 BITS,
561 FRAME_COUNT,
562 TILE_ROWS,
563 TILE_COLS,
564 FB_COLS,
565 >
566{
567 fn format(&self, fmt: defmt::Formatter) {
568 defmt::write!(fmt, "TiledFrameBuffer({:?})", self.0);
569 }
570}
571
572#[cfg_attr(feature = "defmt", derive(defmt::Format))]
634#[derive(core::fmt::Debug)]
635pub struct RemappedFrameBuffer<F, M: PixelRemapper>(F, PhantomData<M>);
636
637impl<F: Default, M: PixelRemapper> RemappedFrameBuffer<F, M> {
638 #[must_use]
642 pub fn new() -> Self {
643 Self(F::default(), PhantomData)
644 }
645}
646
647impl<F: Default, M: PixelRemapper> Default for RemappedFrameBuffer<F, M> {
648 fn default() -> Self {
649 Self::new()
650 }
651}
652
653impl<F: DrawTarget<Error = Infallible, Color = Color>, M: PixelRemapper> DrawTarget
654 for RemappedFrameBuffer<F, M>
655{
656 type Color = Color;
657 type Error = Infallible;
658
659 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
660 where
661 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
662 {
663 self.0.draw_iter(pixels.into_iter().map(M::remap))
664 }
665}
666
667impl<F: DrawTarget<Error = Infallible, Color = Color>, M: PixelRemapper> OriginDimensions
668 for RemappedFrameBuffer<F, M>
669{
670 fn size(&self) -> Size {
671 Size::new(M::virtual_size().1 as u32, M::virtual_size().0 as u32)
672 }
673}
674
675impl<F: FrameBufferOperations + FrameBuffer, M: PixelRemapper> FrameBufferOperations
676 for RemappedFrameBuffer<F, M>
677{
678 #[inline]
679 fn erase(&mut self) {
680 self.0.erase();
681 }
682
683 #[inline]
684 fn set_pixel(&mut self, p: Point, color: Color) {
685 self.0.set_pixel(M::remap_point(p), color);
686 }
687}
688
689unsafe impl<T, F: ReadBuffer<Word = T>, M: PixelRemapper> ReadBuffer for RemappedFrameBuffer<F, M> {
690 type Word = T;
691
692 unsafe fn read_buffer(&self) -> (*const T, usize) {
693 self.0.read_buffer()
694 }
695}
696
697impl<F: FrameBuffer, M: PixelRemapper> FrameBuffer for RemappedFrameBuffer<F, M> {
698 type Word = F::Word;
699
700 fn get_word_size(&self) -> WordSize {
701 self.0.get_word_size()
702 }
703
704 fn plane_count(&self) -> usize {
705 self.0.plane_count()
706 }
707
708 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
709 self.0.plane_ptr_len(plane_idx)
710 }
711}
712
713impl<F: MutableFrameBuffer, M: PixelRemapper> MutableFrameBuffer for RemappedFrameBuffer<F, M> {}
714
715#[cfg(test)]
716mod tests {
717 extern crate std;
718
719 use embedded_graphics::prelude::*;
720
721 use super::*;
722 use crate::MutableFrameBuffer;
723 use core::convert::Infallible;
724
725 #[test]
726 fn test_virtual_size_function_with_equal_rows_and_cols() {
727 const ROWS_IN_PANEL: usize = 32;
728 const COLS_IN_PANEL: usize = 64;
729 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 3, 3>;
730 let virt_size = PanelChain::virtual_size();
731 assert_eq!(virt_size, (ROWS_IN_PANEL * 3, COLS_IN_PANEL * 3));
732 }
733
734 #[test]
735 fn test_virtual_size_function_with_uneven_rows_and_cols() {
736 const ROWS_IN_PANEL: usize = 32;
737 const COLS_IN_PANEL: usize = 64;
738 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 5, 3>;
739 let virt_size = PanelChain::virtual_size();
740 assert_eq!(virt_size, (ROWS_IN_PANEL * 5, COLS_IN_PANEL * 3));
741 }
742
743 #[test]
744 fn test_virtual_size_function_with_single_column() {
745 const ROWS_IN_PANEL: usize = 32;
746 const COLS_IN_PANEL: usize = 64;
747 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 3, 1>;
748 let virt_size = PanelChain::virtual_size();
749 assert_eq!(virt_size, (ROWS_IN_PANEL * 3, COLS_IN_PANEL));
750 }
751
752 #[test]
753 fn test_fb_size_function_with_equal_rows_and_cols() {
754 const ROWS_IN_PANEL: usize = 32;
755 const COLS_IN_PANEL: usize = 64;
756 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 3, 3>;
757 let virt_size = PanelChain::fb_size();
758 assert_eq!(virt_size, (ROWS_IN_PANEL, COLS_IN_PANEL * 9));
759 }
760
761 #[test]
762 fn test_fb_size_function_with_uneven_rows_and_cols() {
763 const ROWS_IN_PANEL: usize = 32;
764 const COLS_IN_PANEL: usize = 64;
765 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 5, 3>;
766 let virt_size = PanelChain::fb_size();
767 assert_eq!(virt_size, (ROWS_IN_PANEL, COLS_IN_PANEL * 15));
768 }
769
770 #[test]
771 fn test_fb_size_function_with_single_column() {
772 const ROWS_IN_PANEL: usize = 32;
773 const COLS_IN_PANEL: usize = 64;
774 type PanelChain = ChainTopRightDown<ROWS_IN_PANEL, COLS_IN_PANEL, 3, 1>;
775 let virt_size = PanelChain::fb_size();
776 assert_eq!(virt_size, (ROWS_IN_PANEL, COLS_IN_PANEL * 3));
777 }
778
779 #[test]
780 fn test_pixel_remap_top_right_down_point_in_origin() {
781 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
782
783 let pixel = PanelChain::remap(Pixel(Point::new(0, 0), Color::RED));
784 assert_eq!(pixel.0, Point::new(384, 0));
785 }
786
787 #[test]
788 fn test_pixel_remap_top_right_down_point_in_bottom_left_corner() {
789 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
790
791 let pixel = PanelChain::remap(Pixel(Point::new(0, 95), Color::RED));
792 assert_eq!(pixel.0, Point::new(0, 31));
793 }
794
795 #[test]
796 fn test_pixel_remap_top_right_down_point_in_bottom_right_corner() {
797 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
798
799 let pixel = PanelChain::remap(Pixel(Point::new(191, 95), Color::RED));
800 assert_eq!(pixel.0, Point::new(191, 31));
801 }
802
803 #[test]
804 fn test_pixel_remap_top_right_down_point_on_x_right_edge_of_first_panel() {
805 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
806
807 let pixel = PanelChain::remap(Pixel(Point::new(63, 0), Color::RED));
808 assert_eq!(pixel.0, Point::new(447, 0));
809 }
810
811 #[test]
812 fn test_pixel_remap_top_right_down_point_on_x_left_edge_of_second_panel() {
813 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
814
815 let pixel = PanelChain::remap(Pixel(Point::new(64, 0), Color::RED));
816 assert_eq!(pixel.0, Point::new(448, 0));
817 }
818
819 #[test]
820 fn test_pixel_remap_top_right_down_point_on_y_bottom_edge_of_first_panel() {
821 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
822
823 let pixel = PanelChain::remap(Pixel(Point::new(0, 31), Color::RED));
824 assert_eq!(pixel.0, Point::new(384, 31));
825 }
826
827 #[test]
828 fn test_pixel_remap_top_right_down_point_on_y_top_edge_of_fourth_panel() {
829 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
830
831 let pixel = PanelChain::remap(Pixel(Point::new(0, 32), Color::RED));
832 assert_eq!(pixel.0, Point::new(383, 31));
833 }
834
835 #[test]
836 fn test_pixel_remap_top_right_down_point_slightly_to_the_top_middle() {
837 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
838
839 let pixel = PanelChain::remap(Pixel(Point::new(100, 40), Color::RED));
840 assert_eq!(pixel.0, Point::new(283, 23));
841 }
842
843 #[test]
844 fn test_pixel_remap_negative_pixel_does_not_remap() {
845 type PanelChain = ChainTopRightDown<32, 64, 3, 3>;
846
847 let pixel = PanelChain::remap(Pixel(Point::new(-5, 40), Color::RED));
848 assert_eq!(pixel.0, Point::new(-5, 40));
849 }
850
851 #[test]
852 fn test_compute_tiled_cols() {
853 assert_eq!(192, compute_tiled_cols(32, 3, 2));
854 }
855
856 #[test]
857 #[allow(deprecated)]
858 fn test_tiling_framebuffer_canvas_size() {
859 use crate::plain::DmaFrameBuffer;
860 use crate::tiling::{compute_tiled_cols, ChainTopRightDown, TiledFrameBuffer};
861 use crate::{compute_frame_count, compute_rows};
862
863 const TILED_COLS: usize = 3;
864 const TILED_ROWS: usize = 3;
865 const ROWS: usize = 32;
866 const PANEL_COLS: usize = 64;
867 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
868 const BITS: u8 = 2;
869 const NROWS: usize = compute_rows(ROWS);
870 const FRAME_COUNT: usize = compute_frame_count(BITS);
871
872 type FBType = DmaFrameBuffer<ROWS, FB_COLS, NROWS, BITS, FRAME_COUNT>;
873 type TiledFBType = TiledFrameBuffer<
874 FBType,
875 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
876 ROWS,
877 PANEL_COLS,
878 NROWS,
879 BITS,
880 FRAME_COUNT,
881 TILED_ROWS,
882 TILED_COLS,
883 FB_COLS,
884 >;
885
886 let fb = TiledFBType::new();
887
888 assert_eq!(fb.size(), Size::new(192, 96));
889 }
890
891 struct TestFrameBuffer {
893 calls: std::cell::RefCell<std::vec::Vec<Call>>,
894 buf: [u8; 8],
895 }
896
897 #[derive(Debug, Clone, PartialEq, Eq)]
898 enum Call {
899 Erase,
900 SetPixel { p: Point, color: Color },
901 Draw(std::vec::Vec<(Point, Color)>),
902 }
903
904 impl TestFrameBuffer {
905 fn new() -> Self {
906 Self {
907 calls: std::cell::RefCell::new(std::vec::Vec::new()),
908 buf: [0; 8],
909 }
910 }
911
912 fn take_calls(&self) -> std::vec::Vec<Call> {
913 core::mem::take(&mut *self.calls.borrow_mut())
914 }
915 }
916
917 impl Default for TestFrameBuffer {
918 fn default() -> Self {
919 Self::new()
920 }
921 }
922
923 impl DrawTarget for TestFrameBuffer {
924 type Color = Color;
925 type Error = Infallible;
926
927 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
928 where
929 I: IntoIterator<Item = Pixel<Self::Color>>,
930 {
931 let v = pixels.into_iter().map(|p| (p.0, p.1)).collect();
932 self.calls.borrow_mut().push(Call::Draw(v));
933 Ok(())
934 }
935 }
936
937 impl OriginDimensions for TestFrameBuffer {
938 fn size(&self) -> Size {
939 Size::new(1, 1)
940 }
941 }
942
943 impl FrameBuffer for TestFrameBuffer {
944 type Word = u8;
945
946 fn plane_count(&self) -> usize {
947 1
948 }
949
950 fn plane_ptr_len(&self, _plane_idx: usize) -> (*const u8, usize) {
951 (self.buf.as_ptr(), self.buf.len())
952 }
953 }
954
955 impl FrameBufferOperations for TestFrameBuffer {
956 fn erase(&mut self) {
957 self.calls.borrow_mut().push(Call::Erase);
958 }
959
960 fn set_pixel(&mut self, p: Point, color: Color) {
961 self.calls.borrow_mut().push(Call::SetPixel { p, color });
962 }
963 }
964
965 impl MutableFrameBuffer for TestFrameBuffer {}
966
967 unsafe impl embedded_dma::ReadBuffer for TestFrameBuffer {
968 type Word = u8;
969
970 unsafe fn read_buffer(&self) -> (*const u8, usize) {
971 (self.buf.as_ptr(), self.buf.len())
972 }
973 }
974
975 #[test]
976 #[allow(deprecated)]
977 fn test_tiled_draw_iter_forwards_with_remap() {
978 const TILED_COLS: usize = 3;
979 const TILED_ROWS: usize = 3;
980 const ROWS: usize = 32;
981 const PANEL_COLS: usize = 64;
982 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
983
984 let mut fb = TiledFrameBuffer::<
985 TestFrameBuffer,
986 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
987 ROWS,
988 PANEL_COLS,
989 { crate::compute_rows(ROWS) },
990 2,
991 { crate::compute_frame_count(2) },
992 TILED_ROWS,
993 TILED_COLS,
994 FB_COLS,
995 >(TestFrameBuffer::new(), core::marker::PhantomData);
996
997 let input = [
998 Pixel(Point::new(0, 0), Color::RED),
999 Pixel(Point::new(63, 0), Color::GREEN),
1000 Pixel(Point::new(64, 0), Color::BLUE),
1001 Pixel(Point::new(100, 40), Color::WHITE),
1002 ];
1003
1004 fb.draw_iter(input.into_iter()).unwrap();
1005
1006 let calls = fb.0.take_calls();
1007 assert_eq!(calls.len(), 1);
1008 match &calls[0] {
1009 Call::Draw(v) => {
1010 let expected =
1011 [
1012 ChainTopRightDown::<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>::remap(
1013 Pixel(Point::new(0, 0), Color::RED),
1014 ),
1015 ChainTopRightDown::<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>::remap(
1016 Pixel(Point::new(63, 0), Color::GREEN),
1017 ),
1018 ChainTopRightDown::<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>::remap(
1019 Pixel(Point::new(64, 0), Color::BLUE),
1020 ),
1021 ChainTopRightDown::<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>::remap(
1022 Pixel(Point::new(100, 40), Color::WHITE),
1023 ),
1024 ];
1025 let expected_points: std::vec::Vec<(Point, Color)> =
1026 expected.iter().map(|p| (p.0, p.1)).collect();
1027 assert_eq!(v.as_slice(), expected_points.as_slice());
1028 }
1029 _ => panic!("expected a Draw call"),
1030 }
1031 }
1032
1033 #[test]
1034 #[allow(deprecated)]
1035 fn test_tiled_set_pixel_remaps_and_forwards() {
1036 const TILED_COLS: usize = 3;
1037 const TILED_ROWS: usize = 3;
1038 const ROWS: usize = 32;
1039 const PANEL_COLS: usize = 64;
1040 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1041
1042 let mut fb = TiledFrameBuffer::<
1043 TestFrameBuffer,
1044 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1045 ROWS,
1046 PANEL_COLS,
1047 { crate::compute_rows(ROWS) },
1048 2,
1049 { crate::compute_frame_count(2) },
1050 TILED_ROWS,
1051 TILED_COLS,
1052 FB_COLS,
1053 >(TestFrameBuffer::new(), core::marker::PhantomData);
1054
1055 let p = Point::new(100, 40);
1056 fb.set_pixel(p, Color::BLUE);
1057
1058 let calls = fb.0.take_calls();
1059 assert_eq!(calls.len(), 1);
1060 match calls.into_iter().next().unwrap() {
1061 Call::SetPixel { p: rp, color } => {
1062 let expected =
1063 ChainTopRightDown::<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>::remap_point(p);
1064 assert_eq!(rp, expected);
1065 assert_eq!(color, Color::BLUE);
1066 }
1067 _ => panic!("expected a SetPixel call"),
1068 }
1069 }
1070
1071 #[test]
1072 #[allow(deprecated)]
1073 fn test_tiled_erase_forwards() {
1074 const TILED_COLS: usize = 2;
1075 const TILED_ROWS: usize = 2;
1076 const ROWS: usize = 32;
1077 const PANEL_COLS: usize = 64;
1078 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1079
1080 let mut fb = TiledFrameBuffer::<
1081 TestFrameBuffer,
1082 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1083 ROWS,
1084 PANEL_COLS,
1085 { crate::compute_rows(ROWS) },
1086 2,
1087 { crate::compute_frame_count(2) },
1088 TILED_ROWS,
1089 TILED_COLS,
1090 FB_COLS,
1091 >(TestFrameBuffer::new(), core::marker::PhantomData);
1092 fb.erase();
1093 let calls = fb.0.take_calls();
1094 assert_eq!(calls, std::vec![Call::Erase]);
1095 }
1096
1097 #[test]
1098 #[allow(deprecated)]
1099 fn test_tiled_negative_coordinates_not_remapped() {
1100 const TILED_COLS: usize = 2;
1101 const TILED_ROWS: usize = 2;
1102 const ROWS: usize = 32;
1103 const PANEL_COLS: usize = 64;
1104 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1105
1106 let mut fb = TiledFrameBuffer::<
1107 TestFrameBuffer,
1108 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1109 ROWS,
1110 PANEL_COLS,
1111 { crate::compute_rows(ROWS) },
1112 2,
1113 { crate::compute_frame_count(2) },
1114 TILED_ROWS,
1115 TILED_COLS,
1116 FB_COLS,
1117 >(TestFrameBuffer::new(), core::marker::PhantomData);
1118
1119 let neg = Point::new(-3, 5);
1121 fb.set_pixel(neg, Color::GREEN);
1122 fb.draw_iter(core::iter::once(Pixel(Point::new(10, -2), Color::RED)))
1124 .unwrap();
1125
1126 let calls = fb.0.take_calls();
1127 assert_eq!(calls.len(), 2);
1128 assert!(matches!(calls[0], Call::SetPixel { p, .. } if p == neg));
1129 match &calls[1] {
1130 Call::Draw(v) => {
1131 assert_eq!(v.as_slice(), &[(Point::new(10, -2), Color::RED)]);
1132 }
1133 _ => panic!("expected a Draw call"),
1134 }
1135 }
1136
1137 #[test]
1138 #[allow(deprecated)]
1139 fn test_tiled_read_buffer_passthrough() {
1140 const TILED_COLS: usize = 2;
1141 const TILED_ROWS: usize = 2;
1142 const ROWS: usize = 32;
1143 const PANEL_COLS: usize = 64;
1144 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1145
1146 let fb = TiledFrameBuffer::<
1147 TestFrameBuffer,
1148 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1149 ROWS,
1150 PANEL_COLS,
1151 { crate::compute_rows(ROWS) },
1152 2,
1153 { crate::compute_frame_count(2) },
1154 TILED_ROWS,
1155 TILED_COLS,
1156 FB_COLS,
1157 >(TestFrameBuffer::new(), core::marker::PhantomData);
1158
1159 let inner_ptr = fb.0.buf.as_ptr();
1160 let inner_len = fb.0.buf.len();
1161
1162 let (ptr, len) = unsafe { fb.read_buffer() };
1163 assert_eq!(ptr, inner_ptr);
1164 assert_eq!(len, inner_len);
1165 }
1166
1167 #[test]
1168 #[allow(deprecated)]
1169 fn test_tiled_get_word_size_passthrough() {
1170 const TILED_COLS: usize = 2;
1171 const TILED_ROWS: usize = 2;
1172 const ROWS: usize = 32;
1173 const PANEL_COLS: usize = 64;
1174 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1175
1176 let fb = TiledFrameBuffer::<
1177 TestFrameBuffer,
1178 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1179 ROWS,
1180 PANEL_COLS,
1181 { crate::compute_rows(ROWS) },
1182 2,
1183 { crate::compute_frame_count(2) },
1184 TILED_ROWS,
1185 TILED_COLS,
1186 FB_COLS,
1187 >(TestFrameBuffer::new(), core::marker::PhantomData);
1188 assert_eq!(fb.get_word_size(), WordSize::Eight);
1189 }
1190
1191 #[test]
1192 #[allow(deprecated)]
1193 fn test_tiled_get_word_size_eight_passthrough() {
1194 const TILED_COLS: usize = 2;
1195 const TILED_ROWS: usize = 2;
1196 const ROWS: usize = 32;
1197 const PANEL_COLS: usize = 64;
1198 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1199
1200 let fb = TiledFrameBuffer::<
1201 TestFrameBuffer,
1202 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1203 ROWS,
1204 PANEL_COLS,
1205 { crate::compute_rows(ROWS) },
1206 2,
1207 { crate::compute_frame_count(2) },
1208 TILED_ROWS,
1209 TILED_COLS,
1210 FB_COLS,
1211 >(TestFrameBuffer::new(), core::marker::PhantomData);
1212 assert_eq!(fb.get_word_size(), WordSize::Eight);
1213 }
1214
1215 struct Huge<
1217 const PANEL_ROWS: usize,
1218 const PANEL_COLS: usize,
1219 const TILE_ROWS: usize,
1220 const TILE_COLS: usize,
1221 >;
1222
1223 impl<
1224 const PANEL_ROWS: usize,
1225 const PANEL_COLS: usize,
1226 const TILE_ROWS: usize,
1227 const TILE_COLS: usize,
1228 > PixelRemapper for Huge<PANEL_ROWS, PANEL_COLS, TILE_ROWS, TILE_COLS>
1229 {
1230 const VIRT_ROWS: usize = PANEL_ROWS * TILE_ROWS;
1231 const VIRT_COLS: usize = PANEL_COLS * TILE_COLS;
1232 const FB_ROWS: usize = PANEL_ROWS;
1233 const FB_COLS: usize = PANEL_COLS * TILE_ROWS * TILE_COLS;
1234
1235 fn remap_xy(x: usize, y: usize) -> (usize, usize) {
1236 (x + 70_000, y + 70_000)
1237 }
1238 }
1239
1240 #[test]
1241 #[allow(deprecated)]
1242 fn test_remap_point_truncates_to_u16_range() {
1243 const TILED_COLS: usize = 1;
1244 const TILED_ROWS: usize = 1;
1245 const ROWS: usize = 32;
1246 const PANEL_COLS: usize = 64;
1247 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1248
1249 let mut fb = TiledFrameBuffer::<
1250 TestFrameBuffer,
1251 Huge<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1252 ROWS,
1253 PANEL_COLS,
1254 { crate::compute_rows(ROWS) },
1255 2,
1256 { crate::compute_frame_count(2) },
1257 TILED_ROWS,
1258 TILED_COLS,
1259 FB_COLS,
1260 >(TestFrameBuffer::new(), core::marker::PhantomData);
1261 fb.set_pixel(Point::new(1, 2), Color::RED);
1262
1263 let calls = fb.0.take_calls();
1264 match calls.into_iter().next().unwrap() {
1265 Call::SetPixel { p, color } => {
1266 let (rx, ry) = (1usize + 70_000, 2usize + 70_000);
1267 let expected = Point::new(i32::from(rx as u16), i32::from(ry as u16));
1268 assert_eq!(p, expected);
1269 assert_eq!(color, Color::RED);
1270 }
1271 other => panic!("unexpected call recorded: {other:?}"),
1272 }
1273 }
1274
1275 #[test]
1276 fn test_more_compute_tiled_cols_cases() {
1277 assert_eq!(compute_tiled_cols(64, 1, 4), 256);
1278 assert_eq!(compute_tiled_cols(64, 4, 1), 256);
1279 assert_eq!(compute_tiled_cols(32, 4, 5), 640);
1280 }
1281
1282 #[test]
1283 #[allow(deprecated)]
1284 fn test_tiled_default_and_new_construct() {
1285 const TILED_COLS: usize = 4;
1286 const TILED_ROWS: usize = 2;
1287 const ROWS: usize = 32;
1288 const PANEL_COLS: usize = 64;
1289 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1290
1291 let fb_default = TiledFrameBuffer::<
1292 TestFrameBuffer,
1293 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1294 ROWS,
1295 PANEL_COLS,
1296 { crate::compute_rows(ROWS) },
1297 2,
1298 { crate::compute_frame_count(2) },
1299 TILED_ROWS,
1300 TILED_COLS,
1301 FB_COLS,
1302 >::default();
1303
1304 let fb_new = TiledFrameBuffer::<
1305 TestFrameBuffer,
1306 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1307 ROWS,
1308 PANEL_COLS,
1309 { crate::compute_rows(ROWS) },
1310 2,
1311 { crate::compute_frame_count(2) },
1312 TILED_ROWS,
1313 TILED_COLS,
1314 FB_COLS,
1315 >::new();
1316
1317 assert_eq!(fb_default.get_word_size(), WordSize::Eight);
1319 assert_eq!(fb_new.get_word_size(), WordSize::Eight);
1320
1321 let expected_size = Size::new((PANEL_COLS * TILED_COLS) as u32, (ROWS * TILED_ROWS) as u32);
1323 assert_eq!(fb_default.size(), expected_size);
1324 assert_eq!(fb_new.size(), expected_size);
1325
1326 assert!(fb_default.0.take_calls().is_empty());
1328 assert!(fb_new.0.take_calls().is_empty());
1329 }
1330
1331 #[test]
1332 #[allow(deprecated)]
1333 fn test_tiled_origin_dimensions_matches_virtual_size() {
1334 const TILED_COLS: usize = 5;
1335 const TILED_ROWS: usize = 2;
1336 const ROWS: usize = 32;
1337 const PANEL_COLS: usize = 64;
1338 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1339
1340 let fb = TiledFrameBuffer::<
1341 TestFrameBuffer,
1342 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1343 ROWS,
1344 PANEL_COLS,
1345 { crate::compute_rows(ROWS) },
1346 2,
1347 { crate::compute_frame_count(2) },
1348 TILED_ROWS,
1349 TILED_COLS,
1350 FB_COLS,
1351 >::new();
1352
1353 let (virt_rows, virt_cols) = <ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS> as PixelRemapper>::virtual_size();
1354 assert_eq!(fb.size(), Size::new(virt_cols as u32, virt_rows as u32));
1355 }
1356
1357 fn expected_ctrdd_xy<const PR: usize, const PC: usize, const TR: usize, const TC: usize>(
1359 x: usize,
1360 y: usize,
1361 ) -> (usize, usize) {
1362 let row = y / PR;
1363 let base = (TR - 1 - row) * (PC * TC);
1364 if row % 2 == 1 {
1365 (base + (PC * TC) - 1 - x, PR - 1 - (y % PR))
1366 } else {
1367 (base + x, y % PR)
1368 }
1369 }
1370
1371 #[test]
1372 fn test_chain_top_right_down_corners_2x3() {
1373 const PR: usize = 32;
1374 const PC: usize = 64;
1375 const TR: usize = 2;
1376 const TC: usize = 3;
1377 type M = ChainTopRightDown<PR, PC, TR, TC>;
1378
1379 for r in 0..TR {
1380 for c in 0..TC {
1381 let x0 = c * PC;
1382 let y0 = r * PR;
1383 let corners = [
1384 (x0, y0), (x0 + PC - 1, y0), (x0, y0 + PR - 1), (x0 + PC - 1, y0 + PR - 1), ];
1389
1390 for &(x, y) in &corners {
1391 let got = <M as PixelRemapper>::remap_xy(x, y);
1392 let exp = expected_ctrdd_xy::<PR, PC, TR, TC>(x, y);
1393 assert_eq!(
1394 got, exp,
1395 "corner mismatch at panel (row={}, col={}), virtual=({}, {})",
1396 r, c, x, y
1397 );
1398 }
1399 }
1400 }
1401 }
1402
1403 #[test]
1404 fn test_chain_top_right_down_corners_3x2() {
1405 const PR: usize = 32;
1406 const PC: usize = 64;
1407 const TR: usize = 3;
1408 const TC: usize = 2;
1409 type M = ChainTopRightDown<PR, PC, TR, TC>;
1410
1411 for r in 0..TR {
1412 for c in 0..TC {
1413 let x0 = c * PC;
1414 let y0 = r * PR;
1415 let corners = [
1416 (x0, y0), (x0 + PC - 1, y0), (x0, y0 + PR - 1), (x0 + PC - 1, y0 + PR - 1), ];
1421
1422 for &(x, y) in &corners {
1423 let got = <M as PixelRemapper>::remap_xy(x, y);
1424 let exp = expected_ctrdd_xy::<PR, PC, TR, TC>(x, y);
1425 assert_eq!(
1426 got, exp,
1427 "corner mismatch at panel (row={}, col={}), virtual=({}, {})",
1428 r, c, x, y
1429 );
1430 }
1431 }
1432 }
1433 }
1434
1435 type TestRemapped = RemappedFrameBuffer<TestFrameBuffer, ChainTopRightDown<32, 64, 3, 3>>;
1438
1439 #[test]
1440 fn test_remapped_default_and_new_construct() {
1441 let _fb = TestRemapped::new();
1442 let _fb2: TestRemapped = Default::default();
1443 }
1444
1445 #[test]
1446 fn test_remapped_origin_dimensions_matches_virtual_size() {
1447 let fb = TestRemapped::new();
1448 assert_eq!(fb.size(), Size::new(192, 96));
1449 }
1450
1451 #[test]
1452 fn test_remapped_draw_iter_forwards_with_remap() {
1453 let mut fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 3, 3>>(
1454 TestFrameBuffer::new(),
1455 core::marker::PhantomData,
1456 );
1457
1458 let input = [
1459 Pixel(Point::new(0, 0), Color::RED),
1460 Pixel(Point::new(63, 0), Color::GREEN),
1461 Pixel(Point::new(64, 0), Color::BLUE),
1462 Pixel(Point::new(100, 40), Color::WHITE),
1463 ];
1464
1465 fb.draw_iter(input.into_iter()).unwrap();
1466
1467 let calls = fb.0.take_calls();
1468 assert_eq!(calls.len(), 1);
1469 match &calls[0] {
1470 Call::Draw(v) => {
1471 let expected = [
1472 ChainTopRightDown::<32, 64, 3, 3>::remap(Pixel(Point::new(0, 0), Color::RED)),
1473 ChainTopRightDown::<32, 64, 3, 3>::remap(Pixel(
1474 Point::new(63, 0),
1475 Color::GREEN,
1476 )),
1477 ChainTopRightDown::<32, 64, 3, 3>::remap(Pixel(Point::new(64, 0), Color::BLUE)),
1478 ChainTopRightDown::<32, 64, 3, 3>::remap(Pixel(
1479 Point::new(100, 40),
1480 Color::WHITE,
1481 )),
1482 ];
1483 let expected_points: std::vec::Vec<(Point, Color)> =
1484 expected.iter().map(|p| (p.0, p.1)).collect();
1485 assert_eq!(v.as_slice(), expected_points.as_slice());
1486 }
1487 _ => panic!("expected a Draw call"),
1488 }
1489 }
1490
1491 #[test]
1492 fn test_remapped_set_pixel_remaps_and_forwards() {
1493 let mut fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 3, 3>>(
1494 TestFrameBuffer::new(),
1495 core::marker::PhantomData,
1496 );
1497
1498 let p = Point::new(100, 40);
1499 fb.set_pixel(p, Color::BLUE);
1500
1501 let calls = fb.0.take_calls();
1502 assert_eq!(calls.len(), 1);
1503 match calls.into_iter().next().unwrap() {
1504 Call::SetPixel { p: rp, color } => {
1505 let expected = ChainTopRightDown::<32, 64, 3, 3>::remap_point(p);
1506 assert_eq!(rp, expected);
1507 assert_eq!(color, Color::BLUE);
1508 }
1509 _ => panic!("expected a SetPixel call"),
1510 }
1511 }
1512
1513 #[test]
1514 fn test_remapped_erase_forwards() {
1515 let mut fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 2, 2>>(
1516 TestFrameBuffer::new(),
1517 core::marker::PhantomData,
1518 );
1519
1520 fb.erase();
1521 let calls = fb.0.take_calls();
1522 assert_eq!(calls, std::vec![Call::Erase]);
1523 }
1524
1525 #[test]
1526 fn test_remapped_negative_coordinates_not_remapped() {
1527 let mut fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 2, 2>>(
1528 TestFrameBuffer::new(),
1529 core::marker::PhantomData,
1530 );
1531
1532 let neg = Point::new(-3, 5);
1533 fb.set_pixel(neg, Color::GREEN);
1534 fb.draw_iter(core::iter::once(Pixel(Point::new(10, -2), Color::RED)))
1535 .unwrap();
1536
1537 let calls = fb.0.take_calls();
1538 assert_eq!(calls.len(), 2);
1539 assert!(matches!(calls[0], Call::SetPixel { p, .. } if p == neg));
1540 match &calls[1] {
1541 Call::Draw(v) => {
1542 assert_eq!(v.as_slice(), &[(Point::new(10, -2), Color::RED)]);
1543 }
1544 _ => panic!("expected a Draw call"),
1545 }
1546 }
1547
1548 #[test]
1549 fn test_remapped_read_buffer_passthrough() {
1550 let fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 2, 2>>(
1551 TestFrameBuffer::new(),
1552 core::marker::PhantomData,
1553 );
1554
1555 let inner_ptr = fb.0.buf.as_ptr();
1556 let inner_len = fb.0.buf.len();
1557
1558 let (ptr, len) = unsafe { fb.read_buffer() };
1559 assert_eq!(ptr, inner_ptr);
1560 assert_eq!(len, inner_len);
1561 }
1562
1563 #[test]
1564 fn test_remapped_get_word_size_passthrough() {
1565 let fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 2, 2>>(
1566 TestFrameBuffer::new(),
1567 core::marker::PhantomData,
1568 );
1569 assert_eq!(fb.get_word_size(), WordSize::Eight);
1570 }
1571
1572 #[test]
1573 fn test_remapped_plane_count_passthrough() {
1574 let fb = RemappedFrameBuffer::<TestFrameBuffer, ChainTopRightDown<32, 64, 2, 2>>(
1575 TestFrameBuffer::new(),
1576 core::marker::PhantomData,
1577 );
1578 assert_eq!(fb.plane_count(), 1);
1579 }
1580
1581 #[test]
1582 fn test_remapped_with_plain_framebuffer() {
1583 use crate::plain::DmaFrameBuffer;
1584 const TILED_COLS: usize = 3;
1585 const TILED_ROWS: usize = 3;
1586 const ROWS: usize = 32;
1587 const PANEL_COLS: usize = 64;
1588 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1589 const BITS: u8 = 2;
1590 const NROWS: usize = crate::compute_rows(ROWS);
1591 const FRAME_COUNT: usize = crate::compute_frame_count(BITS);
1592
1593 type FBType = DmaFrameBuffer<ROWS, FB_COLS, NROWS, BITS, FRAME_COUNT>;
1594 type Display = RemappedFrameBuffer<
1595 FBType,
1596 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1597 >;
1598
1599 let fb = Display::new();
1600 assert_eq!(fb.size(), Size::new(192, 96));
1601 }
1602
1603 #[test]
1604 fn test_remapped_with_latched_framebuffer() {
1605 use crate::latched::DmaFrameBuffer;
1606 const TILED_COLS: usize = 3;
1607 const TILED_ROWS: usize = 3;
1608 const ROWS: usize = 32;
1609 const PANEL_COLS: usize = 64;
1610 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1611 const BITS: u8 = 2;
1612 const NROWS: usize = crate::compute_rows(ROWS);
1613 const FRAME_COUNT: usize = crate::compute_frame_count(BITS);
1614
1615 type FBType = DmaFrameBuffer<ROWS, FB_COLS, NROWS, BITS, FRAME_COUNT>;
1616 type Display = RemappedFrameBuffer<
1617 FBType,
1618 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1619 >;
1620
1621 let fb = Display::new();
1622 assert_eq!(fb.size(), Size::new(192, 96));
1623 }
1624
1625 #[test]
1626 fn test_remapped_with_bitplane_plain_framebuffer() {
1627 use crate::bitplane::plain::DmaFrameBuffer;
1628 const TILED_COLS: usize = 3;
1629 const TILED_ROWS: usize = 3;
1630 const ROWS: usize = 32;
1631 const NROWS: usize = ROWS / 2;
1632 const PANEL_COLS: usize = 64;
1633 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1634 const PLANES: usize = 8;
1635
1636 type FBType = DmaFrameBuffer<NROWS, FB_COLS, PLANES>;
1637 type Display = RemappedFrameBuffer<
1638 FBType,
1639 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1640 >;
1641
1642 let fb = Display::new();
1643 assert_eq!(fb.size(), Size::new(192, 96));
1644 }
1645
1646 #[test]
1647 fn test_remapped_with_bitplane_latched_framebuffer() {
1648 use crate::bitplane::latched::DmaFrameBuffer;
1649 const TILED_COLS: usize = 3;
1650 const TILED_ROWS: usize = 3;
1651 const ROWS: usize = 32;
1652 const NROWS: usize = ROWS / 2;
1653 const PANEL_COLS: usize = 64;
1654 const FB_COLS: usize = compute_tiled_cols(PANEL_COLS, TILED_ROWS, TILED_COLS);
1655 const PLANES: usize = 8;
1656
1657 type FBType = DmaFrameBuffer<NROWS, FB_COLS, PLANES>;
1658 type Display = RemappedFrameBuffer<
1659 FBType,
1660 ChainTopRightDown<ROWS, PANEL_COLS, TILED_ROWS, TILED_COLS>,
1661 >;
1662
1663 let fb = Display::new();
1664 assert_eq!(fb.size(), Size::new(192, 96));
1665 }
1666
1667 #[test]
1668 fn test_quarter_scan_associated_constants() {
1669 type QS = QuarterScan<64, 64>;
1670 assert_eq!(QS::VIRT_ROWS, 64);
1671 assert_eq!(QS::VIRT_COLS, 64);
1672 assert_eq!(QS::FB_ROWS, 16);
1673 assert_eq!(QS::FB_COLS, 256);
1674 assert_eq!(QS::virtual_size(), (64, 64));
1675 assert_eq!(QS::fb_size(), (16, 256));
1676 }
1677}