Skip to content

Commit

Permalink
Mode3::clear_to is a very fast and easily-proven-correct clear routine.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lokathor committed May 31, 2024
1 parent aad5ddd commit 692a8b2
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 36 deletions.
41 changes: 6 additions & 35 deletions examples/paddle_ball.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
#![allow(unused_imports)]
/*
* Made by Evan Goemer
* Discord: @evangoemer
*/
#![no_std]
#![no_main]

use core::ptr::addr_of;
//! Made by Evan Goemer, Discord: @evangoemer

use gba::{
asm_runtime::USER_IRQ_HANDLER,
bios::VBlankIntrWait,
dma::{DmaControl, DmaSrcAddr},
gba_cell::GbaCell,
mem::bulk_memory_set,
mmio::{
DISPCNT, DISPSTAT, DMA3_CONTROL, DMA3_DESTINATION, DMA3_SOURCE,
DMA3_TRANSFER_COUNT, IE, IME, KEYINPUT, MODE3_VRAM, OBJ_PALRAM,
},
video::{Color, DisplayControl, DisplayStatus},
mmio::{DISPCNT, DISPSTAT, IE, IME, KEYINPUT, MODE3_VRAM},
video::{Color, DisplayControl, DisplayStatus, Mode3},
IrqBits, KeyInput,
};

Expand Down Expand Up @@ -151,29 +142,7 @@ fn main() -> ! {
}

extern "C" fn draw_sprites(_bits: IrqBits) {
/*
unsafe {
let color = OBJ_PALRAM.index(0).read();
let c: u32 = color.0 as u32 | (color.0 as u32) << 16;
DMA3_SOURCE.write(addr_of!(c).cast());
DMA3_DESTINATION.write(MODE3_VRAM.as_usize() as _);
DMA3_TRANSFER_COUNT.write(SCREEN_WIDTH * SCREEN_HEIGHT / 2);
DMA3_CONTROL.write(
DmaControl::new()
.with_src_addr(DmaSrcAddr::Fixed)
.with_u32_transfer(true)
.with_enabled(true),
);
}
// */
unsafe {
let dest = MODE3_VRAM.as_usize() as *mut u32;
let byte_count = SCREEN_WIDTH as usize
* SCREEN_HEIGHT as usize
* core::mem::size_of::<Color>();
let r2 = 0;
bulk_memory_set(dest, byte_count, r2);
}
Mode3.clear_to(Color::BLACK);

draw_rect(
SPRITE_POSITIONS[0].read(),
Expand All @@ -198,6 +167,8 @@ extern "C" fn draw_sprites(_bits: IrqBits) {
);
}

// we out-line this because otherwise `draw_sprites` overloads the stack when it
// holds 3 copies of this function.
#[inline(never)]
fn draw_rect(x: u16, y: u16, width: u16, height: u16, color: Color) {
for i in 0..width {
Expand Down
58 changes: 57 additions & 1 deletion src/video.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//!
//! Module for screen-related types and functions.

use bitfrob::{u16_get_bit, u16_with_bit, u16_with_value};

Expand Down Expand Up @@ -326,3 +326,59 @@ pub struct Tile4bpp(pub [u32; 8]);
#[derive(Clone, Copy, Default)]
#[repr(transparent)]
pub struct Tile8bpp(pub [u32; 16]);

/// A zero-sized type that gives a namespace for Mode 3 related things.
#[derive(Clone, Copy)]
pub struct Mode3;
impl Mode3 {
/// Width, in pixels, of the Mode 3 bitmap.
pub const WIDTH: usize = 240;

/// Height, in pixels, of the Mode 3 bitmap.
pub const HEIGHT: usize = 160;

/// The size, in bytes, of the Mode 3 bitmap.
pub const BYTES: usize =
Self::WIDTH * Self::HEIGHT * core::mem::size_of::<Color>();

/// Clears the entire bitmap to a color of your choosing.
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
#[cfg_attr(feature = "on_gba", link_section = ".iwram.mode3.clear_to")]
pub fn clear_to(self, color: Color) {
on_gba_or_unimplemented!(unsafe {
let x: u32 = color.0 as u32 | ((color.0 as u32) << 16);
// now we spam out that `u32`, 10 stm per loop, 8 times per stm.
core::arch::asm!(
"1:",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"stm {ptr}!, {{r0-r5,r7-r8}}",
"subs {count}, {count}, #1",
"bne 1b",

// The assembler will give us a warning (that we can't easily disable)
// if the reg_list for `stm` doesn't give the registers in order from
// low to high, so we just manually pick registers. The count register
// and the pointer register can be anything else.
in("r0") x,
in("r1") x,
in("r2") x,
in("r3") x,
in("r4") x,
in("r5") x,
in("r7") x,
in("r8") x,
count = inout(reg) 240 => _,
ptr = inout(reg) crate::mmio::MODE3_VRAM.as_usize() => _,
options(nostack),
)
});
}
}

0 comments on commit 692a8b2

Please sign in to comment.