Update to bsnes v107r3 beta release.

byuu says:

Changes: HD mode 7 supersampling support, HD mode 7 mosaic disable option,
various HD mode 7 bugfixes, default waveOut audio latency to 128 instead of 512,
removed 512x240 hires mode 7 mode.

There's also a small experiment, making this release a beta release as well:
for a large speedup, when in EXTBG mode, I'm bypassing rendering BG1 for a
performance boost. EXTBG is only used as a priority layer, and is overwritten by
BG2 except in one extremely pathological case.
This commit is contained in:
Tim Allen 2019-04-19 18:02:31 +10:00
parent 7a548482ed
commit becbca47d4
16 changed files with 113 additions and 139 deletions

View File

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

View File

@ -1490,6 +1490,7 @@ const int16 Dsp1::SinTable[256] = {
// As a curiosity, in the positions 0x21c-0x31c it's contained a // As a curiosity, in the positions 0x21c-0x31c it's contained a
// 257-points arccos table that, apparently, have been not used anywhere // 257-points arccos table that, apparently, have been not used anywhere
// (maybe for the MaxAZS_Exp table?). // (maybe for the MaxAZS_Exp table?).
// byuu note: the error at DataRom[0x3c] has been corrected from 0x0001 to 0x0010
const uint16 Dsp1::DataRom[1024] = { const uint16 Dsp1::DataRom[1024] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
@ -1498,7 +1499,7 @@ const int16 Dsp1::SinTable[256] = {
0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020,
0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000,
0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200,
0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002,
0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,

View File

@ -18,9 +18,10 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit); bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
bind(boolean, "Hacks/PPU/Mode7/Hires", hacks.ppu.mode7.hires);
bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale);
bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective); bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective);
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
bind(boolean, "Hacks/PPU/Mode7/Mosaic", hacks.ppu.mode7.mosaic);
bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast); bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast);
bind(boolean, "Hacks/DSP/Cubic", hacks.dsp.cubic); bind(boolean, "Hacks/DSP/Cubic", hacks.dsp.cubic);
bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle); bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle);

View File

