mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r31 release.
byuu says: Changelog: - sfc/ppu-fast: added a barebones background renderer; very incomplete Right now, the 2bpp Mega Man X2 splash screen is rendering correctly, but everything else looks really garbled. I'm thinking my tile cache conversions from 4bpp to bitmap pixels is wrong, but I'm not seeing any obvious issues. If anyone wants to take a look at it, I'd appreciate it. The renderer is mostly modeled after ppu-performance's.
This commit is contained in:
parent
18852bcbe2
commit
51e3fcd3fa
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.30";
|
||||
static const string Version = "106.31";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -39,7 +39,6 @@ auto CPU::power(bool reset) -> void {
|
|||
r.pc.byte(1) = bus.read(0xfffd);
|
||||
|
||||
io = {};
|
||||
io.rdyLine = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ struct CPU : Processor::MOS6502, Thread {
|
|||
bool irqLine = 0;
|
||||
bool apuLine = 0;
|
||||
|
||||
bool rdyLine = 0;
|
||||
bool rdyLine = 1;
|
||||
bool rdyAddrValid = 0;
|
||||
uint16 rdyAddrValue;
|
||||
|
||||
|
|
|
@ -59,7 +59,6 @@ auto PPU::power(bool reset) -> void {
|
|||
|
||||
io = {};
|
||||
latch = {};
|
||||
io.vramIncrement = 1;
|
||||
|
||||
if(!reset) {
|
||||
for(auto& data : ciram ) data = 0;
|
||||
|
|
|
@ -64,7 +64,7 @@ struct PPU : Thread {
|
|||
bool nmiFlag = 0;
|
||||
|
||||
//$2000
|
||||
uint vramIncrement = 0;
|
||||
uint vramIncrement = 1;
|
||||
uint spriteAddress = 0;
|
||||
uint bgAddress = 0;
|
||||
uint spriteHeight = 0;
|
||||
|
|
|
@ -124,8 +124,6 @@ auto CPU::power() -> void {
|
|||
for(auto& n : hram) n = 0x00;
|
||||
|
||||
status = {};
|
||||
status.dmaCompleted = true;
|
||||
status.wramBank = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,13 +84,13 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||
//$ff55 HDMA5
|
||||
bool dmaMode = 0;
|
||||
uint16 dmaLength;
|
||||
bool dmaCompleted = 0;
|
||||
bool dmaCompleted = 1;
|
||||
|
||||
//$ff6c ???
|
||||
uint8 ff6c;
|
||||
|
||||
//$ff70 SVBK
|
||||
uint3 wramBank;
|
||||
uint3 wramBank = 1;
|
||||
|
||||
//$ff72-$ff75 ???
|
||||
uint8 ff72;
|
||||
|
|
|
@ -1,2 +1,103 @@
|
|||
auto PPU::Line::renderBackground(PPU::IO::Background&) -> void {
|
||||
auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void {
|
||||
if(io.displayDisable) return;
|
||||
if(self.tileMode == TileMode::Inactive) return;
|
||||
if(self.tileMode == TileMode::Mode7) return; //todo
|
||||
if(!self.aboveEnable && !self.belowEnable) return;
|
||||
|
||||
bool hires = io.bgMode == 5 || io.bgMode == 6;
|
||||
bool offsetPerTile = io.bgMode == 2 || io.bgMode == 4 || io.bgMode == 6;
|
||||
bool directColor = io.col.directColor && source == Source::BG1 && (io.bgMode == 3 || io.bgMode == 4);
|
||||
uint width = !hires ? 256 : 512;
|
||||
|
||||
uint tileHeight = self.tileSize ? 4 : 3;
|
||||
uint tileWidth = hires ? 4 : tileHeight;
|
||||
uint tileMask = 0x0fff >> self.tileMode;
|
||||
uint tiledataIndex = self.tiledataAddress >> 4 + self.tileMode;
|
||||
|
||||
uint maskX = width << (tileHeight == 4);
|
||||
uint maskY = maskX;
|
||||
if(self.screenSize.bit(0)) maskX <<= 1;
|
||||
if(self.screenSize.bit(1)) maskY <<= 1;
|
||||
maskX--;
|
||||
maskY--;
|
||||
|
||||
uint screenX = self.screenSize.bit(0) ? 32 << 5 : 0;
|
||||
uint screenY = self.screenSize.bit(1) ? 32 << 5 : 0;
|
||||
if(self.screenSize == 3) screenY <<= 1;
|
||||
|
||||
uint paletteBase = io.bgMode == 0 ? source << 5 : 0;
|
||||
uint paletteShift = 2 << self.tileMode;
|
||||
|
||||
uint hscroll = self.hoffset;
|
||||
uint vscroll = self.voffset;
|
||||
|
||||
uint y = this->y; //todo: vmosaic
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(io.interlace) y = y << 1 | ppu.PPUcounter::field();
|
||||
}
|
||||
|
||||
uint mosaicCounter = 1;
|
||||
uint mosaicPalette = 0;
|
||||
uint mosaicPriority = 0;
|
||||
uint mosaicColor = 0;
|
||||
|
||||
auto getTile = [&](uint hoffset, uint voffset) -> uint {
|
||||
uint tileX = (hoffset & maskX) >> tileWidth;
|
||||
uint tileY = (voffset & maskY) >> tileHeight;
|
||||
uint tilePosition = (tileY & 0x1f) << 5 | (tileX & 0x1f);
|
||||
if(tileX & 0x20) tilePosition += screenX;
|
||||
if(tileY & 0x20) tilePosition += screenY;
|
||||
uint15 tiledataAddress = self.screenAddress + tilePosition;
|
||||
return ppu.vram[tiledataAddress];
|
||||
};
|
||||
|
||||
int x = 0 - (hscroll & 7);
|
||||
while(x < width) {
|
||||
uint hoffset = x + hscroll;
|
||||
uint voffset = y + vscroll;
|
||||
if(offsetPerTile); //todo
|
||||
hoffset &= maskX;
|
||||
voffset &= maskY;
|
||||
|
||||
uint tileNumber = getTile(hoffset, voffset);
|
||||
uint mirrorY = tileNumber & 0x8000 ? 7 : 0;
|
||||
uint mirrorX = tileNumber & 0x4000 ? 7 : 0;
|
||||
uint tilePriority = tileNumber & 0x2000 ? self.priority[1] : self.priority[0];
|
||||
uint paletteNumber = tileNumber >> 10 & 7;
|
||||
uint paletteIndex = (paletteBase + (paletteNumber << paletteShift)) & 0xff;
|
||||
|
||||
if(tileWidth == 4 && (hoffset & 8) - 1 != mirrorX) tileNumber += 1;
|
||||
if(tileHeight == 4 && (voffset & 8) - 1 != mirrorY) tileNumber += 16;
|
||||
tileNumber = ((tileNumber & 0x03ff) + tiledataIndex) & tileMask;
|
||||
|
||||
auto tiledata = ppu.tilecache[self.tileMode] + (tileNumber << 6);
|
||||
tiledata += ((voffset & 7) ^ mirrorY) << 3;
|
||||
|
||||
for(uint tileX = 0; tileX < 8; tileX++, x++) {
|
||||
if(x & width) continue; //x < 0 || x >= width
|
||||
if(--mosaicCounter == 0) {
|
||||
mosaicCounter = 1 + io.mosaicSize;
|
||||
mosaicPalette = tiledata[tileX ^ mirrorX];
|
||||
mosaicPriority = tilePriority;
|
||||
if(directColor) {
|
||||
//todo
|
||||
} else {
|
||||
mosaicColor = cgram[paletteIndex + mosaicPalette];
|
||||
}
|
||||
}
|
||||
if(!mosaicPalette) continue;
|
||||
|
||||
if(!hires) {
|
||||
if(self.aboveEnable) { //todo: window
|
||||
plotAbove(x, source, mosaicPriority, mosaicColor);
|
||||
}
|
||||
if(self.belowEnable) { //todo: window
|
||||
plotBelow(x, source, mosaicPriority, mosaicColor);
|
||||
}
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,21 @@ auto PPU::writeVRAM(uint1 byte, uint8 data) -> void {
|
|||
if(!io.displayDisable && vcounter() < vdisp()) return;
|
||||
auto address = vramAddress();
|
||||
vram[address].byte(byte) = data;
|
||||
|
||||
auto word = vram[address];
|
||||
auto line2bpp = tilecache[0] + (address.bits(3,14) << 6) + (address.bits(0,2) << 3);
|
||||
auto line4bpp = tilecache[1] + (address.bits(4,14) << 6) + (address.bits(0,2) << 3);
|
||||
auto line8bpp = tilecache[2] + (address.bits(5,14) << 6) + (address.bits(0,2) << 3);
|
||||
uint plane4bpp = address.bit(3) << 1;
|
||||
uint plane8bpp = address.bit(3) << 1 | address.bit(4) << 2;
|
||||
for(uint x : range(8)) {
|
||||
line2bpp[7 - x].bit( 0) = word.bit(x + 0);
|
||||
line2bpp[7 - x].bit( 1) = word.bit(x + 8);
|
||||
line4bpp[7 - x].bit(plane4bpp + 0) = word.bit(x + 0);
|
||||
line4bpp[7 - x].bit(plane4bpp + 1) = word.bit(x + 8);
|
||||
line8bpp[7 - x].bit(plane8bpp + 0) = word.bit(x + 0);
|
||||
line8bpp[7 - x].bit(plane8bpp + 1) = word.bit(x + 8);
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::readOAM(uint10 address) -> uint8 {
|
||||
|
|
|
@ -1,21 +1,52 @@
|
|||
auto PPU::Line::render() -> void {
|
||||
if(io.displayDisable) {
|
||||
for(uint x : range(512)) {
|
||||
outputLo[x] = 0;
|
||||
outputHi[x] = 0;
|
||||
}
|
||||
} else {
|
||||
auto aboveColor = cgram[0];
|
||||
auto belowColor = 0;
|
||||
for(uint x : range(256)) {
|
||||
above[x].source = Source::COL;
|
||||
above[x].priority = 0;
|
||||
above[x].color = aboveColor;
|
||||
below[x].source = Source::COL;
|
||||
below[x].priority = 0;
|
||||
below[x].color = belowColor;
|
||||
}
|
||||
}
|
||||
|
||||
renderWindow(io.bg1.window);
|
||||
renderWindow(io.bg2.window);
|
||||
renderWindow(io.bg3.window);
|
||||
renderWindow(io.bg4.window);
|
||||
renderWindow(io.obj.window);
|
||||
renderWindow(io.col.window);
|
||||
renderBackground(io.bg1);
|
||||
renderBackground(io.bg2);
|
||||
renderBackground(io.bg3);
|
||||
renderBackground(io.bg4);
|
||||
renderBackground(io.bg1, Source::BG1);
|
||||
renderBackground(io.bg2, Source::BG2);
|
||||
renderBackground(io.bg3, Source::BG3);
|
||||
renderBackground(io.bg4, Source::BG4);
|
||||
renderObject(io.obj);
|
||||
|
||||
if(io.displayDisable) {
|
||||
for(uint x : range(512)) {
|
||||
outputLo[x] = 0;
|
||||
outputHi[x] = 0;
|
||||
}
|
||||
return;
|
||||
for(uint x : range(512)) {
|
||||
outputLo[x] = io.displayBrightness << 15 | above[x >> 1].color;
|
||||
outputHi[x] = io.displayBrightness << 15 | above[x >> 1].color;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void {
|
||||
if(priority > above[x].priority) {
|
||||
above[x].source = source;
|
||||
above[x].priority = priority;
|
||||
above[x].color = color;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void {
|
||||
if(priority > below[x].priority) {
|
||||
below[x].source = source;
|
||||
below[x].priority = priority;
|
||||
below[x].color = color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ PPU::PPU() {
|
|||
output = new uint32[512 * 512];
|
||||
output += 16 * 512; //overscan offset
|
||||
|
||||
tilecache[0] = new uint8[4096 * 8 * 8];
|
||||
tilecache[1] = new uint8[2048 * 8 * 8];
|
||||
tilecache[2] = new uint8[1024 * 8 * 8];
|
||||
|
||||
for(uint y : range(240)) {
|
||||
lines[y].y = y;
|
||||
lines[y].outputLo = output + (y * 2 + 0) * 512;
|
||||
|
@ -28,6 +32,10 @@ PPU::PPU() {
|
|||
PPU::~PPU() {
|
||||
output -= 16 * 512; //overscan offset
|
||||
delete[] output;
|
||||
|
||||
delete[] tilecache[0];
|
||||
delete[] tilecache[1];
|
||||
delete[] tilecache[2];
|
||||
}
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
|
@ -59,9 +67,10 @@ auto PPU::scanline() -> void {
|
|||
frame();
|
||||
}
|
||||
|
||||
if(PPUcounter::vcounter() == 241) {
|
||||
if(PPUcounter::vcounter() == 240) {
|
||||
const uint limit = vdisp();
|
||||
#pragma omp parallel for
|
||||
for(uint y = 1; y < vdisp(); y++) {
|
||||
for(uint y = 1; y < limit; y++) {
|
||||
lines[y].render();
|
||||
}
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
|
|
|
@ -34,6 +34,7 @@ struct PPU : Thread, PPUcounter {
|
|||
|
||||
public:
|
||||
uint32* output = nullptr;
|
||||
uint8* tilecache[3] = {}; //bitplane -> bitmap tiledata
|
||||
uint16 vram[32 * 1024];
|
||||
uint16 cgram[256];
|
||||
|
||||
|
@ -70,10 +71,9 @@ public:
|
|||
auto writeIO(uint24 address, uint8 data) -> void;
|
||||
auto updateVideoMode() -> void;
|
||||
|
||||
struct Source { enum : uint { BG1, BG2, BG3, BG4, OBJ1, OBJ2, COL }; };
|
||||
struct TileMode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; };
|
||||
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
||||
struct ScreenMode { enum : uint { Above, Below }; };
|
||||
struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
|
||||
struct IO {
|
||||
uint1 displayDisable;
|
||||
|
@ -197,17 +197,14 @@ public:
|
|||
uint1 size;
|
||||
} object[128];
|
||||
|
||||
//bitplane -> bitmap tile caches
|
||||
uint8 vram2bpp[4096 * 8 * 8];
|
||||
uint8 vram4bpp[2048 * 8 * 8];
|
||||
uint8 vram8bpp[1024 * 8 * 8];
|
||||
|
||||
struct Line {
|
||||
//line.cpp
|
||||
auto render() -> void;
|
||||
alwaysinline auto plotAbove(uint x, uint source, uint priority, uint color) -> void;
|
||||
alwaysinline auto plotBelow(uint x, uint source, uint priority, uint color) -> void;
|
||||
|
||||
//background.cpp
|
||||
auto renderBackground(PPU::IO::Background&) -> void;
|
||||
auto renderBackground(PPU::IO::Background&, uint source) -> void;
|
||||
|
||||
//object.cpp
|
||||
auto renderObject(PPU::IO::Object&) -> void;
|
||||
|
@ -222,6 +219,12 @@ public:
|
|||
|
||||
uint15 cgram[256];
|
||||
IO io;
|
||||
|
||||
struct Screen {
|
||||
uint source;
|
||||
uint priority;
|
||||
uint color;
|
||||
} above[256], below[256];
|
||||
} lines[240];
|
||||
};
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ auto PPU::scanline() -> void {
|
|||
window.scanline();
|
||||
screen.scanline();
|
||||
|
||||
if(vcounter() == 241) {
|
||||
if(vcounter() == 240) {
|
||||
scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue