mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-11 22:44:11 +02:00
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:
@@ -1,6 +1,6 @@
|
|||||||
include nall/Makefile
|
include nall/Makefile
|
||||||
snes := snes
|
snes := snes
|
||||||
profile := compatibility
|
profile := accuracy
|
||||||
ui := qt
|
ui := qt
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
|
@@ -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
|
||||||
|
@@ -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();
|
||||||
};
|
};
|
||||||
|
@@ -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;
|
||||||
|
@@ -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();
|
||||||
|
@@ -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);
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user