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 include nall/Makefile
snes := snes snes := snes
profile := compatibility profile := accuracy
ui := qt ui := qt
# compiler # compiler

View File

@@ -2,20 +2,26 @@
#include "mode7.cpp" #include "mode7.cpp"
void PPU::Background::frame() {
}
void PPU::Background::scanline() { void PPU::Background::scanline() {
if(self.vcounter() == 1) { if(self.vcounter() == 1) {
t.mosaic_y = 1; t.mosaic_y = regs.mosaic ? 1 : 0; //TODO: this is most likely incorrect
t.mosaic_countdown = 0; t.mosaic_vcounter = 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.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() { void PPU::Background::run() {
if(self.vcounter() == 0) return;
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
if((self.hcounter() & 2) == 0) { if((self.hcounter() & 2) == 0) {
@@ -28,9 +34,13 @@ void PPU::Background::run() {
if(regs.mode == Mode::Inactive) return; if(regs.mode == Mode::Inactive) return;
if(regs.main_enabled == false && regs.sub_enabled == false) 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; 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 color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
unsigned palette_offset = (self.regs.bgmode == 0 ? (id << 5) : 0); 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(); 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; unsigned voffset = vscroll + y;
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) { 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() { void PPU::Background::reset() {
t.x = 0; t.mosaic_x = 0;
t.mosaic_y = 0; t.mosaic_y = 0;
t.mosaic_countdown = 0; t.mosaic_hcounter = 0;
t.mosaic_vcounter = 0;
regs.tiledata_addr = 0; regs.tiledata_addr = 0;
regs.screen_addr = 0; regs.screen_addr = 0;
regs.screen_size = 0; regs.screen_size = 0;
@@ -230,6 +242,7 @@ void PPU::Background::reset() {
regs.sub_enabled = 0; regs.sub_enabled = 0;
regs.hoffset = 0; regs.hoffset = 0;
regs.voffset = 0; regs.voffset = 0;
output.main.palette = 0; output.main.palette = 0;
output.main.priority = 0; output.main.priority = 0;
output.sub.palette = 0; output.sub.palette = 0;
@@ -237,13 +250,6 @@ void PPU::Background::reset() {
} }
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) { 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 #endif

View File

@@ -9,9 +9,10 @@ public:
struct TileSize { enum { Size8x8, Size16x16 }; }; struct TileSize { enum { Size8x8, Size16x16 }; };
struct { struct {
unsigned x; unsigned mosaic_x;
unsigned mosaic_y; unsigned mosaic_y;
unsigned mosaic_countdown; unsigned mosaic_hcounter;
unsigned mosaic_vcounter;
} t; } t;
struct { struct {
@@ -40,6 +41,7 @@ public:
} main, sub; } main, sub;
} output; } output;
void frame();
void scanline(); void scanline();
void run(); void run();
unsigned get_tile(unsigned x, unsigned y); unsigned get_tile(unsigned x, unsigned y);
@@ -50,9 +52,7 @@ public:
Background(PPU &self, unsigned id); Background(PPU &self, unsigned id);
private: private:
static uint16 mosaic_table[16][4096];
//mode7.cpp //mode7.cpp
signed clip(signed n); 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); 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 a = sclip<16>(self.regs.m7a);
signed b = sclip<16>(self.regs.m7b); signed b = sclip<16>(self.regs.m7b);
signed c = sclip<16>(self.regs.m7c); 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 hoffset = sclip<13>(self.regs.mode7_hoffset);
signed voffset = sclip<13>(self.regs.mode7_voffset); 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_hflip) x = 255 - x;
if(self.regs.mode7_vflip) y = 255 - y; if(self.regs.mode7_vflip) y = 255 - y;
unsigned mosaic_x; signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
unsigned mosaic_y; signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
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 * mosaic_y) & ~63) + (cx << 8); signed px = psx + (a * x);
signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * mosaic_y) & ~63) + (cy << 8); signed py = psy + (c * x);
signed px = psx + (a * mosaic_x);
signed py = psy + (c * mosaic_x);
//mask pseudo-FP bits //mask pseudo-FP bits
px >>= 8; px >>= 8;

View File

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

View File

@@ -89,9 +89,10 @@ void PPU::serialize(serializer &s) {
void PPU::Background::serialize(serializer &s) { void PPU::Background::serialize(serializer &s) {
s.integer(id); s.integer(id);
s.integer(t.x); s.integer(t.mosaic_x);
s.integer(t.mosaic_y); 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.tiledata_addr);
s.integer(regs.screen_addr); s.integer(regs.screen_addr);

View File

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