Update to v068r02 release.

byuu says:

This adds mosaic improvements to the S-PPU dot renderer. Specifically,
it eliminates the mosaic_table entirely, and performs mosaic adjustment
per pixel instead. It also moves from a mosaic countdown for mosaic Y to
a mosaic counter (incrementing).

In the process, I realized Sim Earth's map was broken, so I fixed that.
In doing so, I also fixed my old Mode7 demo that was always off-by-one,
causing different results on real hardware versus emulation. But then
I broke both Final Fantasy 5 and Air Strike Patrol effects that use
Mode7 but no mosaic.

I'm not really sure what's going on, but I think I am close. This is the
first time I can reproduce the Mode7 test ROM results without screwing
with M7Y which was obviously wrong. I think that somehow a mosaic >=
1 is glitching the Ycounter for the BG layers to tick one extra time.

There's a workaround that's not very nice to get everything going right
now. It could very well be that the workaround is hardware accurate, but
I can't help but feel there's a more eloquent way of doing this.
This commit is contained in:
Tim Allen 2010-08-28 19:47:06 +10:00
parent 920d139302
commit 39b1acb177
7 changed files with 52 additions and 46 deletions

View File

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

View File

@ -2,20 +2,26 @@
#include "mode7.cpp"
void PPU::Background::frame() {
}
void PPU::Background::scanline() {
if(self.vcounter() == 1) {
t.mosaic_y = 1;
t.mosaic_countdown = 0;
} else {
if(!regs.mosaic || !t.mosaic_countdown) t.mosaic_y = self.vcounter();
if(!t.mosaic_countdown) t.mosaic_countdown = regs.mosaic + 1;
t.mosaic_countdown--;
t.mosaic_y = regs.mosaic ? 1 : 0; //TODO: this is most likely incorrect
t.mosaic_vcounter = 0;
}
t.x = 0;
if(t.mosaic_vcounter++ == regs.mosaic) {
t.mosaic_vcounter = 0;
t.mosaic_y += regs.mosaic + 1;
}
t.mosaic_x = 0;
t.mosaic_hcounter = 0;
}
void PPU::Background::run() {
if(self.vcounter() == 0) return;
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
if((self.hcounter() & 2) == 0) {
@ -28,9 +34,13 @@ void PPU::Background::run() {
if(regs.mode == Mode::Inactive) return;
if(regs.main_enabled == false && regs.sub_enabled == false) return;
unsigned x = t.x++;
unsigned x = t.mosaic_x;
unsigned y = t.mosaic_y;
if(regs.mode == Mode::Mode7) return run_mode7(x, y);
if(t.mosaic_hcounter++ == regs.mosaic) {
t.mosaic_hcounter = 0;
t.mosaic_x += regs.mosaic + 1;
}
if(regs.mode == Mode::Mode7) return run_mode7();
unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
unsigned palette_offset = (self.regs.bgmode == 0 ? (id << 5) : 0);
@ -56,7 +66,7 @@ void PPU::Background::run() {
if(self.regs.interlace) y = (y << 1) + self.field();
}
unsigned hoffset = hscroll + mosaic_table[regs.mosaic][x];
unsigned hoffset = hscroll + x;
unsigned voffset = vscroll + y;
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
@ -215,9 +225,11 @@ unsigned PPU::Background::get_color(unsigned x, unsigned y, uint16 offset) {
}
void PPU::Background::reset() {
t.x = 0;
t.mosaic_x = 0;
t.mosaic_y = 0;
t.mosaic_countdown = 0;
t.mosaic_hcounter = 0;
t.mosaic_vcounter = 0;
regs.tiledata_addr = 0;
regs.screen_addr = 0;
regs.screen_size = 0;
@ -230,6 +242,7 @@ void PPU::Background::reset() {
regs.sub_enabled = 0;
regs.hoffset = 0;
regs.voffset = 0;
output.main.palette = 0;
output.main.priority = 0;
output.sub.palette = 0;
@ -237,13 +250,6 @@ void PPU::Background::reset() {
}
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) {
for(unsigned m = 0; m < 16; m++) {
for(unsigned x = 0; x < 4096; x++) {
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
}
}
}
uint16 PPU::Background::mosaic_table[16][4096];
#endif

View File

@ -9,9 +9,10 @@ public:
struct TileSize { enum { Size8x8, Size16x16 }; };
struct {
unsigned x;
unsigned mosaic_x;
unsigned mosaic_y;
unsigned mosaic_countdown;
unsigned mosaic_hcounter;
unsigned mosaic_vcounter;
} t;
struct {
@ -40,6 +41,7 @@ public:
} main, sub;
} output;
void frame();
void scanline();
void run();
unsigned get_tile(unsigned x, unsigned y);
@ -50,9 +52,7 @@ public:
Background(PPU &self, unsigned id);
private:
static uint16 mosaic_table[16][4096];
//mode7.cpp
signed clip(signed n);
void run_mode7(unsigned x, unsigned y);
void run_mode7();
};

View File

@ -5,7 +5,7 @@ signed PPU::Background::clip(signed n) {
return n & 0x2000 ? (n | ~1023) : (n & 1023);
}
void PPU::Background::run_mode7(unsigned x, unsigned y) {
void PPU::Background::run_mode7() {
signed a = sclip<16>(self.regs.m7a);
signed b = sclip<16>(self.regs.m7b);
signed c = sclip<16>(self.regs.m7c);
@ -16,24 +16,16 @@ void PPU::Background::run_mode7(unsigned x, unsigned y) {
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
signed voffset = sclip<13>(self.regs.mode7_voffset);
unsigned x = t.mosaic_x;
unsigned y = self.bg1.t.mosaic_y; //BG2 vertical mosaic uses BG1 mosaic size
if(self.regs.mode7_hflip) x = 255 - x;
if(self.regs.mode7_vflip) y = 255 - y;
unsigned mosaic_x;
unsigned mosaic_y;
if(id == ID::BG1) {
mosaic_x = mosaic_table[self.bg1.regs.mosaic][x];
mosaic_y = mosaic_table[self.bg1.regs.mosaic][y];
} else if(id == ID::BG2) {
mosaic_x = mosaic_table[self.bg2.regs.mosaic][x];
mosaic_y = mosaic_table[self.bg1.regs.mosaic][y]; //BG2 vertical mosaic uses BG1 mosaic size
}
signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * mosaic_y) & ~63) + (cx << 8);
signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * mosaic_y) & ~63) + (cy << 8);
signed px = psx + (a * mosaic_x);
signed py = psy + (c * mosaic_x);
signed px = psx + (a * x);
signed py = psy + (c * x);
//mask pseudo-FP bits
px >>= 8;

View File

@ -106,7 +106,14 @@ void PPU::reset() {
}
void PPU::scanline() {
if(vcounter() == 0) frame();
if(vcounter() == 0) {
frame();
bg1.frame();
bg2.frame();
bg3.frame();
bg4.frame();
}
bg1.scanline();
bg2.scanline();
bg3.scanline();

View File

@ -89,9 +89,10 @@ void PPU::serialize(serializer &s) {
void PPU::Background::serialize(serializer &s) {
s.integer(id);
s.integer(t.x);
s.integer(t.mosaic_x);
s.integer(t.mosaic_y);
s.integer(t.mosaic_countdown);
s.integer(t.mosaic_hcounter);
s.integer(t.mosaic_vcounter);
s.integer(regs.tiledata_addr);
s.integer(regs.screen_addr);

View File

@ -1,12 +1,12 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "068.01";
static const unsigned SerializerVersion = 12;
static const char Version[] = "068.02";
static const unsigned SerializerVersion = 13;
}
}
#define DEBUGGER
//#define DEBUGGER
#define CHEAT_SYSTEM
#include <libco/libco.h>