diff --git a/ctru-rs/examples/linear-memory.rs b/ctru-rs/examples/linear-memory.rs new file mode 100644 index 0000000..96ec554 --- /dev/null +++ b/ctru-rs/examples/linear-memory.rs @@ -0,0 +1,43 @@ +#![feature(allocator_api)] + +use ctru::prelude::*; +use ctru::linear::LinearAllocator; + +fn main() { + ctru::init(); + let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); + let hid = Hid::init().expect("Couldn't obtain HID controller"); + let apt = Apt::init().expect("Couldn't obtain APT controller"); + let _console = Console::init(gfx.top_screen.borrow_mut()); + + let linear_space_before = LinearAllocator::free_space(); + + // Normal `Box` on the heap + let heap_box = Box::new(1492); + // `Box` living on the linear memory sector + let linear_box: Box:: = Box::new_in(2022, LinearAllocator); + + println!("This value is from the heap: {heap_box}"); + println!("This value is from the LINEAR memory: {linear_box}"); + + println!("\nLINEAR space free before allocation: {linear_space_before}"); + println!("LINEAR space free after allocation: {}", LinearAllocator::free_space()); + + println!("\x1b[29;16HPress Start to exit"); + + // Main loop + while apt.main_loop() { + //Scan all the inputs. This should be done once for each frame + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::KEY_START) { + break; + } + // Flush and swap framebuffers + gfx.flush_buffers(); + gfx.swap_buffers(); + + //Wait for VBlank + gfx.wait_for_vblank(); + } +} diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 264d0ef..35fdc0c 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -3,6 +3,7 @@ #![feature(test)] #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] +#![feature(allocator_api)] #![test_runner(test_runner::run)] extern "C" fn services_deinit() { @@ -76,6 +77,7 @@ pub mod applets; pub mod console; pub mod error; pub mod gfx; +pub mod linear; pub mod prelude; pub mod services; diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs new file mode 100644 index 0000000..88f65fe --- /dev/null +++ b/ctru-rs/src/linear.rs @@ -0,0 +1,38 @@ +//! Linear memory allocator +//! +//! Linear memory is a sector of the 3DS' RAM that binds virtual addresses exactly to the physical address. +//! As such, it is used for fast and safe memory sharing between services (and is especially needed for GPU and DSP). +//! +//! Resources:
+//!
+//! + +use std::alloc::Allocator; + +// Implementing an `std::alloc::Allocator` type is the best way to handle this case, since it gives +// us full control over the normal `std` implementations (like `Box`). The only issue is that this is another unstable feature to add. +// Sadly the linear memory allocator included in `libctru` doesn't implement `linearRealloc` at the time of these additions, +// but the default fallback of the `std` will take care of that for us. + +/// [`std::alloc::Allocator`] struct for LINEAR memory +pub struct LinearAllocator; + +impl LinearAllocator { + /// Returns the amount of free space left in the LINEAR sector + pub fn free_space() -> u32 { + unsafe { ctru_sys::linearSpaceFree() } + } +} + +unsafe impl Allocator for LinearAllocator { + fn allocate(&self, layout: std::alloc::Layout) -> Result, std::alloc::AllocError> { + let pointer = unsafe { ctru_sys::linearAlloc(layout.size() as u32) }; + let slice: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(pointer as *mut u8, layout.size()) }; + + std::ptr::NonNull::new(slice).ok_or(std::alloc::AllocError) + } + + unsafe fn deallocate(&self, ptr: std::ptr::NonNull, _layout: std::alloc::Layout) { + unsafe { ctru_sys::linearFree(ptr.as_ptr() as *mut _) }; + } +}