mirror of https://github.com/bsnes-emu/bsnes.git
Update to v104r11 release.
byuu says: Changelog: - sfc/ppu/background: minor code cleanup and simplification - sfc/ppu/background: $2106 MOSAIC register was implemented incorrectly - sfc/ppu/background: fixed mosaic effects in hires mode (temporary fix) - sfc/ppu/background: fixed mosaic effects in interlace mode [Cydrak] Errata: - sfc/ppu/background/background.cpp:48: should be `if(!mosaic.enable) {` Turns out there is only one mosaic size, and the other four bits are per-BG mosaic enable. This matters a lot for hires/interlace, as mosaicSize=0 (2x2) is not the same thing as mosaicEnable=false (1x1). Although I've now implemented this, I really don't like how my mosaic implementation works right now. I tried to redesign the entire system, and completely failed. So I started over from v104r10 again and instead went with a more evolutionary improvement for now. I'll keep trying. Also, the combination of mosaic + offset-per-tile is still sketchy, as is mode 6 offset-per-tile. I'll get to those in the future as well.
This commit is contained in:
parent
28060d3a69
commit
3dce3aa3c8
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "104.10";
|
||||
static const string Version = "104.11";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#include "mode7.cpp"
|
||||
uint4 PPU::Background::Mosaic::size;
|
||||
|
||||
auto PPU::Background::hires() const -> bool {
|
||||
return ppu.io.bgMode == 5 || ppu.io.bgMode == 6;
|
||||
}
|
||||
|
||||
auto PPU::Background::voffset() const -> uint16 {
|
||||
if(io.mosaic) return latch.voffset;
|
||||
return io.voffset;
|
||||
return mosaic.enable ? latch.voffset : io.voffset;
|
||||
}
|
||||
|
||||
auto PPU::Background::hoffset() const -> uint16 {
|
||||
if(io.mosaic) return latch.hoffset;
|
||||
return io.hoffset;
|
||||
return mosaic.enable ? latch.hoffset : io.hoffset;
|
||||
}
|
||||
|
||||
//V = 0, H = 0
|
||||
|
@ -20,76 +23,73 @@ auto PPU::Background::scanline() -> void {
|
|||
|
||||
//H = 28
|
||||
auto PPU::Background::begin() -> void {
|
||||
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||
x = -7;
|
||||
y = ppu.vcounter();
|
||||
|
||||
tileCounter = 7 - (io.hoffset & 7) << hires();
|
||||
for(auto& word : data) word = 0;
|
||||
|
||||
if(y == 1) {
|
||||
mosaic.vcounter = io.mosaic + 1;
|
||||
mosaic.vcounter = mosaic.size + 1;
|
||||
mosaic.voffset = 1;
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
} else if(--mosaic.vcounter == 0) {
|
||||
mosaic.vcounter = io.mosaic + 1;
|
||||
mosaic.voffset += io.mosaic + 1;
|
||||
mosaic.vcounter = mosaic.size + 1;
|
||||
mosaic.voffset += mosaic.size + 1;
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
}
|
||||
|
||||
tileCounter = (7 - (latch.hoffset & 7)) << hires;
|
||||
for(auto& d : data) d = 0;
|
||||
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.hcounter = mosaic.size + 1;
|
||||
mosaic.hoffset = 0;
|
||||
|
||||
if(io.mode == Mode::Mode7) return beginMode7();
|
||||
if(io.mosaic == 0) {
|
||||
if(mosaic.size == 0) {
|
||||
latch.hoffset = io.hoffset;
|
||||
latch.voffset = io.voffset;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Background::getTile() -> void {
|
||||
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||
|
||||
uint colorDepth = (io.mode == Mode::BPP2 ? 0 : io.mode == Mode::BPP4 ? 1 : 2);
|
||||
uint paletteOffset = (ppu.io.bgMode == 0 ? id << 5 : 0);
|
||||
uint colorDepth = io.mode == Mode::BPP2 ? 0 : io.mode == Mode::BPP4 ? 1 : 2;
|
||||
uint paletteOffset = ppu.io.bgMode == 0 ? id << 5 : 0;
|
||||
uint paletteSize = 2 << colorDepth;
|
||||
uint tileMask = ppu.vram.mask >> (3 + colorDepth);
|
||||
uint tiledataIndex = io.tiledataAddress >> (3 + colorDepth);
|
||||
uint tileMask = ppu.vram.mask >> 3 + colorDepth;
|
||||
uint tiledataIndex = io.tiledataAddress >> 3 + colorDepth;
|
||||
|
||||
uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
uint tileWidth = (!hires ? tileHeight : 4);
|
||||
uint tileHeight = io.tileSize == TileSize::Size8x8 ? 3 : 4;
|
||||
uint tileWidth = !hires() ? tileHeight : 4;
|
||||
|
||||
uint width = 256 << hires;
|
||||
uint width = 256 << hires();
|
||||
|
||||
uint hmask = (tileHeight == 3 ? width : width << 1);
|
||||
uint hmask = tileHeight == 3 ? width : width << 1;
|
||||
uint vmask = hmask;
|
||||
if(io.screenSize & 1) hmask <<= 1;
|
||||
if(io.screenSize & 2) vmask <<= 1;
|
||||
hmask--;
|
||||
vmask--;
|
||||
|
||||
uint px = x << hires;
|
||||
uint py = (io.mosaic == 0 ? y : mosaic.voffset);
|
||||
uint px = x << hires();
|
||||
uint py = mosaic.enable ? (uint)mosaic.voffset : y;
|
||||
|
||||
uint hscroll = hoffset();
|
||||
uint vscroll = voffset();
|
||||
if(hires) {
|
||||
if(hires()) {
|
||||
hscroll <<= 1;
|
||||
if(ppu.io.interlace) py = (py << 1) + ppu.field();
|
||||
if(ppu.io.interlace) py = py << 1 | (ppu.field() & !mosaic.enable); //todo: temporary vmosaic hack
|
||||
}
|
||||
|
||||
uint hoffset = hscroll + px;
|
||||
uint voffset = vscroll + py;
|
||||
|
||||
if(ppu.io.bgMode == 2 || ppu.io.bgMode == 4 || ppu.io.bgMode == 6) {
|
||||
uint16 offsetX = (x + (hscroll & 7));
|
||||
uint16 offsetX = x + (hscroll & 7);
|
||||
|
||||
if(offsetX >= 8) {
|
||||
uint hval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 0);
|
||||
uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8);
|
||||
uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000);
|
||||
uint validMask = id == ID::BG1 ? 0x2000 : 0x4000;
|
||||
|
||||
if(ppu.io.bgMode == 4) {
|
||||
if(hval & validMask) {
|
||||
|
@ -109,31 +109,31 @@ auto PPU::Background::getTile() -> void {
|
|||
hoffset &= hmask;
|
||||
voffset &= vmask;
|
||||
|
||||
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||
uint screenX = io.screenSize & 1 ? 32 << 5 : 0;
|
||||
uint screenY = io.screenSize & 2 ? 32 << 5 : 0;
|
||||
if(io.screenSize == 3) screenY <<= 1;
|
||||
|
||||
uint tx = hoffset >> tileWidth;
|
||||
uint ty = voffset >> tileHeight;
|
||||
|
||||
uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
|
||||
uint16 offset = (ty & 0x1f) << 5 | (tx & 0x1f);
|
||||
if(tx & 0x20) offset += screenX;
|
||||
if(ty & 0x20) offset += screenY;
|
||||
|
||||
uint16 address = io.screenAddress + offset;
|
||||
tile = ppu.vram[address];
|
||||
bool mirrorY = tile & 0x8000;
|
||||
bool mirrorX = tile & 0x4000;
|
||||
priority = io.priority[bool(tile & 0x2000)];
|
||||
paletteNumber = (tile >> 10) & 7;
|
||||
bool mirrorY = tile.bit(15);
|
||||
bool mirrorX = tile.bit(14);
|
||||
priority = io.priority[tile.bit(13)];
|
||||
paletteNumber = tile.bits(10,12);
|
||||
paletteIndex = paletteOffset + (paletteNumber << paletteSize);
|
||||
|
||||
if(tileWidth == 4 && (bool)(hoffset & 8) != mirrorX) tile += 1;
|
||||
if(tileHeight == 4 && (bool)(voffset & 8) != mirrorY) tile += 16;
|
||||
uint16 character = ((tile & 0x03ff) + tiledataIndex) & tileMask;
|
||||
if(tileWidth == 4 && (bool)(hoffset & 8) != mirrorX) tile += 1;
|
||||
if(tileHeight == 4 && (bool)(voffset & 8) != mirrorY) tile += 16;
|
||||
uint16 character = tile.bits(0,9) + tiledataIndex & tileMask;
|
||||
|
||||
if(mirrorY) voffset ^= 7;
|
||||
offset = (character << (3 + colorDepth)) + (voffset & 7);
|
||||
offset = (character << 3 + colorDepth) + (voffset & 7);
|
||||
|
||||
switch(io.mode) {
|
||||
case Mode::BPP8:
|
||||
|
@ -146,20 +146,19 @@ auto PPU::Background::getTile() -> void {
|
|||
}
|
||||
|
||||
if(mirrorX) for(auto n : range(2)) {
|
||||
data[n] = ((data[n] >> 4) & 0x0f0f0f0f) | ((data[n] << 4) & 0xf0f0f0f0);
|
||||
data[n] = ((data[n] >> 2) & 0x33333333) | ((data[n] << 2) & 0xcccccccc);
|
||||
data[n] = ((data[n] >> 1) & 0x55555555) | ((data[n] << 1) & 0xaaaaaaaa);
|
||||
data[n] = (data[n] >> 4 & 0x0f0f0f0f) | (data[n] << 4 & 0xf0f0f0f0);
|
||||
data[n] = (data[n] >> 2 & 0x33333333) | (data[n] << 2 & 0xcccccccc);
|
||||
data[n] = (data[n] >> 1 & 0x55555555) | (data[n] << 1 & 0xaaaaaaaa);
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Background::run(bool screen) -> void {
|
||||
if(ppu.vcounter() == 0) return;
|
||||
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||
|
||||
if(screen == Screen::Below) {
|
||||
output.above.priority = 0;
|
||||
output.below.priority = 0;
|
||||
if(!hires) return;
|
||||
if(!hires()) return;
|
||||
}
|
||||
|
||||
if(tileCounter-- == 0) {
|
||||
|
@ -169,19 +168,26 @@ auto PPU::Background::run(bool screen) -> void {
|
|||
|
||||
if(io.mode == Mode::Mode7) return runMode7();
|
||||
|
||||
uint8 palette = getTileColor();
|
||||
if(x == 0) mosaic.hcounter = 1;
|
||||
if(x >= 0 && --mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.priority = priority;
|
||||
mosaic.palette = palette ? paletteIndex + palette : 0;
|
||||
mosaic.tile = tile;
|
||||
uint8 color = getTileColor();
|
||||
Pixel pixel;
|
||||
pixel.priority = priority;
|
||||
pixel.palette = color ? paletteIndex + color : 0;
|
||||
pixel.tile = tile;
|
||||
|
||||
if(x == 0) {
|
||||
mosaic.hcounter = 1;
|
||||
mosaic.pixel = pixel;
|
||||
} else if(x >= 1 && screen == Screen::Above && --mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = mosaic.size + 1;
|
||||
mosaic.pixel = pixel;
|
||||
} else if(mosaic.enable) {
|
||||
pixel = mosaic.pixel;
|
||||
}
|
||||
if(screen == Screen::Above) x++;
|
||||
if(mosaic.palette == 0) return;
|
||||
if(pixel.palette == 0) return;
|
||||
|
||||
if(!hires || screen == Screen::Above) if(io.aboveEnable) output.above = mosaic;
|
||||
if(!hires || screen == Screen::Below) if(io.belowEnable) output.below = mosaic;
|
||||
if(!hires() || screen == Screen::Above) if(io.aboveEnable) output.above = pixel;
|
||||
if(!hires() || screen == Screen::Below) if(io.belowEnable) output.below = pixel;
|
||||
}
|
||||
|
||||
auto PPU::Background::getTileColor() -> uint {
|
||||
|
@ -207,34 +213,24 @@ auto PPU::Background::getTileColor() -> uint {
|
|||
}
|
||||
|
||||
auto PPU::Background::power() -> void {
|
||||
io = {};
|
||||
io.tiledataAddress = (random() & 0x0f) << 12;
|
||||
io.screenAddress = (random() & 0xfc) << 8;
|
||||
io.screenSize = random();
|
||||
io.mosaic = random();
|
||||
io.tileSize = random();
|
||||
io.mode = 0;
|
||||
for(auto& p : io.priority) p = 0;
|
||||
io.aboveEnable = random();
|
||||
io.belowEnable = random();
|
||||
io.hoffset = random();
|
||||
io.voffset = random();
|
||||
|
||||
latch.hoffset = 0;
|
||||
latch.voffset = 0;
|
||||
latch = {};
|
||||
|
||||
output.above.palette = 0;
|
||||
output.above.priority = 0;
|
||||
output.below.palette = 0;
|
||||
output.below.priority = 0;
|
||||
output.above = {};
|
||||
output.below = {};
|
||||
|
||||
mosaic.priority = 0;
|
||||
mosaic.palette = 0;
|
||||
mosaic.tile = 0;
|
||||
|
||||
mosaic.vcounter = 0;
|
||||
mosaic.voffset = 0;
|
||||
mosaic.hcounter = 0;
|
||||
mosaic.hoffset = 0;
|
||||
mosaic = {};
|
||||
mosaic.size = random();
|
||||
mosaic.enable = random();
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
@ -244,29 +240,28 @@ auto PPU::Background::power() -> void {
|
|||
priority = 0;
|
||||
paletteNumber = 0;
|
||||
paletteIndex = 0;
|
||||
for(auto& d : data) d = 0;
|
||||
for(auto& word : data) word = 0;
|
||||
}
|
||||
|
||||
auto PPU::Background::getTile(uint x, uint y) -> uint {
|
||||
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||
uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
uint tileWidth = (!hires ? tileHeight : 4);
|
||||
uint width = (!hires ? 256 : 512);
|
||||
uint maskX = (tileHeight == 3 ? width : width << 1);
|
||||
uint tileHeight = io.tileSize == TileSize::Size8x8 ? 3 : 4;
|
||||
uint tileWidth = !hires() ? tileHeight : 4;
|
||||
uint width = !hires() ? 256 : 512;
|
||||
uint maskX = tileHeight == 3 ? width : width << 1;
|
||||
uint maskY = maskX;
|
||||
if(io.screenSize & 1) maskX <<= 1;
|
||||
if(io.screenSize & 2) maskY <<= 1;
|
||||
maskX--;
|
||||
maskY--;
|
||||
|
||||
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||
uint screenX = io.screenSize & 1 ? 32 << 5 : 0;
|
||||
uint screenY = io.screenSize & 2 ? 32 << 5 : 0;
|
||||
if(io.screenSize == 3) screenY <<= 1;
|
||||
|
||||
x = (x & maskX) >> tileWidth;
|
||||
y = (y & maskY) >> tileHeight;
|
||||
|
||||
uint16 offset = ((y & 0x1f) << 5) + (x & 0x1f);
|
||||
uint16 offset = (y & 0x1f) << 5 | (x & 0x1f);
|
||||
if(x & 0x20) offset += screenX;
|
||||
if(y & 0x20) offset += screenY;
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
struct Background {
|
||||
Background(uint id) : id(id) {}
|
||||
|
||||
alwaysinline auto voffset() const -> uint16;
|
||||
alwaysinline auto hires() const -> bool;
|
||||
alwaysinline auto hoffset() const -> uint16;
|
||||
alwaysinline auto voffset() const -> uint16;
|
||||
|
||||
auto frame() -> void;
|
||||
auto scanline() -> void;
|
||||
|
@ -31,14 +32,13 @@ struct Background {
|
|||
uint16 tiledataAddress;
|
||||
uint16 screenAddress;
|
||||
uint2 screenSize;
|
||||
uint4 mosaic;
|
||||
bool tileSize;
|
||||
uint1 tileSize;
|
||||
|
||||
uint mode;
|
||||
uint priority[2];
|
||||
uint8 mode;
|
||||
uint8 priority[2];
|
||||
|
||||
bool aboveEnable;
|
||||
bool belowEnable;
|
||||
uint1 aboveEnable;
|
||||
uint1 belowEnable;
|
||||
|
||||
uint16 hoffset;
|
||||
uint16 voffset;
|
||||
|
@ -49,32 +49,39 @@ struct Background {
|
|||
uint16 voffset;
|
||||
} latch;
|
||||
|
||||
struct Pixel {
|
||||
uint8 priority; //0 = none (transparent)
|
||||
uint8 palette;
|
||||
uint16 tile;
|
||||
} above, below;
|
||||
|
||||
struct Output {
|
||||
struct Pixel {
|
||||
uint priority; //0 = none (transparent)
|
||||
uint8 palette;
|
||||
uint16 tile;
|
||||
} above, below;
|
||||
Pixel above;
|
||||
Pixel below;
|
||||
} output;
|
||||
|
||||
struct Mosaic : Output::Pixel {
|
||||
uint vcounter;
|
||||
uint voffset;
|
||||
uint hcounter;
|
||||
uint hoffset;
|
||||
struct Mosaic {
|
||||
static uint4 size;
|
||||
uint1 enable;
|
||||
|
||||
uint16 vcounter;
|
||||
uint16 hcounter;
|
||||
|
||||
uint16 voffset;
|
||||
uint16 hoffset;
|
||||
|
||||
Pixel pixel;
|
||||
} mosaic;
|
||||
|
||||
struct {
|
||||
int x;
|
||||
int y;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
uint tileCounter;
|
||||
uint tile;
|
||||
uint priority;
|
||||
uint paletteNumber;
|
||||
uint paletteIndex;
|
||||
uint32 data[2];
|
||||
};
|
||||
uint3 tileCounter;
|
||||
uint16 tile;
|
||||
uint8 priority;
|
||||
uint3 paletteNumber;
|
||||
uint8 paletteIndex;
|
||||
uint32 data[2];
|
||||
|
||||
friend class PPU;
|
||||
};
|
||||
|
|
|
@ -25,8 +25,8 @@ auto PPU::Background::runMode7() -> void {
|
|||
uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
|
||||
|
||||
if(--mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = io.mosaic + 1;
|
||||
mosaic.hoffset += io.mosaic + 1;
|
||||
mosaic.hcounter = mosaic.size + 1;
|
||||
mosaic.hoffset += mosaic.size + 1;
|
||||
}
|
||||
|
||||
if(ppu.io.hflipMode7) x = 255 - x;
|
||||
|
|
|
@ -238,11 +238,11 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//MOSAIC
|
||||
case 0x2106: {
|
||||
uint mosaicSize = data.bits(4,7);
|
||||
bg1.io.mosaic = data.bit(0) ? mosaicSize : 0;
|
||||
bg2.io.mosaic = data.bit(1) ? mosaicSize : 0;
|
||||
bg3.io.mosaic = data.bit(2) ? mosaicSize : 0;
|
||||
bg4.io.mosaic = data.bit(3) ? mosaicSize : 0;
|
||||
bg1.mosaic.enable = data.bit(0);
|
||||
bg2.mosaic.enable = data.bit(1);
|
||||
bg3.mosaic.enable = data.bit(2);
|
||||
bg4.mosaic.enable = data.bit(3);
|
||||
Background::Mosaic::size = data.bits(4,7);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,15 +93,11 @@ auto PPU::Background::serialize(serializer& s) -> void {
|
|||
s.integer(io.tiledataAddress);
|
||||
s.integer(io.screenAddress);
|
||||
s.integer(io.screenSize);
|
||||
s.integer(io.mosaic);
|
||||
s.integer(io.tileSize);
|
||||
|
||||
s.integer(io.mode);
|
||||
s.array(io.priority);
|
||||
|
||||
s.integer(io.aboveEnable);
|
||||
s.integer(io.belowEnable);
|
||||
|
||||
s.integer(io.hoffset);
|
||||
s.integer(io.voffset);
|
||||
|
||||
|
@ -111,23 +107,22 @@ auto PPU::Background::serialize(serializer& s) -> void {
|
|||
s.integer(output.above.priority);
|
||||
s.integer(output.above.palette);
|
||||
s.integer(output.above.tile);
|
||||
|
||||
s.integer(output.below.priority);
|
||||
s.integer(output.below.palette);
|
||||
s.integer(output.below.tile);
|
||||
|
||||
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);
|
||||
s.integer(mosaic.pixel.palette);
|
||||
s.integer(mosaic.pixel.tile);
|
||||
|
||||
s.integer(x);
|
||||
s.integer(y);
|
||||
|
||||
s.integer(mosaic.priority);
|
||||
s.integer(mosaic.palette);
|
||||
s.integer(mosaic.tile);
|
||||
|
||||
s.integer(mosaic.vcounter);
|
||||
s.integer(mosaic.voffset);
|
||||
s.integer(mosaic.hcounter);
|
||||
s.integer(mosaic.hoffset);
|
||||
|
||||
s.integer(tileCounter);
|
||||
s.integer(tile);
|
||||
s.integer(priority);
|
||||
|
|
Loading…
Reference in New Issue