@ -29,9 +29,10 @@ struct Configuration {
bool fast = true; bool fast = true;
bool noSpriteLimit = false; bool noSpriteLimit = false;
struct Mode7 { struct Mode7 {
bool hires = false;
uint scale = 1; uint scale = 1;
bool perspective = true; bool perspective = true;
bool supersample = false;
bool mosaic = true;
} mode7; } mode7;
} ppu; } ppu;
struct DSP { struct DSP {

View File

@ -14,6 +14,7 @@ auto PPUfast::Line::flush() -> void {
auto PPUfast::Line::render() -> void { auto PPUfast::Line::render() -> void {
auto hd = ppufast.hd(); auto hd = ppufast.hd();
auto ss = ppufast.ss();
auto scale = ppufast.hdScale(); auto scale = ppufast.hdScale();
auto output = ppufast.output + (!hd auto output = ppufast.output + (!hd
? (y * 1024 + (ppufast.interlace() && ppufast.field() ? 512 : 0)) ? (y * 1024 + (ppufast.interlace() && ppufast.field() ? 512 : 0))
@ -29,11 +30,10 @@ auto PPUfast::Line::render() -> void {
} }
bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
bool hiresMode7 = io.bgMode == 7 && configuration.hacks.ppu.mode7.hires;
auto aboveColor = cgram[0]; auto aboveColor = cgram[0];
auto belowColor = hires ? cgram[0] : io.col.fixedColor; auto belowColor = hires ? cgram[0] : io.col.fixedColor;
uint xa = hd && ppufast.interlace() && ppufast.field() ? 256 * scale * scale / 2 : 0; uint xa = (hd || ss) && ppufast.interlace() && ppufast.field() ? 256 * scale * scale / 2 : 0;
uint xb = !hd ? 256 << hiresMode7 : ppufast.interlace() && !ppufast.field() ? 256 * scale * scale / 2 : 256 * scale * scale; uint xb = !(hd || ss) ? 256 : ppufast.interlace() && !ppufast.field() ? 256 * scale * scale / 2 : 256 * scale * scale;
for(uint x = xa; x < xb; x++) { for(uint x = xa; x < xb; x++) {
above[x] = {Source::COL, 0, aboveColor}; above[x] = {Source::COL, 0, aboveColor};
below[x] = {Source::COL, 0, belowColor}; below[x] = {Source::COL, 0, belowColor};
@ -50,10 +50,6 @@ auto PPUfast::Line::render() -> void {
auto luma = io.displayBrightness << 15; auto luma = io.displayBrightness << 15;
if(hd) for(uint x : range(256 * scale * scale)) { if(hd) for(uint x : range(256 * scale * scale)) {
*output++ = luma | pixel(x / scale & 255, above[x], below[x]); *output++ = luma | pixel(x / scale & 255, above[x], below[x]);
} else if(hiresMode7) for(uint x : range(512)) {
auto Above = above[x >> 1].source >= Source::OBJ1 ? above[x >> 1] : above[x >> 1 | (x & 1 ? 256 : 0)];
auto Below = below[x >> 1].source >= Source::OBJ1 ? below[x >> 1] : below[x >> 1 | (x & 1 ? 256 : 0)];
*output++ = luma | pixel(x >> 1, Above, Below);
} else if(width == 256) for(uint x : range(256)) { } else if(width == 256) for(uint x : range(256)) {
*output++ = luma | pixel(x, above[x], below[x]); *output++ = luma | pixel(x, above[x], below[x]);
} else if(!hires) for(uint x : range(256)) { } else if(!hires) for(uint x : range(256)) {

View File

@ -1,6 +1,12 @@
auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> void { auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> void {
if(ppufast.hdScale() > 1) return renderMode7HD(self, source); //EXTBG is only really used by games to give the mode 7 layer two priority levels
if(configuration.hacks.ppu.mode7.hires) return renderMode7Hires(self, source); //especially with HD mode 7, it's just wasteful to render BG1 just to be overwritten by BG2
if(io.extbg && source == Source::BG1) return;
//HD mode 7 support
if(!ppufast.hdMosaic() || !self.mosaicEnable || !io.mosaicSize) {
if(ppufast.hdScale() > 1) return renderMode7HD(self, source);
}
int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
int y = !io.mode7.vflip ? Y : 255 - Y; int y = !io.mode7.vflip ? Y : 255 - Y;

View File

@ -21,9 +21,6 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
} }
#undef isLineMode7 #undef isLineMode7
int Y = y - (self.mosaicEnable ? y % (1 + io.mosaicSize) : 0);
float yt = !io.mode7.vflip ? Y : 255 - Y;
Line line_a = ppufast.lines[y_a]; Line line_a = ppufast.lines[y_a];
float a_a = (int16)line_a.io.mode7.a; float a_a = (int16)line_a.io.mode7.a;
float b_a = (int16)line_a.io.mode7.b; float b_a = (int16)line_a.io.mode7.b;
@ -41,6 +38,11 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
int hoffset = (int13)io.mode7.hoffset; int hoffset = (int13)io.mode7.hoffset;
int voffset = (int13)io.mode7.voffset; int voffset = (int13)io.mode7.voffset;
if(io.mode7.vflip) {
y_a = 255 - y_a;
y_b = 255 - y_b;
}
array<bool[256]> windowAbove; array<bool[256]> windowAbove;
array<bool[256]> windowBelow; array<bool[256]> windowBelow;
renderWindow(self.window, self.window.aboveEnable, windowAbove); renderWindow(self.window, self.window.aboveEnable, windowAbove);
@ -48,74 +50,92 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
int pixelYp = INT_MIN; int pixelYp = INT_MIN;
for(int ys : range(scale)) { for(int ys : range(scale)) {
float y = yt + ys * 1.0 / scale - 0.5; float yf = y + ys * 1.0 / scale - 0.5;
float a = 1.0 / lerp(y_a, 1.0 / a_a, y_b, 1.0 / a_b, y); if(io.mode7.vflip) yf = 255 - yf;
float b = 1.0 / lerp(y_a, 1.0 / b_a, y_b, 1.0 / b_b, y);
float c = 1.0 / lerp(y_a, 1.0 / c_a, y_b, 1.0 / c_b, y); float a = 1.0 / lerp(y_a, 1.0 / a_a, y_b, 1.0 / a_b, yf);
float d = 1.0 / lerp(y_a, 1.0 / d_a, y_b, 1.0 / d_b, y); float b = 1.0 / lerp(y_a, 1.0 / b_a, y_b, 1.0 / b_b, yf);
float c = 1.0 / lerp(y_a, 1.0 / c_a, y_b, 1.0 / c_b, yf);
float d = 1.0 / lerp(y_a, 1.0 / d_a, y_b, 1.0 / d_b, yf);
int ht = (hoffset - hcenter) % 1024; int ht = (hoffset - hcenter) % 1024;
float vty = ((voffset - vcenter) % 1024) + y; float vty = ((voffset - vcenter) % 1024) + yf;
float originX = (a * ht) + (b * vty) + (hcenter << 8); float originX = (a * ht) + (b * vty) + (hcenter << 8);
float originY = (c * ht) + (d * vty) + (vcenter << 8); float originY = (c * ht) + (d * vty) + (vcenter << 8);
uint tile, palette, priority;
//some games enable mosaic with a mosaic size of 0 (1x1)
bool mosaicEnable = self.mosaicEnable && io.mosaicSize;
uint mosaicCounter = 1;
uint mosaicPalette = 0;
uint mosaicPriority = 0;
uint mosaicColor = 0;
Pixel mosaicPixel;
int pixelXp = INT_MIN; int pixelXp = INT_MIN;
for(int X : range(256)) { for(int x : range(256)) {
float xt = !io.mode7.hflip ? X : 255 - X; bool doAbove = self.aboveEnable && !windowAbove[x];
bool doAbove = self.aboveEnable && !windowAbove[X]; bool doBelow = self.belowEnable && !windowBelow[x];
bool doBelow = self.belowEnable && !windowBelow[X];
for(int xs : range(scale)) { for(int xs : range(scale)) {
float x = xt + xs * 1.0 / scale - 0.5; float xf = x + xs * 1.0 / scale - 0.5;
int pixelX = (originX + a * x) / 256; if(io.mode7.hflip) xf = 255 - xf;
int pixelY = (originY + c * x) / 256;
int pixelX = (originX + a * xf) / 256;
int pixelY = (originY + c * xf) / 256;
above++; above++;
below++; below++;
//only compute color again when coordinates have changed //only compute color again when coordinates have changed
if(pixelX != pixelXp || pixelY != pixelYp) { if(pixelX != pixelXp || pixelY != pixelYp) {
pixelXp = pixelX; uint tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)].byte(0);
pixelYp = pixelY; uint palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)].byte(1);
tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)].byte(0);
palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)].byte(1);
uint priority;
if(!extbg) { if(!extbg) {
priority = self.priority[0]; priority = self.priority[0];
} else { } else {
priority = self.priority[palette >> 7]; priority = self.priority[palette >> 7];
palette &= 0x7f; palette &= 0x7f;
} }
} if(!palette) continue;
if(!mosaicEnable || --mosaicCounter == 0) { uint color;
mosaicCounter = (1 + io.mosaicSize) * scale;
mosaicPalette = palette;
mosaicPriority = priority;
if(io.col.directColor && !extbg) { if(io.col.directColor && !extbg) {
mosaicColor = directColor(0, palette); color = directColor(0, palette);
} else { } else {
mosaicColor = cgram[palette]; color = cgram[palette];
} }
pixel = {source, mosaicPriority, mosaicColor};
}
if(!mosaicPalette) continue;
if(doAbove && (!extbg || mosaicPriority > above->priority)) *above = pixel; pixel = {source, priority, color};
if(doBelow && (!extbg || mosaicPriority > below->priority)) *below = pixel; pixelXp = pixelX;
pixelYp = pixelY;
}
if(doAbove && (!extbg || pixel.priority > above->priority)) *above = pixel;
if(doBelow && (!extbg || pixel.priority > below->priority)) *below = pixel;
} }
} }
} }
if(ppufast.ss()) {
uint divisor = scale * scale;
for(uint p : range(256)) {
uint ab = 0, bb = 0;
uint ag = 0, bg = 0;
uint ar = 0, br = 0;
for(uint y : range(scale)) {
auto above = &this->above[p * scale];
auto below = &this->below[p * scale];
for(uint x : range(scale)) {
uint a = above[x].color;
uint b = below[x].color;
ab += a >> 0 & 31;
ag += a >> 5 & 31;
ar += a >> 10 & 31;
bb += b >> 0 & 31;
bg += b >> 5 & 31;
br += b >> 10 & 31;
}
}
uint aboveColor = ab / divisor << 0 | ag / divisor << 5 | ar / divisor << 10;
uint belowColor = bb / divisor << 0 | bg / divisor << 5 | br / divisor << 10;
this->above[p] = {source, this->above[p * scale].priority, aboveColor};
this->below[p] = {source, this->below[p * scale].priority, belowColor};
}
}
} }
//interpolation and extrapolation //interpolation and extrapolation

View File

@ -1,63 +0,0 @@
auto PPUfast::Line::renderMode7Hires(PPUfast::IO::Background& self, uint source) -> void {
int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
int y = !io.mode7.vflip ? Y : 255 - Y;
int a = (int16)io.mode7.a;
int b = (int16)io.mode7.b;
int c = (int16)io.mode7.c;
int d = (int16)io.mode7.d;
int hcenter = (int13)io.mode7.x;
int vcenter = (int13)io.mode7.y;
int hoffset = (int13)io.mode7.hoffset;
int voffset = (int13)io.mode7.voffset;
uint mosaicCounter = 1;
uint mosaicPalette = 0;
uint mosaicPriority = 0;
uint mosaicColor = 0;
auto clip = [](int n) -> int { return n & 0x2000 ? (n | ~1023) : (n & 1023); };
int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8);
int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8);
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow);
for(int X : range(512)) {
int x = !io.mode7.hflip ? X : 511 - X;
int pixelX = 2 * originX + a * x >> 9;
int pixelY = 2 * originY + c * x >> 9;
int tileX = pixelX >> 3 & 127;
int tileY = pixelY >> 3 & 127;
bool outOfBounds = (pixelX | pixelY) & ~1023;
uint15 tileAddress = tileY * 128 + tileX;
uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7);
uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppufast.vram[tileAddress].byte(0);
uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppufast.vram[paletteAddress + (tile << 6)].byte(1);
uint priority;
if(source == Source::BG1) {
priority = self.priority[0];
} else if(source == Source::BG2) {
priority = self.priority[palette >> 7];
palette &= 0x7f;
}
if(!self.mosaicEnable || !io.mosaicSize || --mosaicCounter == 0) {
mosaicCounter = (1 + io.mosaicSize) << 1;
mosaicPalette = palette;
mosaicPriority = priority;
if(io.col.directColor && source == Source::BG1) {
mosaicColor = directColor(0, palette);
} else {
mosaicColor = cgram[palette];
}
}
if(!mosaicPalette) continue;
if(self.aboveEnable && !windowAbove[X >> 1]) plotAbove(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor);
if(self.belowEnable && !windowBelow[X >> 1]) plotBelow(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor);
}
}

