diff --git a/ctru-rs/examples/linear-memory.rs b/ctru-rs/examples/linear-memory.rs new file mode 100644 index 0000000..11d13d3 --- /dev/null +++ b/ctru-rs/examples/linear-memory.rs @@ -0,0 +1,46 @@ +#![feature(allocator_api)] + +use ctru::linear::LinearAllocator; +use ctru::prelude::*; + +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 f461822..490b268 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -3,6 +3,8 @@ #![feature(test)] #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] +#![feature(allocator_api)] +#![feature(nonnull_slice_from_raw_parts)] #![test_runner(test_runner::run)] extern "C" fn services_deinit() { @@ -76,6 +78,7 @@ pub mod applets; pub mod console; pub mod error; pub mod gfx; +pub mod linear; pub mod mii; 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..da91eb7 --- /dev/null +++ b/ctru-rs/src/linear.rs @@ -0,0 +1,42 @@ +//! 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::{AllocError, Allocator, Layout}; +use std::ptr::NonNull; + +// 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 +/// To use this struct the main crate must activate the `allocator_api` unstable feature. +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: Layout) -> Result, AllocError> { + let pointer = + unsafe { ctru_sys::linearMemAlign(layout.size() as u32, layout.align() as u32) }; + + NonNull::new(pointer.cast()) + .map(|ptr| NonNull::slice_from_raw_parts(ptr, layout.size())) + .ok_or(AllocError) + } + + unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { + ctru_sys::linearFree(ptr.as_ptr().cast()); + } +}