Enhanced perspective correction support [DerKoun]
This commit is contained in:
byuu 2019-09-03 18:50:46 +09:00
parent 90f094b931
commit 1195c46ac0
5 changed files with 129 additions and 12 deletions

View File

@ -29,7 +29,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "108.16";
static const string Version = "108.17";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org";

View File

@ -3,6 +3,7 @@ uint PPU::Line::count = 0;
auto PPU::Line::flush() -> void {
if(Line::count) {
if(ppu.hdScale() > 1) cacheMode7HD();
#pragma omp parallel for if(Line::count >= 8)
for(uint y = 0; y < Line::count; y++) {
if(ppu.deinterlace()) {

View File

@ -16,8 +16,6 @@ auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void {
int hoffset = (int13)io.mode7.hoffset;
int voffset = (int13)io.mode7.voffset;
//if(source==Source::BG1&&y==1) print(a, " ", b, " ", c, " ", d, " ", hcenter, " ", vcenter, " ", hoffset, " ", voffset, "\n");
uint mosaicCounter = 1;
uint mosaicPalette = 0;
uint mosaicPriority = 0;

View File

@ -1,3 +1,100 @@
//determine mode 7 line groups for perspective correction
auto PPU::Line::cacheMode7HD() -> void {
ppu.mode7LineGroups.count = 0;
if(ppu.hdPerspective()) {
#define isLineMode7(line) (line.io.bg1.tileMode == TileMode::Mode7 && !line.io.displayDisable && ( \
(line.io.bg1.aboveEnable || line.io.bg1.belowEnable) \
))
bool state = false;
uint y;
//find the moe 7 groups
for(y = 0; y < Line::count; y++) {
if(state != isLineMode7(ppu.lines[Line::start + y])) {
state = !state;
if(state) {
ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y;
} else {
ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1;
//the lines at the edges of mode 7 groups may be erroneous, so start and end lines for interpolation are moved inside
int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8;
ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset;
ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset;
ppu.mode7LineGroups.count++;
}
}
}
#undef isLineMode7
if(state) {
//close the last group if necessary
ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1;
int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8;
ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset;
ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset;
ppu.mode7LineGroups.count++;
}
//detect groups that do not have perspective
for(int i : range(ppu.mode7LineGroups.count)) {
int a = -1, b = -1, c = -1, d = -1; //the mode 7 scale factors of the current line
int aPrev = -1, bPrev = -1, cPrev = -1, dPrev = -1; //the mode 7 scale factors of the previous line
bool aVar = false, bVar = false, cVar = false, dVar = false; //has a varying value been found for the factors?
bool aInc = false, bInc = false, cInc = false, dInc = false; //has the variation been an increase or decrease?
for(y = ppu.mode7LineGroups.startLerpLine[i]; y <= ppu.mode7LineGroups.endLerpLine[i]; y++) {
a = ((int)((int16)(ppu.lines[y].io.mode7.a)));
b = ((int)((int16)(ppu.lines[y].io.mode7.b)));
c = ((int)((int16)(ppu.lines[y].io.mode7.c)));
d = ((int)((int16)(ppu.lines[y].io.mode7.d)));
//has the value of 'a' changed compared to the last line?
//(and is the factor larger than zero, which happens sometimes and seems to be game-specific, mostly at the edges of the screen)
if(aPrev > 0 && a > 0 && a != aPrev) {
if(!aVar) {
//if there has been no variation yet, store that there is one and store if it is an increase or decrease
aVar = true;
aInc = a > aPrev;
} else if(aInc != a > aPrev) {
//if there has been an increase and now we have a decrease, or vice versa, set the interpolation lines to -1
//to deactivate perspective correction for this group and stop analyzing it further
ppu.mode7LineGroups.startLerpLine[i] = -1;
ppu.mode7LineGroups.endLerpLine[i] = -1;
break;
}
}
if(bPrev > 0 && b > 0 && b != bPrev) {
if(!bVar) {
bVar = true;
bInc = b > bPrev;
} else if(bInc != b > bPrev) {
ppu.mode7LineGroups.startLerpLine[i] = -1;
ppu.mode7LineGroups.endLerpLine[i] = -1;
break;
}
}
if(cPrev > 0 && c > 0 && c != cPrev) {
if(!cVar) {
cVar = true;
cInc = c > cPrev;
} else if(cInc != c > cPrev) {
ppu.mode7LineGroups.startLerpLine[i] = -1;
ppu.mode7LineGroups.endLerpLine[i] = -1;
break;
}
}
if(dPrev > 0 && d > 0 && d != bPrev) {
if(!dVar) {
dVar = true;
dInc = d > dPrev;
} else if(dInc != d > dPrev) {
ppu.mode7LineGroups.startLerpLine[i] = -1;
ppu.mode7LineGroups.endLerpLine[i] = -1;
break;
}
}
aPrev = a, bPrev = b, cPrev = c, dPrev = d;
}
}
}
}
auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
const bool extbg = source == Source::BG2;
const uint scale = ppu.hdScale();
@ -7,15 +104,25 @@ auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
Pixel* below = &this->below[-1];
//find the first and last scanline for interpolation
int y_a = y;
int y_b = y;
#define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \
int y_a = -1;
int y_b = -1;
#define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && !ppu.lines[n].io.displayDisable && ( \
(ppu.lines[n].io.bg1.aboveEnable || ppu.lines[n].io.bg1.belowEnable) \
))
if(ppu.hdPerspective()) {
while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1;
while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8;
} else {
if(ppu.hdPerspective()) {
//find the mode 7 line group this line is in and use its interpolation lines
for(int i : range(ppu.mode7LineGroups.count)) {
if(y >= ppu.mode7LineGroups.startLine[i] && y <= ppu.mode7LineGroups.endLine[i]) {
y_a = ppu.mode7LineGroups.startLerpLine[i];
y_b = ppu.mode7LineGroups.endLerpLine[i];
break;
}
}
}
if(y_a == -1 || y_b == -1) {
//if perspective correction is disabled or the group was detected as non-perspective, use the neighboring lines
y_a = y;
y_b = y;
if(y_a > 1 && isLineMode7(y_a)) y_a--;
if(y_b < 239 && isLineMode7(y_b)) y_b++;
}

View File

@ -265,7 +265,7 @@ public:
auto readObject(uint10 address) -> uint8;
auto writeObject(uint10 address, uint8 data) -> void;
//[serialized]
//serialized:
Latch latch;
IO io;
@ -303,6 +303,7 @@ public:
auto renderMode7(PPU::IO::Background&, uint source) -> void;
//mode7hd.cpp
static auto cacheMode7HD() -> void;
auto renderMode7HD(PPU::IO::Background&, uint source) -> void;
alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float;
@ -313,7 +314,7 @@ public:
auto renderWindow(PPU::IO::WindowLayer&, bool enable, bool output[256]) -> void;
auto renderWindow(PPU::IO::WindowColor&, uint mask, bool output[256]) -> void;
//[unserialized]
//unserialized:
uint y; //constant
bool fieldID;
@ -333,6 +334,8 @@ public:
static uint start;
static uint count;
};
//unserialized:
Line lines[240];
//used to help detect when the video output size changes between frames to clear overscan area.
@ -341,6 +344,14 @@ public:
uint width = 0;
uint height = 0;
} frame;
struct Mode7LineGroups {
int count = -1;
int startLine[32];
int endLine[32];
int startLerpLine[32];
int endLerpLine[32];
} mode7LineGroups;
};
extern PPU ppufast;