Update to v068r13 release.

byuu says:

Bug-fix night for the new PPUs.

Accuracy:

Fixed BG palette clamping, which fixes Taz-Mania.

Added blocking for CGRAM writes during active display, to match the
compatibility core. It really should override to the last fetched
palette color, I'll probably try that out soon enough.

Performance:

Mosaic should match the other renderers. Unfortunately, as suspected, it
murders speed. 290->275fps. It's now only 11fps faster, hardly worth it
at all. But the old rendering code is really awful, so maybe it's for
the best it gets refreshed.
It's really tough to understand why this is such a performance hit, it's
just a decrement+compare check four times per pixel. But yeah, it hits
it really, really hard.

Fixed a missing check in Mode4 offset-per-tile, fixes vertical alignment
of a test image in the SNES Test Program.
This commit is contained in:
Tim Allen 2010-09-05 23:22:26 +10:00
parent 5b4702afc4
commit 3f43747474
9 changed files with 66 additions and 56 deletions

View File

@ -1,6 +1,6 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
profile := accuracy profile := performance
ui := qt ui := qt
# compiler # compiler

View File

@ -3,18 +3,18 @@
#include "mode7.cpp" #include "mode7.cpp"
unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) { unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
unsigned tile_x = hoffset >> tile_width; unsigned tile_x = (hoffset & mask_x) >> tile_width;
unsigned tile_y = voffset >> tile_height; unsigned tile_y = (voffset & mask_y) >> tile_height;
unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f); unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f);
if(tile_y & 0x20) tile_pos += scy; if(tile_y & 0x20) tile_pos += scy;
if(tile_x & 0x20) tile_pos += scx; if(tile_x & 0x20) tile_pos += scx;
const unsigned tiledata_addr = regs.screen_addr + (tile_pos << 1); const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1);
return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8); return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8);
} }
void PPU::Background::offset_per_tile(unsigned x, unsigned &hoffset, unsigned &voffset) { void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset) {
unsigned opt_x = (x + (hscroll & 7)), hval, vval; unsigned opt_x = (x + (hscroll & 7)), hval, vval;
if(opt_x >= 8) { if(opt_x >= 8) {
hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0); hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
@ -23,9 +23,11 @@ void PPU::Background::offset_per_tile(unsigned x, unsigned &hoffset, unsigned &v
if(self.regs.bgmode == 4) { if(self.regs.bgmode == 4) {
if(hval & opt_valid_bit) { if(hval & opt_valid_bit) {
hoffset = opt_x + (hval & ~7); if(!(hval & 0x8000)) {
} else { hoffset = opt_x + (hval & ~7);
voffset = y + hval; } else {
voffset = y + hval;
}
} }
} else { } else {
if(hval & opt_valid_bit) { if(hval & opt_valid_bit) {
@ -39,7 +41,15 @@ void PPU::Background::offset_per_tile(unsigned x, unsigned &hoffset, unsigned &v
} }
void PPU::Background::scanline() { void PPU::Background::scanline() {
y = mosaic_table[regs.mosaic][self.vcounter()] + (regs.mosaic > 0); if(self.vcounter() == 1) {
mosaic_vcounter = regs.mosaic + 1;
y = 1;
} else if(--mosaic_vcounter == 0) {
mosaic_vcounter = regs.mosaic + 1;
y += regs.mosaic + 1;
}
if(self.regs.display_disable) return;
hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
width = !hires ? 256 : 512; width = !hires ? 256 : 512;
@ -66,6 +76,11 @@ void PPU::Background::render() {
if(regs.sub_enable) window.render(1); if(regs.sub_enable) window.render(1);
if(regs.mode == Mode::Mode7) return render_mode7(); if(regs.mode == Mode::Mode7) return render_mode7();
unsigned mosaic_hcounter = 1;
unsigned mosaic_palette = 0;
unsigned mosaic_priority = 0;
unsigned mosaic_color = 0;
const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0); const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0);
const unsigned pal_size = 2 << regs.mode; const unsigned pal_size = 2 << regs.mode;
const unsigned tile_mask = 0x0fff >> regs.mode; const unsigned tile_mask = 0x0fff >> regs.mode;
@ -74,6 +89,7 @@ void PPU::Background::render() {
hscroll = regs.hoffset; hscroll = regs.hoffset;
vscroll = regs.voffset; vscroll = regs.voffset;
unsigned y = Background::y;
if(hires) { if(hires) {
hscroll <<= 1; hscroll <<= 1;
if(self.regs.interlace) y = (y << 1) + self.field(); if(self.regs.interlace) y = (y << 1) + self.field();
@ -91,7 +107,7 @@ void PPU::Background::render() {
while(x < width) { while(x < width) {
hoffset = x + hscroll; hoffset = x + hscroll;
voffset = y + vscroll; voffset = y + vscroll;
if(is_opt_mode) offset_per_tile(x, hoffset, voffset); if(is_opt_mode) offset_per_tile(x, y, hoffset, voffset);
hoffset &= mask_x; hoffset &= mask_x;
voffset &= mask_y; voffset &= mask_y;
@ -100,53 +116,44 @@ void PPU::Background::render() {
mirror_x = tile_num & 0x4000; mirror_x = tile_num & 0x4000;
tile_pri = tile_num & 0x2000 ? regs.priority1 : regs.priority0; tile_pri = tile_num & 0x2000 ? regs.priority1 : regs.priority0;
pal_num = (tile_num >> 10) & 7; pal_num = (tile_num >> 10) & 7;
pal_index = bgpal_index + (pal_num << pal_size); pal_index = (bgpal_index + (pal_num << pal_size)) & 0xff;
if(tile_width == 4) { if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile_num += 1;
if((bool)(hoffset & 8) != mirror_x) tile_num++; if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_num += 16;
} tile_num = ((tile_num & 0x03ff) + tiledata_index) & tile_mask;
if(tile_height == 4) {
if((bool)(voffset & 8) != mirror_y) tile_num += 16;
}
tile_num &= 0x03ff;
tile_num += tiledata_index;
tile_num &= tile_mask;
if(mirror_y) voffset ^= 7; if(mirror_y) voffset ^= 7;
signed step = mirror_x ? -1 : +1; unsigned mirror_xmask = !mirror_x ? 0 : 7;
unsigned plot_x = x + (mirror_x ? 7 : 0);
uint8 *tiledata = self.cache.tile(regs.mode, tile_num); uint8 *tiledata = self.cache.tile(regs.mode, tile_num);
tiledata += ((voffset & 7) * 8); tiledata += ((voffset & 7) * 8);
for(unsigned n = 0; n < 8; n++) { for(unsigned n = 0; n < 8; n++, x++) {
unsigned col = tiledata[n & regs.mosaic_mask]; if(x & width) continue;
if(col && !(plot_x & width)) { if(--mosaic_hcounter == 0) {
unsigned color; mosaic_hcounter = regs.mosaic + 1;
mosaic_palette = tiledata[n ^ mirror_xmask];
mosaic_priority = tile_pri;
if(is_direct_color_mode) { if(is_direct_color_mode) {
color = self.screen.get_direct_color(pal_num, col); mosaic_color = self.screen.get_direct_color(pal_num, mosaic_palette);
} else { } else {
color = self.screen.get_palette(pal_index + col); mosaic_color = self.screen.get_palette(pal_index + mosaic_palette);
}
if(hires == false) {
if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, tile_pri, id);
if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, tile_pri, id);
} else {
signed half_x = plot_x >> 1;
if(plot_x & 1) {
if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, color, tile_pri, id);
} else {
if(regs.sub_enable && !window.sub[half_x]) self.screen.output.plot_sub(half_x, color, tile_pri, id);
}
} }
} }
plot_x += step; if(mosaic_palette == 0) continue;
}
x += 8; if(hires == false) {
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, mosaic_color, mosaic_priority, id);
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, mosaic_color, mosaic_priority, id);
} else {
signed half_x = x >> 1;
if(x & 1) {
if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, mosaic_color, mosaic_priority, id);
} else {
if(regs.sub_enable && !window.sub[half_x]) self.screen.output.plot_sub(half_x, mosaic_color, mosaic_priority, id);
}
}
}
} }
} }

View File

@ -11,7 +11,6 @@ class Background {
bool tile_size; bool tile_size;
unsigned mosaic; unsigned mosaic;
unsigned mosaic_mask;
unsigned screen_addr; unsigned screen_addr;
unsigned screen_size; unsigned screen_size;
@ -45,10 +44,12 @@ class Background {
unsigned hscroll; unsigned hscroll;
unsigned vscroll; unsigned vscroll;
unsigned mosaic_vcounter;
LayerWindow window; LayerWindow window;
alwaysinline unsigned get_tile(unsigned hoffset, unsigned voffset); alwaysinline unsigned get_tile(unsigned hoffset, unsigned voffset);
void offset_per_tile(unsigned x, unsigned &hoffset, unsigned &voffset); void offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset);
void scanline(); void scanline();
void render(); void render();
void render_mode7(); void render_mode7();

View File

@ -341,10 +341,6 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0);
bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0);
bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0);
bg4.regs.mosaic_mask = ~(bg4.regs.mosaic >> 1);
bg3.regs.mosaic_mask = ~(bg3.regs.mosaic >> 1);
bg2.regs.mosaic_mask = ~(bg2.regs.mosaic >> 1);
bg1.regs.mosaic_mask = ~(bg1.regs.mosaic >> 1);
return; return;
} }