View File

@ -9,7 +9,6 @@ PPUfast ppufast;
#include "line.cpp" #include "line.cpp"
#include "background.cpp" #include "background.cpp"
#include "mode7.cpp" #include "mode7.cpp"
#include "mode7hires.cpp"
#include "mode7hd.cpp" #include "mode7hd.cpp"
#include "object.cpp" #include "object.cpp"
#include "window.cpp" #include "window.cpp"
@ -20,8 +19,11 @@ auto PPUfast::overscan() const -> bool { return ppubase.display.overscan; }
auto PPUfast::vdisp() const -> uint { return ppubase.display.vdisp; } auto PPUfast::vdisp() const -> uint { return ppubase.display.vdisp; }
auto PPUfast::hires() const -> bool { return latch.hires; } auto PPUfast::hires() const -> bool { return latch.hires; }
auto PPUfast::hd() const -> bool { return latch.hd; } auto PPUfast::hd() const -> bool { return latch.hd; }
auto PPUfast::ss() const -> bool { return latch.ss; }
auto PPUfast::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; } auto PPUfast::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; }
auto PPUfast::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; } auto PPUfast::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; }
auto PPUfast::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; }
auto PPUfast::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; }
PPUfast::PPUfast() { PPUfast::PPUfast() {
output = new uint32[2304 * 2304] + 72 * 2304; //overscan offset output = new uint32[2304 * 2304] + 72 * 2304; //overscan offset
@ -78,14 +80,15 @@ auto PPUfast::scanline() -> void {
ppubase.display.overscan = io.overscan; ppubase.display.overscan = io.overscan;
latch.hires = false; latch.hires = false;
latch.hd = false; latch.hd = false;
latch.ss = false;
io.obj.timeOver = false; io.obj.timeOver = false;
io.obj.rangeOver = false; io.obj.rangeOver = false;
} }
if(vcounter() > 0 && vcounter() < vdisp()) { if(vcounter() > 0 && vcounter() < vdisp()) {
latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
latch.hires |= io.bgMode == 7 && configuration.hacks.ppu.mode7.hires; latch.hd |= io.bgMode == 7 && hdScale() > 1 && hdSupersample() == 0;
latch.hd |= io.bgMode == 7 && hdScale() > 1; latch.ss |= io.bgMode == 7 && hdScale() > 1 && hdSupersample() == 1;
} }
if(vcounter() == vdisp() && !io.displayDisable) { if(vcounter() == vdisp() && !io.displayDisable) {

View File

@ -11,8 +11,11 @@ struct PPUfast : Thread, PPUcounter {
alwaysinline auto vdisp() const -> uint; alwaysinline auto vdisp() const -> uint;
alwaysinline auto hires() const -> bool; alwaysinline auto hires() const -> bool;
alwaysinline auto hd() const -> bool; alwaysinline auto hd() const -> bool;
alwaysinline auto ss() const -> bool;
alwaysinline auto hdScale() const -> uint; alwaysinline auto hdScale() const -> uint;
alwaysinline auto hdPerspective() const -> bool; alwaysinline auto hdPerspective() const -> bool;
alwaysinline auto hdSupersample() const -> bool;
alwaysinline auto hdMosaic() const -> bool;
//ppu.cpp //ppu.cpp
PPUfast(); PPUfast();
@ -42,6 +45,7 @@ public:
uint1 overscan; uint1 overscan;
uint1 hires; uint1 hires;
uint1 hd; uint1 hd;
uint1 ss;
uint16 vram; uint16 vram;
uint8 oam; uint8 oam;
@ -281,9 +285,6 @@ public:
//mode7.cpp //mode7.cpp
auto renderMode7(PPUfast::IO::Background&, uint source) -> void; auto renderMode7(PPUfast::IO::Background&, uint source) -> void;
//mode7hires.cpp
auto renderMode7Hires(PPUfast::IO::Background&, uint source) -> void;
//mode7hd.cpp //mode7hd.cpp
auto renderMode7HD(PPUfast::IO::Background&, uint source) -> void; auto renderMode7HD(PPUfast::IO::Background&, uint source) -> void;
alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float; alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float;

View File

@ -18,6 +18,7 @@ auto PPUfast::Latch::serialize(serializer& s) -> void {
s.integer(overscan); s.integer(overscan);
s.integer(hires); s.integer(hires);
s.integer(hd); s.integer(hd);
s.integer(ss);
s.integer(vram); s.integer(vram);
s.integer(oam); s.integer(oam);
s.integer(cgram); s.integer(cgram);

View File

@ -1,7 +1,6 @@
auto Program::hackCompatibility() -> void { auto Program::hackCompatibility() -> void {
bool fastPPU = emulatorSettings.fastPPU.checked(); bool fastPPU = emulatorSettings.fastPPU.checked();
bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked(); bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked();
bool fastPPUHiresMode7 = emulatorSettings.hiresMode7.checked();
bool fastDSP = emulatorSettings.fastDSP.checked(); bool fastDSP = emulatorSettings.fastDSP.checked();
bool coprocessorsDelayedSync = emulatorSettings.coprocessorsDelayedSyncOption.checked(); bool coprocessorsDelayedSync = emulatorSettings.coprocessorsDelayedSyncOption.checked();
@ -12,9 +11,10 @@ auto Program::hackCompatibility() -> void {
emulator->configure("Hacks/PPU/Fast", fastPPU); emulator->configure("Hacks/PPU/Fast", fastPPU);
emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit); emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit);
emulator->configure("Hacks/PPU/Mode7/Hires", fastPPUHiresMode7);
emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale); emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale);
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
emulator->configure("Hacks/DSP/Fast", fastDSP); emulator->configure("Hacks/DSP/Fast", fastDSP);
emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic); emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic);
emulator->configure("Hacks/Coprocessors/DelayedSync", coprocessorsDelayedSync); emulator->configure("Hacks/Coprocessors/DelayedSync", coprocessorsDelayedSync);

View File

@ -13,7 +13,7 @@ auto DriverSettings::create() -> void {
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); }); videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
videoFormatLabel.setText("Format:"); videoFormatLabel.setText("Format:");
videoFormatOption.onChange([&] { videoFormatChange(); }); videoFormatOption.onChange([&] { videoFormatChange(); });
videoExclusiveToggle.setText("Exclusive").setToolTip( videoExclusiveToggle.setText("Exclusive fullscreen mode").setToolTip(
"(Direct3D driver only)\n\n" "(Direct3D driver only)\n\n"
"Acquires exclusive access to the display in fullscreen mode.\n" "Acquires exclusive access to the display in fullscreen mode.\n"
"Eliminates compositing issues such as video stuttering." "Eliminates compositing issues such as video stuttering."
@ -57,7 +57,7 @@ auto DriverSettings::create() -> void {
audioFrequencyOption.onChange([&] { audioFrequencyChange(); }); audioFrequencyOption.onChange([&] { audioFrequencyChange(); });
audioLatencyLabel.setText("Latency:"); audioLatencyLabel.setText("Latency:");
audioLatencyOption.onChange([&] { audioLatencyChange(); }); audioLatencyOption.onChange([&] { audioLatencyChange(); });
audioExclusiveToggle.setText("Exclusive").setToolTip( audioExclusiveToggle.setText("Exclusive mode").setToolTip(
"(ASIO, WASAPI drivers only)\n\n" "(ASIO, WASAPI drivers only)\n\n"
"Acquires exclusive control of the sound card device.\n" "Acquires exclusive control of the sound card device.\n"
"This can significantly reduce audio latency.\n" "This can significantly reduce audio latency.\n"

View File

@ -42,19 +42,13 @@ auto EmulatorSettings::create() -> void {
settings.emulator.hack.ppu.fast = fastPPU.checked(); settings.emulator.hack.ppu.fast = fastPPU.checked();
if(!fastPPU.checked()) { if(!fastPPU.checked()) {
noSpriteLimit.setEnabled(false).setChecked(false).doToggle(); noSpriteLimit.setEnabled(false).setChecked(false).doToggle();
hiresMode7.setEnabled(false).setChecked(false).doToggle();
} else { } else {
noSpriteLimit.setEnabled(true); noSpriteLimit.setEnabled(true);
hiresMode7.setEnabled(true);
} }
}).doToggle(); }).doToggle();
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] { noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked(); settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
}); });
hiresMode7.setText("Hires mode 7").setChecked(settings.emulator.hack.ppu.mode7.hires).setVisible(false).onToggle([&] {
settings.emulator.hack.ppu.mode7.hires = hiresMode7.checked();
emulator->configure("Hacks/PPU/Mode7/Hires", settings.emulator.hack.ppu.mode7.hires);
});
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold()); mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
mode7ScaleLabel.setText("Scale:"); mode7ScaleLabel.setText("Scale:");
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1)); mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
@ -77,6 +71,14 @@ auto EmulatorSettings::create() -> void {
settings.emulator.hack.ppu.mode7.perspective = mode7Perspective.checked(); settings.emulator.hack.ppu.mode7.perspective = mode7Perspective.checked();
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
}); });
mode7Supersample.setText("Supersample").setChecked(settings.emulator.hack.ppu.mode7.supersample).onToggle([&] {
settings.emulator.hack.ppu.mode7.supersample = mode7Supersample.checked();
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
});
mode7Mosaic.setText("HD->SD Mosaic").setChecked(settings.emulator.hack.ppu.mode7.mosaic).onToggle([&] {
settings.emulator.hack.ppu.mode7.mosaic = mode7Mosaic.checked();
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
});
dspLabel.setText("DSP (audio)").setFont(Font().setBold()); dspLabel.setText("DSP (audio)").setFont(Font().setBold());
fastDSP.setText("Fast mode").setChecked(settings.emulator.hack.dsp.fast).onToggle([&] { fastDSP.setText("Fast mode").setChecked(settings.emulator.hack.dsp.fast).onToggle([&] {
settings.emulator.hack.dsp.fast = fastDSP.checked(); settings.emulator.hack.dsp.fast = fastDSP.checked();
@ -105,8 +107,10 @@ auto EmulatorSettings::create() -> void {
auto EmulatorSettings::updateConfiguration() -> void { auto EmulatorSettings::updateConfiguration() -> void {
emulator->configure("Hacks/PPU/Fast", fastPPU.checked()); emulator->configure("Hacks/PPU/Fast", fastPPU.checked());
emulator->configure("Hacks/PPU/NoSpriteLimit", noSpriteLimit.checked()); emulator->configure("Hacks/PPU/NoSpriteLimit", noSpriteLimit.checked());
emulator->configure("Hacks/PPU/Mode7/Hires", hiresMode7.checked());
emulator->configure("Hacks/PPU/Mode7/Scale", mode7Scale.selected().property("multiplier").natural()); emulator->configure("Hacks/PPU/Mode7/Scale", mode7Scale.selected().property("multiplier").natural());
emulator->configure("Hacks/PPU/Mode7/Perspective", mode7Perspective.checked());
emulator->configure("Hacks/PPU/Mode7/Supersample", mode7Supersample.checked());
emulator->configure("Hacks/PPU/Mode7/Mosaic", mode7Mosaic.checked());
emulator->configure("Hacks/DSP/Fast", fastDSP.checked()); emulator->configure("Hacks/DSP/Fast", fastDSP.checked());
emulator->configure("Hacks/DSP/Cubic", cubicInterpolation.checked()); emulator->configure("Hacks/DSP/Cubic", cubicInterpolation.checked());
emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked()); emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked());

View File

@ -97,9 +97,10 @@ auto Settings::process(bool load) -> void {
bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad); bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad);
bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast); bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast);
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit); bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
bind(boolean, "Emulator/Hack/PPU/Mode7/Hires", emulator.hack.ppu.mode7.hires);
bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale); bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale);
bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective); bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective);
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
bind(boolean, "Emulator/Hack/PPU/Mode7/Mosaic", emulator.hack.ppu.mode7.mosaic);
bind(boolean, "Emulator/Hack/DSP/Fast", emulator.hack.dsp.fast); bind(boolean, "Emulator/Hack/DSP/Fast", emulator.hack.dsp.fast);
bind(boolean, "Emulator/Hack/DSP/Cubic", emulator.hack.dsp.cubic); bind(boolean, "Emulator/Hack/DSP/Cubic", emulator.hack.dsp.cubic);
bind(boolean, "Emulator/Hack/Coprocessors/DelayedSync", emulator.hack.coprocessors.delayedSync); bind(boolean, "Emulator/Hack/Coprocessors/DelayedSync", emulator.hack.coprocessors.delayedSync);

