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:
Tim Allen 2018-05-28 11:51:38 +10:00
parent 18852bcbe2
commit 51e3fcd3fa
13 changed files with 186 additions and 31 deletions

View File

@ -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/";

View File

@ -39,7 +39,6 @@ auto CPU::power(bool reset) -> void {
r.pc.byte(1) = bus.read(0xfffd);
io = {};
io.rdyLine = 1;
}
}

View File

@ -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;

View File

@ -59,7 +59,6 @@ auto PPU::power(bool reset) -> void {
io = {};
latch = {};
io.vramIncrement = 1;
if(!reset) {
for(auto& data : ciram ) data = 0;

View File

@ -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;

View File

@ -124,8 +124,6 @@ auto CPU::power() -> void {
for(auto& n : hram) n = 0x00;
status = {};
status.dmaCompleted = true;
status.wramBank = 1;
}
}

View File

@ -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;

View File

@ -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
}
}
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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];
};

View File

@ -210,7 +210,7 @@ auto PPU::scanline() -> void {
window.scanline();
screen.scanline();
if(vcounter() == 241) {
if(vcounter() == 240) {
scheduler.exit(Scheduler::Event::Frame);
}
}