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
snes := snes
profile := accuracy
profile := performance
ui := qt
# compiler

View File

@ -3,18 +3,18 @@
#include "mode7.cpp"
unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
unsigned tile_x = hoffset >> tile_width;
unsigned tile_y = voffset >> tile_height;
unsigned tile_x = (hoffset & mask_x) >> tile_width;
unsigned tile_y = (voffset & mask_y) >> tile_height;
unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f);
if(tile_y & 0x20) tile_pos += scy;
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);
}
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;
if(opt_x >= 8) {
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(hval & opt_valid_bit) {
hoffset = opt_x + (hval & ~7);
} else {
voffset = y + hval;
if(!(hval & 0x8000)) {
hoffset = opt_x + (hval & ~7);
} else {
voffset = y + hval;
}
}
} else {
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() {
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);
width = !hires ? 256 : 512;
@ -66,6 +76,11 @@ void PPU::Background::render() {
if(regs.sub_enable) window.render(1);
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 pal_size = 2 << regs.mode;
const unsigned tile_mask = 0x0fff >> regs.mode;
@ -74,6 +89,7 @@ void PPU::Background::render() {
hscroll = regs.hoffset;
vscroll = regs.voffset;
unsigned y = Background::y;
if(hires) {
hscroll <<= 1;
if(self.regs.interlace) y = (y << 1) + self.field();
@ -91,7 +107,7 @@ void PPU::Background::render() {
while(x < width) {
hoffset = x + hscroll;
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;
voffset &= mask_y;
@ -100,53 +116,44 @@ void PPU::Background::render() {
mirror_x = tile_num & 0x4000;
tile_pri = tile_num & 0x2000 ? regs.priority1 : regs.priority0;
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((bool)(hoffset & 8) != mirror_x) tile_num++;
}
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(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile_num += 1;
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_num += 16;
tile_num = ((tile_num & 0x03ff) + tiledata_index) & tile_mask;
if(mirror_y) voffset ^= 7;
signed step = mirror_x ? -1 : +1;
unsigned plot_x = x + (mirror_x ? 7 : 0);
unsigned mirror_xmask = !mirror_x ? 0 : 7;
uint8 *tiledata = self.cache.tile(regs.mode, tile_num);
tiledata += ((voffset & 7) * 8);
for(unsigned n = 0; n < 8; n++) {
unsigned col = tiledata[n & regs.mosaic_mask];
if(col && !(plot_x & width)) {
unsigned color;
for(unsigned n = 0; n < 8; n++, x++) {
if(x & width) continue;
if(--mosaic_hcounter == 0) {
mosaic_hcounter = regs.mosaic + 1;
mosaic_palette = tiledata[n ^ mirror_xmask];
mosaic_priority = tile_pri;
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 {
color = self.screen.get_palette(pal_index + col);
}
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);
}
mosaic_color = self.screen.get_palette(pal_index + mosaic_palette);
}
}
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;
unsigned mosaic;
unsigned mosaic_mask;
unsigned screen_addr;
unsigned screen_size;
@ -45,10 +44,12 @@ class Background {
unsigned hscroll;
unsigned vscroll;
unsigned mosaic_vcounter;
LayerWindow window;
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 render();
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);
bg2.regs.mosaic = (data & 0x02 ? 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;
}

View File

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

View File

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

View File

@ -45,10 +45,16 @@ void PPU::oam_write(unsigned addr, uint8 data) {
}
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];
}
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;
}

View File

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

View File

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