use core::{ alloc::Layout, cell::UnsafeCell, ops::{Deref, DerefMut}, sync::atomic::{self, AtomicBool}, }; use alloc::{ alloc::{Allocator, Global}, boxed::Box, sync::Arc, vec, }; use bytemuck::{AnyBitPattern, NoUninit}; use esp_hal::{ Blocking, dma::{ self, BurstConfig, DmaDescriptor, DmaTxBuffer, Mem2Mem, SimpleMem2Mem, SimpleMem2MemTransfer, }, handler, interrupt::{self, Priority}, lcd_cam::lcd::dpi::{Dpi, DpiTransfer}, peripherals::{DMA, DMA_CH0, Interrupt}, ram, spi::master::AnySpi, }; use esp_hal_bounce_buffers::{DmaBounce, Swapchain, SwapchainWriter, allocate_dma_buffer_in}; use log::error; use ouroboros::self_referencing; use crate::PSRAM_ALLOCATOR; /// THIS IS TAKEN FROM https://github.com/esp-rs/esp-hal/blob/main/esp-hal/src/soc/esp32s3/mod.rs /// Write back a specific range of data in the cache. #[doc(hidden)] #[unsafe(link_section = ".rwtext")] pub unsafe fn cache_writeback_addr(addr: u32, size: u32) { unsafe extern "C" { fn rom_Cache_WriteBack_Addr(addr: u32, size: u32); fn Cache_Suspend_DCache_Autoload() -> u32; fn Cache_Resume_DCache_Autoload(value: u32); } // suspend autoload, avoid load cachelines being written back unsafe { let autoload = Cache_Suspend_DCache_Autoload(); rom_Cache_WriteBack_Addr(addr, size); Cache_Resume_DCache_Autoload(autoload); } } /// THIS IS TAKEN FROM https://github.com/esp-rs/esp-hal/blob/main/esp-hal/src/soc/esp32s3/mod.rs /// Invalidate a specific range of addresses in the cache. #[doc(hidden)] #[unsafe(link_section = ".rwtext")] pub unsafe fn cache_invalidate_addr(addr: u32, size: u32) { unsafe extern "C" { fn Cache_Invalidate_Addr(addr: u32, size: u32); } unsafe { Cache_Invalidate_Addr(addr, size); } } // TODO: Rename or get rid of. pub struct Framebuffer { pub width: u32, pub height: u32, pub swapchain: Option, pub bounce_buffers: Option, } impl Framebuffer { pub fn new( channel: DMA_CH0<'static>, peripheral_src: AnySpi<'static>, peripheral_dst: Dpi<'static, Blocking>, burst_config: BurstConfig, front_porch_pixels: u32, width_pixels: u32, height_pixels: u32, rows_per_window: usize, cyclic: bool, ) -> Self { const BYTES_PER_PIXEL: usize = core::mem::size_of::(); let buffer_size = width_pixels as usize * height_pixels as usize * BYTES_PER_PIXEL; let framebuffers = [ Box::leak(allocate_dma_buffer_in( buffer_size, burst_config, &PSRAM_ALLOCATOR, )), Box::leak(allocate_dma_buffer_in( buffer_size, burst_config, &PSRAM_ALLOCATOR, )), ]; let (swapchain_reader, swapchain_writer) = Swapchain { framebuffers }.into_reader_writer(); let bounce_buffers = DmaBounce::new( Global, channel, peripheral_src, peripheral_dst, swapchain_reader, front_porch_pixels as usize * BYTES_PER_PIXEL, width_pixels as usize * BYTES_PER_PIXEL, rows_per_window, burst_config, cyclic, ); Self { width: width_pixels, height: height_pixels, swapchain: Some(swapchain_writer), bounce_buffers: Some(bounce_buffers), } } }