View File

@ -56,11 +56,11 @@ void PPU::add_clocks(unsigned clocks) {
} }
void PPU::render_scanline() { void PPU::render_scanline() {
if(regs.display_disable) return screen.render_black();
bg1.scanline(); bg1.scanline();
bg2.scanline(); bg2.scanline();
bg3.scanline(); bg3.scanline();
bg4.scanline(); bg4.scanline();
if(regs.display_disable) return screen.render_black();
screen.scanline(); screen.scanline();
bg1.render(); bg1.render();
bg2.render(); bg2.render();

View File

@ -27,8 +27,8 @@ class Background {
struct Output { struct Output {
struct Pixel { struct Pixel {
unsigned priority; //0 = none (transparent) unsigned priority; //0 = none (transparent)
unsigned palette; uint8 palette;
unsigned tile; uint16 tile;
} main, sub; } main, sub;
} output; } output;

View File

@ -45,10 +45,16 @@ void PPU::oam_write(unsigned addr, uint8 data) {
} }
uint8 PPU::cgram_read(unsigned addr) { uint8 PPU::cgram_read(unsigned addr) {
if(!regs.display_disable && vcounter() < (!regs.overscan ? 225 : 240)) {
if(hcounter() >= 128 && hcounter() < 1096) addr = 0x0000;
}
return memory::cgram[addr]; return memory::cgram[addr];
} }
void PPU::cgram_write(unsigned addr, uint8 data) { void PPU::cgram_write(unsigned addr, uint8 data) {
if(!regs.display_disable && vcounter() < (!regs.overscan ? 225 : 240)) {
if(hcounter() >= 128 && hcounter() < 1096) addr = 0x0000;
}
memory::cgram[addr] = data; memory::cgram[addr] = data;
} }

View File

@ -55,7 +55,7 @@ class Sprite {
struct Output { struct Output {
struct Pixel { struct Pixel {
unsigned priority; //0 = none (transparent) unsigned priority; //0 = none (transparent)
unsigned palette; uint8 palette;
} main, sub; } main, sub;
} output; } output;

View File

@ -1,7 +1,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "068.12"; static const char Version[] = "068.13";
static const unsigned SerializerVersion = 13; static const unsigned SerializerVersion = 13;
} }
} }