Improved vertical mosaic emulation.
This commit is contained in:
byuu 2020-01-16 05:09:52 +09:00
parent 55e78b03de
commit fb463d34ef
17 changed files with 118 additions and 76 deletions

View File

@ -29,13 +29,13 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "114";
static const string Version = "114.1";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org";
//incremented only when serialization format changes
static const string SerializerVersion = "112";
static const string SerializerVersion = "114.1";
namespace Constants {
namespace Colorburst {

View File

@ -1,15 +1,3 @@
//single-threaded
auto PPU::Line::cacheBackground(PPU::IO::Background& bg) -> void {
if(y == 1) {
bg.mosaicCounter = ppu.io.mosaicSize + 1;
bg.mosaicOffset = 1;
} else if(--bg.mosaicCounter == 0) {
bg.mosaicCounter = ppu.io.mosaicSize + 1;
bg.mosaicOffset += ppu.io.mosaicSize + 1;
}
}
//parallelized
auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> void {
if(!self.aboveEnable && !self.belowEnable) return;
if(self.tileMode == TileMode::Mode7) return renderMode7(self, source);
@ -39,10 +27,14 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi
uint hmask = (width << self.tileSize << !!(self.screenSize & 1)) - 1;
uint vmask = (width << self.tileSize << !!(self.screenSize & 2)) - 1;
uint y = self.mosaicEnable ? self.mosaicOffset : this->y;
uint y = this->y;
if(self.mosaicEnable) y -= io.mosaic.size - io.mosaic.counter;
if(hires) {
hscroll <<= 1;
if(io.interlace) y = y << 1 | field();
if(io.interlace) {
y = y << 1 | field();
if(self.mosaicEnable) y -= io.mosaic.size - io.mosaic.counter + ppu.field();
}
}
uint mosaicCounter = 1;
@ -103,7 +95,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi
for(uint tileX = 0; tileX < 8; tileX++, x++) {
if(x & width) continue; //x < 0 || x >= width
if(!self.mosaicEnable || --mosaicCounter == 0) {
if(--mosaicCounter == 0) {
uint color, shift = mirrorX ? tileX : 7 - tileX;
/*if(self.tileMode >= TileMode::BPP2)*/ {
color = data >> shift + 0 & 1;
@ -120,7 +112,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi
color += data >> shift + 49 & 128;
}
mosaicCounter = 1 + io.mosaicSize;
mosaicCounter = self.mosaicEnable ? io.mosaic.size : 1;
mosaicPalette = color;
mosaicPriority = tilePriority;
if(directColorMode) {

View File

@ -248,11 +248,17 @@ auto PPU::writeIO(uint address, uint8 data) -> void {
}
case 0x2106: { //MOSAIC
bool enable = io.bg1.mosaicEnable || io.bg2.mosaicEnable || io.bg3.mosaicEnable || io.bg4.mosaicEnable;
io.bg1.mosaicEnable = data >> 0 & 1;
io.bg2.mosaicEnable = data >> 1 & 1;
io.bg3.mosaicEnable = data >> 2 & 1;
io.bg4.mosaicEnable = data >> 3 & 1;
io.mosaicSize = data >> 4 & 15;
io.mosaic.enable = data >> 0 & 15;
io.mosaic.size = (data >> 4 & 15) + 1;
if(!enable && (data >> 0 & 15)) {
//mosaic vcounter is reloaded when mosaic becomes enabled
io.mosaic.counter = io.mosaic.size + 1;
}
return;
}

View File

@ -26,12 +26,13 @@ auto PPU::Line::flush() -> void {
}
auto PPU::Line::cache() -> void {
cacheBackground(ppu.io.bg1);
cacheBackground(ppu.io.bg2);
cacheBackground(ppu.io.bg3);
cacheBackground(ppu.io.bg4);
uint y = ppu.vcounter();
if(y == 1) {
ppu.io.mosaic.counter = ppu.io.mosaic.enable ? ppu.io.mosaic.size + 1 : 0;
}
if(ppu.io.mosaic.counter && !--ppu.io.mosaic.counter) {
ppu.io.mosaic.counter = ppu.io.mosaic.enable ? ppu.io.mosaic.size + 0 : 0;
}
if(ppu.io.displayDisable || y >= ppu.vdisp()) {
io.displayDisable = true;
} else {

View File

@ -1,11 +1,12 @@
auto PPU::Line::renderMode7(PPU::IO::Background& self, uint8 source) -> void {
//HD mode 7 support
if(!ppu.hdMosaic() || !self.mosaicEnable || !io.mosaicSize) {
if(!ppu.hdMosaic() || !self.mosaicEnable || !io.mosaic.size) {
if(ppu.hdScale() > 1) return renderMode7HD(self, source);
}
int Y = self.mosaicEnable ? self.mosaicOffset : this->y;
int Y = this->y;
int y = !io.mode7.vflip ? Y : 255 - Y;
if(self.mosaicEnable) y -= io.mosaic.size - io.mosaic.counter;
int a = (int16)io.mode7.a;
int b = (int16)io.mode7.b;
@ -50,8 +51,8 @@ auto PPU::Line::renderMode7(PPU::IO::Background& self, uint8 source) -> void {
palette &= 0x7f;
}
if(!self.mosaicEnable || --mosaicCounter == 0) {
mosaicCounter = 1 + io.mosaicSize;
if(--mosaicCounter == 0) {
mosaicCounter = self.mosaicEnable ? io.mosaic.size : 1;
mosaicPalette = palette;
mosaicPriority = priority;
if(io.col.directColor && source == Source::BG1) {

View File

@ -85,7 +85,6 @@ public:
bool oamPriority = 0;
bool bgPriority = 0;
uint8 bgMode = 0;
uint8 mosaicSize = 0;
bool vramIncrementMode = 0;
uint8 vramMapping = 0;
uint8 vramIncrementSize = 0;
@ -99,6 +98,15 @@ public:
bool pseudoHires = 0;
bool extbg = 0;
struct Mosaic {
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 enable = 0;
uint8 size = 1;
uint8 counter = 0;
} mosaic;
struct Mode7 {
//serialization.cpp
auto serialize(serializer&) -> void;
@ -161,8 +169,6 @@ public:
bool aboveEnable = 0;
bool belowEnable = 0;
bool mosaicEnable = 0;
uint16 mosaicCounter = 0;
uint16 mosaicOffset = 0;
uint16 tiledataAddress = 0;
uint16 screenAddress = 0;
uint8 screenSize = 0;
@ -293,7 +299,6 @@ public:
alwaysinline auto plotHD(Pixel*, uint x, uint8 source, uint8 priority, uint16 color, bool hires, bool subpixel) -> void;
//background.cpp
auto cacheBackground(PPU::IO::Background&) -> void;
auto renderBackground(PPU::IO::Background&, uint8 source) -> void;
auto getTile(PPU::IO::Background&, uint hoffset, uint voffset) -> uint;

View File

@ -44,7 +44,6 @@ auto PPU::IO::serialize(serializer& s) -> void {
s.integer(oamPriority);
s.integer(bgPriority);
s.integer(bgMode);
s.integer(mosaicSize);
s.integer(vramIncrementMode);
s.integer(vramMapping);
s.integer(vramIncrementSize);
@ -58,6 +57,7 @@ auto PPU::IO::serialize(serializer& s) -> void {
s.integer(pseudoHires);
s.integer(extbg);
mosaic.serialize(s);
mode7.serialize(s);
window.serialize(s);
bg1.serialize(s);
@ -68,6 +68,12 @@ auto PPU::IO::serialize(serializer& s) -> void {
col.serialize(s);
}
auto PPU::IO::Mosaic::serialize(serializer& s) -> void {
s.integer(enable);
s.integer(size);
s.integer(counter);
}
auto PPU::IO::Mode7::serialize(serializer& s) -> void {
s.integer(hflip);
s.integer(vflip);
@ -114,8 +120,6 @@ auto PPU::IO::Background::serialize(serializer& s) -> void {
s.integer(aboveEnable);
s.integer(belowEnable);
s.integer(mosaicEnable);
s.integer(mosaicCounter);
s.integer(mosaicOffset);
s.integer(tiledataAddress);
s.integer(screenAddress);
s.integer(screenSize);

View File

@ -1,5 +1,4 @@
#include "mode7.cpp"
uint4 PPU::Background::Mosaic::size;
auto PPU::Background::hires() const -> bool {
return ppu.io.bgMode == 5 || ppu.io.bgMode == 6;
@ -11,26 +10,13 @@ auto PPU::Background::frame() -> void {
//H = 0
auto PPU::Background::scanline() -> void {
if(ppu.vcounter() == 1) {
mosaic.vcounter = mosaic.size + 1;
mosaic.voffset = 1;
latch.hoffset = io.hoffset;
latch.voffset = io.voffset;
} else if(--mosaic.vcounter == 0) {
mosaic.vcounter = mosaic.size + 1;
mosaic.voffset += mosaic.size + 1;
latch.hoffset = io.hoffset;
latch.voffset = io.voffset;
}
mosaic.hcounter = mosaic.size + 1;
mosaic.hcounter = ppu.mosaic.size;
mosaic.hoffset = 0;
if(io.mode == Mode::Mode7) return beginMode7();
if(mosaic.size == 0) {
latch.hoffset = io.hoffset;
latch.voffset = io.voffset;
}
nameTableIndex = 0;
characterIndex = 0;
@ -52,13 +38,17 @@ auto PPU::Background::fetchNameTable() -> void {
int x = (ppu.hcounter() & ~31) >> 2;
uint hpixel = x << hires();
uint vpixel = mosaic.enable ? (uint)mosaic.voffset : ppu.vcounter();
uint vpixel = ppu.vcounter();
uint hscroll = latch.hoffset;
uint vscroll = latch.voffset;
uint hscroll = mosaic.enable ? latch.hoffset : io.hoffset;
uint vscroll = mosaic.enable ? latch.voffset : io.voffset;
if(mosaic.enable) vpixel -= ppu.mosaic.voffset();
if(hires()) {
hscroll <<= 1;
if(ppu.io.interlace) vpixel = vpixel << 1 | (ppu.field() && !mosaic.enable);
if(ppu.io.interlace) {
vpixel = vpixel << 1 | ppu.field();
if(mosaic.enable) vpixel -= ppu.mosaic.voffset() + ppu.field();
}
}
bool repeated = false;
@ -214,10 +204,10 @@ auto PPU::Background::run(bool screen) -> void {
uint x = ppu.hcounter() - 56 >> 2;
if(x == 0) {
mosaic.hcounter = mosaic.size + 1;
mosaic.hcounter = ppu.mosaic.size;
mosaic.pixel = pixel;
} else if((!hires() || screen == Screen::Below) && --mosaic.hcounter == 0) {
mosaic.hcounter = mosaic.size + 1;
mosaic.hcounter = ppu.mosaic.size;
mosaic.pixel = pixel;
} else if(mosaic.enable) {
pixel = mosaic.pixel;
@ -246,6 +236,5 @@ auto PPU::Background::power() -> void {
output.below = {};
mosaic = {};
mosaic.size = random();
mosaic.enable = random();
}

View File

@ -61,15 +61,9 @@ struct Background {
} output;
struct Mosaic {
static uint4 size;
uint1 enable;
uint16 vcounter;
uint16 hcounter;
uint16 voffset;
uint16 hoffset;
Pixel pixel;
} mosaic;

View File

@ -262,11 +262,15 @@ auto PPU::writeIO(uint addr, uint8 data) -> void {
//MOSAIC
case 0x2106: {
if(!mosaic.enable() && (data >> 0 & 15)) {
//mosaic vcounter is reloaded when mosaic becomes enabled
mosaic.vcounter = (data >> 4 & 15) + 2;
}
bg1.mosaic.enable = data >> 0 & 1;
bg2.mosaic.enable = data >> 1 & 1;
bg3.mosaic.enable = data >> 2 & 1;
bg4.mosaic.enable = data >> 3 & 1;
Background::Mosaic::size = data >> 4 & 15;
mosaic.size = (data >> 4 & 15) + 1;
return;
}

View File

@ -17,6 +17,7 @@ auto PPU::main() -> void {
obj.frame();
}
mosaic.scanline();
bg1.scanline();
bg2.scanline();
bg3.scanline();

View File

@ -21,13 +21,12 @@ auto PPU::Background::runMode7() -> void {
int voffset = (int13)latch.voffset;
uint x = mosaic.hoffset;
uint y = !mosaic.enable ? ppu.vcounter() : ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
uint y = ppu.vcounter();
if(ppu.bg1.mosaic.enable) y -= ppu.mosaic.voffset(); //BG2 vertical mosaic uses BG1 mosaic enable
if(!mosaic.enable) {
mosaic.hoffset += 1;
} else if(--mosaic.hcounter == 0) {
mosaic.hcounter = mosaic.size + 1;
mosaic.hoffset += mosaic.size + 1;
if(--mosaic.hcounter == 0) {
mosaic.hcounter = ppu.mosaic.size;
mosaic.hoffset += ppu.mosaic.size;
}
if(ppu.io.hflipMode7) x = 255 - x;

26
bsnes/sfc/ppu/mosaic.cpp Normal file
View File

@ -0,0 +1,26 @@
auto PPU::Mosaic::enable() const -> bool {
if(ppu.bg1.mosaic.enable) return true;
if(ppu.bg2.mosaic.enable) return true;
if(ppu.bg3.mosaic.enable) return true;
if(ppu.bg4.mosaic.enable) return true;
return false;
}
auto PPU::Mosaic::voffset() const -> uint {
return size - vcounter;
}
//H = 0
auto PPU::Mosaic::scanline() -> void {
if(ppu.vcounter() == 1) {
vcounter = enable() ? size + 1 : 0;
}
if(vcounter && !--vcounter) {
vcounter = enable() ? size + 0 : 0;
}
}
auto PPU::Mosaic::power() -> void {
size = (random() & 15) + 1;
vcounter = 0;
}

13
bsnes/sfc/ppu/mosaic.hpp Normal file
View File

@ -0,0 +1,13 @@
struct Mosaic {
//mosaic.cpp
alwaysinline auto enable() const -> bool;
alwaysinline auto voffset() const -> uint;
auto scanline() -> void;
auto power() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint5 size;
uint5 vcounter;
};

View File

@ -5,6 +5,7 @@ namespace SuperFamicom {
PPU ppu;
#include "main.cpp"
#include "io.cpp"
#include "mosaic.cpp"
#include "background.cpp"
#include "object.cpp"
#include "window.cpp"
@ -173,6 +174,7 @@ auto PPU::power(bool reset) -> void {
//$213d OPVCT
io.vcounter = 0;
mosaic.power();
bg1.power();
bg2.power();
bg3.power();

View File

@ -153,11 +153,13 @@ private:
uint16 vcounter;
} io;
#include "mosaic.hpp"
#include "background.hpp"
#include "object.hpp"
#include "window.hpp"
#include "screen.hpp"
Mosaic mosaic;
Background bg1;
Background bg2;
Background bg3;

View File

@ -73,6 +73,7 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(io.hcounter);
s.integer(io.vcounter);
mosaic.serialize(s);
bg1.serialize(s);
bg2.serialize(s);
bg3.serialize(s);
@ -82,6 +83,11 @@ auto PPU::serialize(serializer& s) -> void {
screen.serialize(s);
}
auto PPU::Mosaic::serialize(serializer& s) -> void {
s.integer(size);
s.integer(vcounter);
}
auto PPU::Background::serialize(serializer& s) -> void {
s.integer(io.tiledataAddress);
s.integer(io.screenAddress);
@ -105,11 +111,8 @@ auto PPU::Background::serialize(serializer& s) -> void {
s.integer(output.below.palette);
s.integer(output.below.paletteGroup);
s.integer(mosaic.size);
s.integer(mosaic.enable);
s.integer(mosaic.vcounter);
s.integer(mosaic.hcounter);
s.integer(mosaic.voffset);
s.integer(mosaic.hoffset);
s.integer(mosaic.pixel.priority);