View File

@ -79,9 +79,10 @@ struct Settings : Markup::Node {
bool fast = true; bool fast = true;
bool noSpriteLimit = false; bool noSpriteLimit = false;
struct Mode7 { struct Mode7 {
bool hires = false;
uint scale = 1; uint scale = 1;
bool perspective = true; bool perspective = true;
bool supersample = false;
bool mosaic = true;
} mode7; } mode7;
} ppu; } ppu;
struct DSP { struct DSP {
@ -265,12 +266,13 @@ public:
HorizontalLayout ppuLayout{&layout, Size{~0, 0}}; HorizontalLayout ppuLayout{&layout, Size{~0, 0}};
CheckLabel fastPPU{&ppuLayout, Size{0, 0}}; CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}}; CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
CheckLabel hiresMode7{&ppuLayout, Size{0, 0}};
Label mode7Label{&layout, Size{~0, 0}, 2}; Label mode7Label{&layout, Size{~0, 0}, 2};
HorizontalLayout mode7Layout{&layout, Size{~0, 0}}; HorizontalLayout mode7Layout{&layout, Size{~0, 0}};
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}}; Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
ComboButton mode7Scale{&mode7Layout, Size{0, 0}}; ComboButton mode7Scale{&mode7Layout, Size{0, 0}};
CheckLabel mode7Perspective{&mode7Layout, Size{0, 0}}; CheckLabel mode7Perspective{&mode7Layout, Size{0, 0}};
CheckLabel mode7Supersample{&mode7Layout, Size{0, 0}};
CheckLabel mode7Mosaic{&mode7Layout, Size{0, 0}};
Label dspLabel{&layout, Size{~0, 0}, 2}; Label dspLabel{&layout, Size{~0, 0}, 2};
HorizontalLayout dspLayout{&layout, Size{~0, 0}}; HorizontalLayout dspLayout{&layout, Size{~0, 0}};
CheckLabel fastDSP{&dspLayout, Size{0, 0}}; CheckLabel fastDSP{&dspLayout, Size{0, 0}};