mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
copy affine matricies at copy time
This commit is contained in:
parent
354cf7addc
commit
0e9910c517
|
@ -12,8 +12,6 @@ pub use affine::AffineMatrix;
|
||||||
pub use managed::{OAMManager, Object};
|
pub use managed::{OAMManager, Object};
|
||||||
pub use unmanaged::{AffineMode, OAMIterator, OAMSlot, UnmanagedOAM, UnmanagedObject};
|
pub use unmanaged::{AffineMode, OAMIterator, OAMSlot, UnmanagedOAM, UnmanagedObject};
|
||||||
|
|
||||||
pub(crate) use affine::init_affine;
|
|
||||||
|
|
||||||
use super::DISPLAY_CONTROL;
|
use super::DISPLAY_CONTROL;
|
||||||
|
|
||||||
const OBJECT_ATTRIBUTE_MEMORY: usize = 0x0700_0000;
|
const OBJECT_ATTRIBUTE_MEMORY: usize = 0x0700_0000;
|
||||||
|
|
|
@ -1,37 +1,63 @@
|
||||||
|
use core::cell::Cell;
|
||||||
|
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
|
|
||||||
use crate::{display::affine::AffineMatrixObject, sync::Static};
|
use crate::display::affine::AffineMatrixObject;
|
||||||
|
|
||||||
use super::OBJECT_ATTRIBUTE_MEMORY;
|
use super::OBJECT_ATTRIBUTE_MEMORY;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct AffineMatrixLocation {
|
struct AffineMatrixData {
|
||||||
location: u16,
|
frame_count: Cell<u32>,
|
||||||
|
location: Cell<u32>,
|
||||||
|
matrix: AffineMatrixObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct AffineMatrixVram(Rc<AffineMatrixLocation>);
|
pub(crate) struct AffineMatrixVram(Rc<AffineMatrixData>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AffineMatrix {
|
pub struct AffineMatrix {
|
||||||
location: AffineMatrixVram,
|
location: AffineMatrixVram,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AffineMatrix {
|
impl AffineMatrix {
|
||||||
pub fn new(affine_matrix: AffineMatrixObject) -> Option<AffineMatrix> {
|
#[must_use]
|
||||||
let mut matrix = AFFINE_MATRIX_DISTRIBUTOR.get_matrix()?;
|
pub fn new(affine_matrix: AffineMatrixObject) -> AffineMatrix {
|
||||||
matrix.write(affine_matrix);
|
AffineMatrix {
|
||||||
|
location: AffineMatrixVram(Rc::new(AffineMatrixData {
|
||||||
Some(matrix)
|
frame_count: Cell::new(u32::MAX),
|
||||||
|
location: Cell::new(u32::MAX),
|
||||||
|
matrix: affine_matrix,
|
||||||
|
})),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn vram(self) -> AffineMatrixVram {
|
pub(crate) fn vram(self) -> AffineMatrixVram {
|
||||||
self.location
|
self.location
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write(&mut self, affine_matrix: AffineMatrixObject) {
|
impl AffineMatrixVram {
|
||||||
let components = affine_matrix.components();
|
pub fn frame_count(&self) -> u32 {
|
||||||
let location = self.location.0.location as usize;
|
self.0.frame_count.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_frame_count(&self, frame: u32) {
|
||||||
|
self.0.frame_count.set(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn location(&self) -> u32 {
|
||||||
|
self.0.location.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_location(&self, location: u32) {
|
||||||
|
self.0.location.set(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_to_location(&self) {
|
||||||
|
let components = self.0.matrix.components();
|
||||||
|
let location = self.0.location.get() as usize;
|
||||||
for (idx, component) in components.iter().enumerate() {
|
for (idx, component) in components.iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||||
|
@ -42,74 +68,15 @@ impl AffineMatrix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AffineMatrixVram {
|
#[cfg(test)]
|
||||||
pub fn location(&self) -> u16 {
|
mod tests {
|
||||||
self.0.location
|
use super::*;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for AffineMatrixLocation {
|
#[test_case]
|
||||||
fn drop(&mut self) {
|
fn niche_optimisation(_gba: &mut crate::Gba) {
|
||||||
// safety: obtained via affine matrix distributor
|
assert_eq!(
|
||||||
unsafe { AFFINE_MATRIX_DISTRIBUTOR.return_matrix(self.location) }
|
core::mem::size_of::<AffineMatrix>(),
|
||||||
}
|
core::mem::size_of::<Option<AffineMatrix>>()
|
||||||
}
|
);
|
||||||
|
|
||||||
struct AffineMatrixDistributor {
|
|
||||||
tip: Static<u16>,
|
|
||||||
}
|
|
||||||
|
|
||||||
static AFFINE_MATRIX_DISTRIBUTOR: AffineMatrixDistributor = AffineMatrixDistributor::new();
|
|
||||||
|
|
||||||
pub(crate) unsafe fn init_affine() {
|
|
||||||
AFFINE_MATRIX_DISTRIBUTOR.initialise_affine_matricies();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AffineMatrixDistributor {
|
|
||||||
const fn new() -> Self {
|
|
||||||
AffineMatrixDistributor {
|
|
||||||
tip: Static::new(u16::MAX),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn initialise_affine_matricies(&self) {
|
|
||||||
for i in 0..32 {
|
|
||||||
let ptr = (OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(i * 16 + 3);
|
|
||||||
|
|
||||||
if i == 31 {
|
|
||||||
// none
|
|
||||||
ptr.write_volatile(u16::MAX);
|
|
||||||
} else {
|
|
||||||
ptr.write_volatile(i as u16 + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tip.write(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn location_of(affine_matrix_location: u16) -> *mut u16 {
|
|
||||||
unsafe {
|
|
||||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(affine_matrix_location as usize * 16 + 3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_matrix(&self) -> Option<AffineMatrix> {
|
|
||||||
let location = self.tip.read();
|
|
||||||
if location == u16::MAX {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let next_tip = unsafe { Self::location_of(location).read_volatile() };
|
|
||||||
|
|
||||||
self.tip.write(next_tip);
|
|
||||||
|
|
||||||
Some(AffineMatrix {
|
|
||||||
location: AffineMatrixVram(Rc::new(AffineMatrixLocation { location })),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn return_matrix(&self, mat_id: u16) {
|
|
||||||
Self::location_of(mat_id).write_volatile(mat_id);
|
|
||||||
self.tip.write(mat_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use self::attributes::{
|
||||||
ObjectAttribute0, ObjectAttribute1Affine, ObjectAttribute1Standard, ObjectAttribute2,
|
ObjectAttribute0, ObjectAttribute1Affine, ObjectAttribute1Standard, ObjectAttribute2,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
pub struct Attributes {
|
pub struct Attributes {
|
||||||
a0: ObjectAttribute0,
|
a0: ObjectAttribute0,
|
||||||
a1s: ObjectAttribute1Standard,
|
a1s: ObjectAttribute1Standard,
|
||||||
|
@ -32,7 +32,7 @@ pub enum AffineMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attributes {
|
impl Attributes {
|
||||||
pub fn bytes(&self) -> [u8; 6] {
|
pub fn bytes(self) -> [u8; 6] {
|
||||||
let mode = self.a0.object_mode();
|
let mode = self.a0.object_mode();
|
||||||
let attrs = match mode {
|
let attrs = match mode {
|
||||||
ObjectMode::Normal => [
|
ObjectMode::Normal => [
|
||||||
|
@ -51,7 +51,7 @@ impl Attributes {
|
||||||
unsafe { core::mem::transmute(attrs) }
|
unsafe { core::mem::transmute(attrs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_visible(&self) -> bool {
|
pub fn is_visible(self) -> bool {
|
||||||
self.a0.object_mode() != ObjectMode::Disabled
|
self.a0.object_mode() != ObjectMode::Disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@ use super::attributes::{AffineMode, Attributes};
|
||||||
struct OamFrameModifyables {
|
struct OamFrameModifyables {
|
||||||
up_to: i32,
|
up_to: i32,
|
||||||
this_frame_sprites: Vec<SpriteVram>,
|
this_frame_sprites: Vec<SpriteVram>,
|
||||||
this_frame_affine: Vec<AffineMatrixVram>,
|
frame: u32,
|
||||||
|
affine_matrix_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UnmanagedOAM<'gba> {
|
pub struct UnmanagedOAM<'gba> {
|
||||||
phantom: PhantomData<&'gba ()>,
|
phantom: PhantomData<&'gba ()>,
|
||||||
frame_data: UnsafeCell<OamFrameModifyables>,
|
frame_data: UnsafeCell<OamFrameModifyables>,
|
||||||
previous_frame_sprites: Vec<SpriteVram>,
|
previous_frame_sprites: Vec<SpriteVram>,
|
||||||
previous_frame_affine: Vec<AffineMatrixVram>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OAMIterator<'oam> {
|
pub struct OAMIterator<'oam> {
|
||||||
|
@ -38,16 +38,29 @@ pub struct OAMSlot<'oam> {
|
||||||
|
|
||||||
impl OAMSlot<'_> {
|
impl OAMSlot<'_> {
|
||||||
pub fn set(&mut self, object: &UnmanagedObject) {
|
pub fn set(&mut self, object: &UnmanagedObject) {
|
||||||
self.set_bytes(object.attributes.bytes());
|
let mut attributes = object.attributes;
|
||||||
|
|
||||||
// SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM].
|
// SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM].
|
||||||
let frame_data = unsafe { &mut *self.frame_data.get() };
|
let frame_data = unsafe { &mut *self.frame_data.get() };
|
||||||
|
|
||||||
frame_data.this_frame_sprites.push(object.sprite.clone());
|
if let Some(affine_matrix) = &object.affine_matrix {
|
||||||
if let Some(affine) = &object.affine_matrix {
|
if affine_matrix.frame_count() != frame_data.frame {
|
||||||
frame_data.this_frame_affine.push(affine.clone());
|
affine_matrix.set_frame_count(frame_data.frame);
|
||||||
|
assert!(
|
||||||
|
frame_data.affine_matrix_count <= 32,
|
||||||
|
"too many affine matricies in one frame"
|
||||||
|
);
|
||||||
|
affine_matrix.set_location(frame_data.affine_matrix_count);
|
||||||
|
frame_data.affine_matrix_count += 1;
|
||||||
|
affine_matrix.write_to_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attributes.set_affine_matrix(affine_matrix.location() as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_bytes(attributes.bytes());
|
||||||
|
|
||||||
|
frame_data.this_frame_sprites.push(object.sprite.clone());
|
||||||
|
|
||||||
frame_data.up_to = self.slot as i32;
|
frame_data.up_to = self.slot as i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +109,8 @@ impl UnmanagedOAM<'_> {
|
||||||
pub fn iter(&mut self) -> OAMIterator<'_> {
|
pub fn iter(&mut self) -> OAMIterator<'_> {
|
||||||
let frame_data = self.frame_data.get_mut();
|
let frame_data = self.frame_data.get_mut();
|
||||||
frame_data.up_to = -1;
|
frame_data.up_to = -1;
|
||||||
|
frame_data.frame = frame_data.frame.wrapping_add(1);
|
||||||
|
frame_data.affine_matrix_count = 0;
|
||||||
|
|
||||||
// We drain the previous frame sprites here to reuse the Vecs allocation and remove the now unused sprites.
|
// We drain the previous frame sprites here to reuse the Vecs allocation and remove the now unused sprites.
|
||||||
// Any sprites currently being shown will now be put in the new Vec.
|
// Any sprites currently being shown will now be put in the new Vec.
|
||||||
|
@ -105,13 +120,6 @@ impl UnmanagedOAM<'_> {
|
||||||
&mut self.previous_frame_sprites,
|
&mut self.previous_frame_sprites,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Drain previous frame affine matricies
|
|
||||||
self.previous_frame_affine.drain(..);
|
|
||||||
core::mem::swap(
|
|
||||||
&mut frame_data.this_frame_affine,
|
|
||||||
&mut self.previous_frame_affine,
|
|
||||||
);
|
|
||||||
|
|
||||||
OAMIterator {
|
OAMIterator {
|
||||||
index: 0,
|
index: 0,
|
||||||
frame_data: &self.frame_data,
|
frame_data: &self.frame_data,
|
||||||
|
@ -123,7 +131,6 @@ impl UnmanagedOAM<'_> {
|
||||||
frame_data: Default::default(),
|
frame_data: Default::default(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
previous_frame_sprites: Default::default(),
|
previous_frame_sprites: Default::default(),
|
||||||
previous_frame_affine: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,9 +228,7 @@ impl UnmanagedObject {
|
||||||
|
|
||||||
pub fn set_affine_matrix(&mut self, affine_matrix: AffineMatrix) -> &mut Self {
|
pub fn set_affine_matrix(&mut self, affine_matrix: AffineMatrix) -> &mut Self {
|
||||||
let vram = affine_matrix.vram();
|
let vram = affine_matrix.vram();
|
||||||
let location = vram.location();
|
|
||||||
self.affine_matrix = Some(vram);
|
self.affine_matrix = Some(vram);
|
||||||
self.attributes.set_affine_matrix(location);
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,6 @@ impl Gba {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub unsafe fn new_in_entry() -> Self {
|
pub unsafe fn new_in_entry() -> Self {
|
||||||
display::object::init_affine();
|
|
||||||
Self::single_new()
|
Self::single_new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue