Skip to content

Commit a5a8930

Browse files
committed
Add SimpleVramAllocator::free_all and attach a lifetime to VRAM chunks
1 parent 0cd5a70 commit a5a8930

File tree

2 files changed

+48
-20
lines changed

2 files changed

+48
-20
lines changed

examples/cube/src/main.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,21 @@ unsafe fn psp_main_inner() {
8989
psp::enable_home_button();
9090

9191
let mut allocator = get_vram_allocator().unwrap();
92-
let fbp0 = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm8888).as_mut_ptr_from_zero();
93-
let fbp1 = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm8888).as_mut_ptr_from_zero();
94-
let zbp = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm4444).as_mut_ptr_from_zero();
92+
let fbp0 = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm8888);
93+
let fbp1 = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm8888);
94+
let zbp = allocator.alloc_texture_pixels(BUF_WIDTH, SCREEN_HEIGHT, TexturePixelFormat::Psm4444);
95+
// Attempting to free the three VRAM chunks at this point would give a
96+
// compile-time error since fbp0, fbp1 and zbp are used later on
97+
//allocator.free_all();
9598

9699
sys::sceGumLoadIdentity();
97100

98101
sys::sceGuInit();
99102

100103
sys::sceGuStart(GuContextType::Direct, &mut LIST.0 as *mut [u32; 0x40000] as *mut _);
101-
sys::sceGuDrawBuffer(DisplayPixelFormat::Psm8888, fbp0 as _, BUF_WIDTH as i32);
102-
sys::sceGuDispBuffer(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32, fbp1 as _, BUF_WIDTH as i32);
103-
sys::sceGuDepthBuffer(zbp as _, BUF_WIDTH as i32);
104+
sys::sceGuDrawBuffer(DisplayPixelFormat::Psm8888, fbp0.as_mut_ptr_from_zero() as _, BUF_WIDTH as i32);
105+
sys::sceGuDispBuffer(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32, fbp1.as_mut_ptr_from_zero() as _, BUF_WIDTH as i32);
106+
sys::sceGuDepthBuffer(zbp.as_mut_ptr_from_zero() as _, BUF_WIDTH as i32);
104107
sys::sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2));
105108
sys::sceGuViewport(2048, 2048, SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32);
106109
sys::sceGuDepthRange(65535, 0);

psp/src/vram_alloc.rs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::sys::TexturePixelFormat;
22
use crate::sys::{sceGeEdramGetAddr, sceGeEdramGetSize};
3+
use core::marker::PhantomData;
34
use core::mem::size_of;
45
use core::ptr::null_mut;
6+
use core::sync::atomic::{AtomicU32, Ordering};
57

68
type VramAllocator = SimpleVramAllocator;
79

@@ -27,14 +29,20 @@ impl VramAllocatorSingleton {
2729
}
2830
}
2931

30-
pub struct VramMemChunk {
32+
pub struct VramMemChunk<'a> {
3133
start: u32,
3234
len: u32,
35+
// This makes the VRAM chunk act like it has a mutable reference
36+
vram: PhantomData<&'a mut ()>,
3337
}
3438

35-
impl VramMemChunk {
39+
impl VramMemChunk<'_> {
3640
fn new(start: u32, len: u32) -> Self {
37-
Self { start, len }
41+
Self {
42+
start,
43+
len,
44+
vram: PhantomData,
45+
}
3846
}
3947

4048
pub fn as_mut_ptr_from_zero(&self) -> *mut u8 {
@@ -54,38 +62,55 @@ impl VramMemChunk {
5462
// TODO: pin?
5563
#[derive(Debug)]
5664
pub struct SimpleVramAllocator {
57-
offset: u32,
65+
offset: AtomicU32,
5866
}
5967

6068
impl SimpleVramAllocator {
6169
const fn new() -> Self {
62-
Self { offset: 0 }
70+
Self {
71+
offset: AtomicU32::new(0),
72+
}
6373
}
6474

65-
// TODO: return a Result instead of panicking
66-
pub fn alloc(&mut self, size: u32) -> VramMemChunk {
67-
let old_offset = self.offset;
68-
self.offset += size;
75+
/// Frees all previously allocated VRAM chunks.
76+
///
77+
/// This resets the allocator's counter, but does not change the contents of
78+
/// VRAM. Since this method requires `&mut Self`, it cannot overlap with any
79+
/// previously allocated `VramMemChunk`s since they have the lifetime of the
80+
/// `&Self` that allocated them.
81+
pub fn free_all(&mut self) {
82+
self.offset.store(0, Ordering::Relaxed);
83+
}
6984

70-
if self.offset > self.total_mem() {
85+
// TODO: return a Result instead of panicking
86+
/// Allocates a `size` bytes of VRAM
87+
///
88+
/// The returned VRAM chunk has the same lifetime as the
89+
/// `SimpleVramAllocator` borrow (i.e. `&self`) that allocated it.
90+
pub fn alloc<'a>(&'a self, size: u32) -> VramMemChunk<'a> {
91+
let old_offset = self.offset.load(Ordering::Relaxed);
92+
let new_offset = old_offset + size;
93+
self.offset.store(new_offset, Ordering::Relaxed);
94+
95+
if new_offset > self.total_mem() {
7196
panic!("Total VRAM size exceeded!");
7297
}
7398

7499
VramMemChunk::new(old_offset, size)
75100
}
76101

77102
// TODO: ensure 16-bit alignment?
78-
pub fn alloc_sized<T: Sized>(&mut self, count: u32) -> VramMemChunk {
103+
pub fn alloc_sized<'a, T: Sized>(&'a self, count: u32) -> VramMemChunk<'a> {
79104
let size = size_of::<T>() as u32;
80105
self.alloc(count * size)
81106
}
82107

83-
pub fn alloc_texture_pixels(
84-
&mut self,
108+
pub fn alloc_texture_pixels<'a>(
109+
&'a self,
85110
width: u32,
86111
height: u32,
87112
psm: TexturePixelFormat,
88-
) -> VramMemChunk {
113+
) -> VramMemChunk<'a> {
89114
let size = get_memory_size(width, height, psm);
90115
self.alloc(size)
91116
}

0 commit comments

Comments
 (0)