Skip to content

Commit

Permalink
Implement 512px high res (mode 5, 6)
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed May 4, 2024
1 parent 6701b34 commit b3539ad
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 131 deletions.
4 changes: 2 additions & 2 deletions src/frontend/sdl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ impl Renderer for SDLRenderer {
let window = video_subsystem
.window(
"Siena SNES emulator",
(width * 3).try_into()?,
(height * 3).try_into()?,
(width * 2).try_into()?,
(height * 2).try_into()?,
)
.position_centered()
.build()?;
Expand Down
23 changes: 14 additions & 9 deletions src/snes/ppu/ppu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use std::sync::Arc;
use std::thread::sleep;
use std::time::{Duration, Instant};

pub const SCREEN_WIDTH: usize = 8 * 32;
pub const SCREEN_HEIGHT: usize = 8 * 28;
pub const SCREEN_WIDTH: usize = 512;
pub const SCREEN_HEIGHT: usize = 448;

// The entire screen should be shifted up by 1 scanline
const SCANLINE_OUTPUT_OFFSET: isize = -1;
Expand Down Expand Up @@ -185,19 +185,24 @@ where

pub fn render_scanline(&mut self, scanline: usize, output_offset: isize) {
let output_line = usize::try_from((scanline as isize) + output_offset).unwrap();
if output_line >= SCREEN_HEIGHT {
return;
}
let upper_line = output_line * 2;
let lower_line = upper_line + 1;

let mut t_state = self.state.clone();
let t_buffer = self.renderer.as_mut().unwrap().get_buffer();

self.pool.execute(move || {
let line = t_state.render_scanline(scanline);
for (x, color) in line.into_iter().enumerate() {
let idx = ((output_line * SCREEN_WIDTH) + x) * 4;
t_buffer[idx].store(color.2.into(), Ordering::Release);
t_buffer[idx + 1].store(color.1.into(), Ordering::Release);
t_buffer[idx + 2].store(color.0.into(), Ordering::Release);
let idx_upper = ((upper_line * SCREEN_WIDTH) + x) * 4;
t_buffer[idx_upper].store(color.2.into(), Ordering::Release);
t_buffer[idx_upper + 1].store(color.1.into(), Ordering::Release);
t_buffer[idx_upper + 2].store(color.0.into(), Ordering::Release);

let idx_lower = ((lower_line * SCREEN_WIDTH) + x) * 4;
t_buffer[idx_lower].store(color.2.into(), Ordering::Release);
t_buffer[idx_lower + 1].store(color.1.into(), Ordering::Release);
t_buffer[idx_lower + 2].store(color.0.into(), Ordering::Release);
}
});
}
Expand Down
33 changes: 21 additions & 12 deletions src/snes/ppu/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,11 @@ impl PPUState {

let bghofs = self.bgxhofs[bg] as usize;
let bgvofs = self.bgxvofs[bg] as usize;
let tilesize = self.get_bg_tile_size(bg);
let (tilewidth, tileheight) = self.get_bg_tile_size(bg);
let scale = self.get_screen_mode_scale_bg();

let mut x = 0;
'line: while x < SCREEN_WIDTH {
'line: while x < (SCREEN_WIDTH / scale) {
// Get adjusted offsets for offset-per-tile (if applicable)
let (thofs, tvofs) = self.adjust_offsets_opt(bg, x, bghofs, bgvofs);

Expand All @@ -190,8 +191,8 @@ impl PPUState {

// Determine coordinates within the tile. This is
// a full tile (so either 8x8 or 16x16).
let px_x = (x + thofs) % tilesize;
let px_y = (scanline + tvofs) % tilesize;
let px_x = (x + thofs) % tilewidth;
let px_y = (scanline + tvofs) % tileheight;
// get_bg_tile will select the sub-tile (for 16x16).
let tile = self.get_bg_tile(bg, &entry, px_x, px_y);

Expand Down Expand Up @@ -246,6 +247,8 @@ impl PPUState {
// This is also why scanline 0 is never rendered.
let scanline = scanline - 1;

let scale = self.get_screen_mode_scale_sprites();

for idx in 0..OAM_ENTRIES {
let prio_idx = if self.oam_priority {
// Priority rotation enabled
Expand All @@ -261,7 +264,7 @@ impl PPUState {

if (e.y..(e.y + e.height)).contains(&scanline) {
for x in e.x..(e.x + e.width as i32) {
if x >= state.idx.len() as i32 || x < 0 {
if (x * scale as i32) >= state.idx.len() as i32 || x < 0 {
// Outside of visible area.
continue;
}
Expand All @@ -284,18 +287,21 @@ impl PPUState {
((scanline - e.y) / TILE_HEIGHT) as usize,
);
// Should be positive from here on
let x = x as usize;
let x = (x as usize) * scale;

let sprite = self.get_sprite_tile(&e, t_x, t_y);

let coloridx = sprite.get_coloridx(in_x, in_y, &self.vram);
if coloridx == 0 || state.idx[x] != 0 {
continue;
}
state.idx[x] = coloridx;
state.palette[x] = sprite.oam.palette();
state.paletted[x] = self.sprite_cindex_to_color(&sprite, coloridx);
state.layer[x] = LAYER_SPRITES;

for ix in x..(x + scale) {
state.idx[ix] = coloridx;
state.palette[ix] = sprite.oam.palette();
state.paletted[ix] = self.sprite_cindex_to_color(&sprite, coloridx);
state.layer[ix] = LAYER_SPRITES;
}
}
}
}
Expand Down Expand Up @@ -507,10 +513,11 @@ impl PPUState {
);

// Send line to screen buffer
let scale = self.get_screen_mode_scale_bg();
let brightness = (self.inidisp & 0x0F) as usize;

let mut out: ArrayVec<Color, SCREEN_WIDTH> = ArrayVec::new();
for x in 0..SCREEN_WIDTH {
for x in 0..(SCREEN_WIDTH / scale) {
if brightness == 0 || self.inidisp & 0x80 != 0 {
// Force blank or no brightness
out.push(SnesColor::BLACK.to_native());
Expand All @@ -531,7 +538,9 @@ impl PPUState {
};

// Apply master brightness and output
out.push(pixel.apply_brightness(brightness).to_native());
for _ in 0..scale {
out.push(pixel.apply_brightness(brightness).to_native());
}
}

out
Expand Down
46 changes: 36 additions & 10 deletions src/snes/ppu/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,31 @@ impl PPUState {
TilemapEntry(self.vram[self.get_tilemap_offset(bg, tileidx)])
}

/// Returns the active PPU mode.
pub(super) fn get_screen_mode(&self) -> u8 {
self.bgmode & 0x07
}

/// Returns the horizontal scaling factor of the active PPU mode,
/// for backgrounds, based on the full resolution (512).
/// Does not look at pseudo high res.
pub(super) fn get_screen_mode_scale_bg(&self) -> usize {
match self.get_screen_mode() {
5 | 6 => 1,
_ => 2,
}
}

/// Returns the horizontal scaling factor of the active PPU mode,
/// for sprites, based on the full resolution (512).
/// Does not look at pseudo high res.
pub(super) fn get_screen_mode_scale_sprites(&self) -> usize {
match self.get_screen_mode() {
5 | 6 => 2,
_ => 1,
}
}

pub(super) fn get_tilemap_dimensions(&self, bg: usize) -> TilemapDimensions {
TilemapDimensions::from_u8(self.bgxsc[bg] & 0x03).unwrap()
}
Expand All @@ -289,7 +310,7 @@ impl PPUState {
) -> TilemapEntry {
debug_assert!(self.get_screen_mode() != 7);

let tilesize = self.get_bg_tile_size(bg);
let (tilewidth, tileheight) = self.get_bg_tile_size(bg);

// AA BB CC DD, size = 0x800 per sub-map
// 00 32x32 AA
Expand All @@ -306,8 +327,8 @@ impl PPUState {
TilemapDimensions::D64x32 => (true, false),
TilemapDimensions::D64x64 => (true, true),
};
let tm_x = (bghofs + x) / tilesize;
let tm_y = (bgvofs + y) / tilesize;
let tm_x = (bghofs + x) / tilewidth;
let tm_y = (bgvofs + y) / tileheight;

// 32 tiles per row in the sub-map, 0-31
let mut idx = ((tm_y & 0x1F) << 5) + (tm_x & 0x1F);
Expand Down Expand Up @@ -406,10 +427,11 @@ impl PPUState {
// T+00 T+01
// T+16 T+17
let mut tilenr = entry.charnr() as usize;
if self.get_bg_tile_size(bg) == 16 && (px_x >= TILE_WIDTH) == !entry.flip_x() {
let (tilewidth, tileheight) = self.get_bg_tile_size(bg);
if tilewidth == 16 && (px_x >= TILE_WIDTH) == !entry.flip_x() {
tilenr += 1;
}
if self.get_bg_tile_size(bg) == 16 && (px_y >= TILE_HEIGHT) == !entry.flip_y() {
if tileheight == 16 && (px_y >= TILE_HEIGHT) == !entry.flip_y() {
tilenr += 16;
}

Expand All @@ -421,11 +443,15 @@ impl PPUState {
}
}

pub(super) fn get_bg_tile_size(&self, bg: usize) -> usize {
if self.bgmode & (1 << (4 + bg)) != 0 {
16
} else {
8
/// Returns the size in pixels (width, height) of a bg tile
pub(super) fn get_bg_tile_size(&self, bg: usize) -> (usize, usize) {
match self.get_screen_mode() {
0..=5 if self.bgmode & (1 << (4 + bg)) != 0 => (16, 16),
0..=4 => (8, 8),
5 => (16, 8),
6 => (16, 16),
7 => (8, 8),
_ => unreachable!(),
}
}
}
44 changes: 22 additions & 22 deletions src/test/peterlemon_65816.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,93 +27,93 @@ macro_rules! test {

test!(
ADC,
"90c7029b247df20706c49d7fe590c2f37be0438fd7d6463084aa840e9cc1a61a"
"09e1e039d4ce04db11444c391dce4278fd9454a156ac00550c0e67a809afb0f4"
);
test!(
AND,
"a07825d3bf9a4a5d138ff131877e976e640a055a2c37872a14f971bda49207ae"
"5883aff6b941092a4537000267f39c85d2e98a276d65346b992f92b185d836ab"
);
test!(
ASL,
"5173b94d17861fc73c3225ca62718f3c6575892b305486aade1f175f8e28afde"
"4c8fb96e050fbefbc8b34891ba2d7a62ba60390291542674b3aadb20d2e28bd9"
);
test!(
BIT,
"b6d935d42a4034d337a5e9993920b9923195892e9a85dfd32a765854b9af17e5"
"6b979e59f0b84c114a78eecd5dc1be918ded4273d955a0c1cfd4782091a57fba"
);
test!(
BRA,
"9a92b3f53290c22c2df30ab91de88f2697a66c07ac9362e726c3c1dca2e3011d"
"855ad6b651be7bc54a79ca05ba5b3026527aab37c4f11112a17a2f3e3e535917"
);
test!(
CMP,
"f212561a035b42936b3a495457c1a09d6dfc93990a9a82b02996b089ebe9026e"
"f1d0681e1a5784a04be5e2c7dec14ef7eb2f440de68f834f8fb3d0e155e5a522"
);
test!(
DEC,
"d78763079aec92e7340f896f3fea58477e933c8a5c7a2ba61bae5e6832aeaeb4"
"bded97b61ade7ddc4c04f056d32fa161ee202388adbd09fdc7ffcaf17edb248d"
);
test!(
EOR,
"87e9f07695a9945da509f578a5ddb4b8ef8aebc6365a99b47f282d6d07a5efcd"
"f93f0d8d4c4a82f015f54437bcb70f76c1c7404ac4c691291e05fdf3f4522690"
);
test!(
INC,
"ee5fd161a95a36104e00f7ef5c410de585205ac9c47504419a329fd87516de12"
"66a3ad9b024c502fb57a6dbe84a48e771b38c790289935d9f0aca403de787edd"
);
test!(
JMP,
"0107a1e933c74b74a1fc7f2bea324c7437e86e4ab66b3b1e9577f62e59875a4b"
"99a7d5e4b8d6d3a2a3e9a913ff6ade1e36f8dc1ba9aa7b966c921947becfa64c"
);
test!(
LDR,
"94d2b2d46228116116fca7b51f2ac3381a4a84b8b39df2a5c383fbe4d6d15c10"
"b17468cc1c7cd6585fd022247af8ad2d45f50b048f47930893464dce46e93ac1"
);
test!(
LSR,
"4f3154db684d2f03d0b2d5f96e78c34794134d77a628d67311d7129dab1805f7"
"231b26a5f0f68adf5c43e99cf556482e38aa51a89b400729d6036de372903206"
);
test!(
MOV,
"396113963ba0219f88e7f0dc3c2dff0362511c755e36c6522f63f80a4ad89c39"
"a935507f18286e8527a0a056ec0ac5f482daa1b13fefa9e5d5580a1ebe216f4a"
);
//test!(
// MSC,
// ""
//);
test!(
ORA,
"5cb7b05939edf71c82f4c1f8f9bc3ec75b561ca2c8499804c188bcb723f77d46"
"7c4c14dab0163ab0c05adf114f741bae6344973cb8636571cdbd8850f9c9caad"
);
test!(
PHL,
"c93495aafedc6d6b789ec760dbe57a20077be87bcd4493cd393e209890b2cc38"
"ccd2830e7da40fe7ee4ff45fa96d579508868bf93956fbc0039c1c2118c910b5"
);
test!(
PSR,
"3ec1f1d7c405eebef52eb3c8755f2987377f35d4f7b60671e127b2a734d23d3b"
"2cc82ca6150945d6e6e54b2726e17f27f2b7c3e8aeede349dcca5032d5e1208f"
);
test!(
RET,
"9a16006eadafef71059192295cc791239deeafd1008eed2e7296b2481692e93f"
"60ff23a891458de47c736cab93b1da275045809f314ad8bb034475dfdb82ad88"
);
test!(
ROL,
"387d2e971dff021feaee18bf71879561948afc285e409b2de34b5c70451cd043"
"c340d41e39c8818c10d329556d96a790a6661c3d834984f81396215f0ce706f5"
);
test!(
ROR,
"409f998b8fec3eb0e7c04a67734311ab04dad48a3f6b12194cacf09c5ca299a0"
"cbec3c3ad79e4ce60068b99d1733ac8aecebd3f24a491179644c5462a1a986e8"
);
test!(
SBC,
"0319caa2c83fad543bfe4826aa454f514fc5e9089b9c981601e0fa8f56f37285"
"a379af0bad0687a51f7aefd2887dda837508b2fa50ab8b61db3f8dcff15bb184"
);
test!(
STR,
"920b22b58157811affcea80730cfd3bf9dd83a8453896e0f2e60e47c8c15aaef"
"aa0a524afd646b589f83dabd2fc4d94ca941ea4ecdb69a29ff88705b75582df5"
);
test!(
TRN,
"58354be3f8257551b7a71991f535dedd80afb4c8a344f40147cd1deac1cd7775"
"d29eb5016ffff391324c79d7a4cd1f52cda2e811ce8cbbd35775b313370b5671"
);
10 changes: 5 additions & 5 deletions src/test/peterlemon_bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,25 @@ macro_rules! hirom_test {
hirom_test!(
BANKHiROMFastROM,
"HiROMFastROM/BANKHiROMFastROM.sfc",
"2ab4871e60935c6fcaf06a40849912f7b8ad23f8e850bb0f03d2576e96664536"
"d777408bf78b94b7cde5331f9b2669de066b4df1f744751c1aff4205f290f35a"
);
hirom_test!(
BANKHiROMSlowROM,
"HiROMSlowROM/BANKHiROMSlowROM.sfc",
"36ab039767172d7a452d6337f7703627e912e8ffc833b10e3eb3467b1cc38e60"
"af47aefcfd6f0a0842d7ef117d4539d8d3c1ae1e97ea713df8167fce8b81458c"
);
lorom_test!(
BANKLoROMFastROM,
"LoROMFastROM/BANKLoROMFastROM.sfc",
"1f2385252686bc02246eed8d670ee46d1bd01e25ad3c0a217dcb84a180e2f045"
"ba0b954785794fd831d84de131fb022b252aceab6fe1d2dbf154fcbab9ac0f41"
);
lorom_test!(
BANKLoROMSlowROM,
"LoROMSlowROM/BANKLoROMSlowROM.sfc",
"89b0ae2ce790bceaa0ea97f780b78e69546e812c0539a39b810d6e87f7d2f379"
"09e7951a9d0ccee76f6e7c388a452d7e107a46703ae61e1272af661e1540973c"
);
lorom_test!(
BANKWRAM,
"WRAM/BANKWRAM.sfc",
"c54861d958c14c00b9eadfe2727b0ce9c4b6e25411cf1b833efe337714b61a6c"
"fa69f0d486b66e4825fcc1a9c94a70ef4a748c748ae9c75e888302543209470e"
);
Loading

0 comments on commit b3539ad

Please sign in to comment.