mirror of https://github.com/stella-emu/stella.git
Merge branch 'master' into feature/filesystem
This commit is contained in:
commit
944f20a011
|
@ -72,62 +72,71 @@ FrameLayout FrameLayoutDetector::detectedLayout(bool detectPal60, bool detectNts
|
|||
}
|
||||
#endif
|
||||
|
||||
// Multiply each hue's count with its NTSC and PAL stats and aggregate results
|
||||
// If NTSC/PAL results differ significantly, overrule frame result
|
||||
FrameLayout layout = myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc;
|
||||
// Init the layout based on scanline analysis.
|
||||
FrameLayout layout = myPalFrameSum > myNtscFrameSum ? FrameLayout::pal : FrameLayout::ntsc;
|
||||
|
||||
constexpr std::array<double, NUM_HUES> ntscColorFactor{
|
||||
0.00000, 0.05683, 0.06220, 0.05505, 0.06162, 0.02874, 0.03532, 0.03716,
|
||||
0.15568, 0.06471, 0.02886, 0.03224, 0.06903, 0.11478, 0.02632, 0.01675
|
||||
}; // ignore black = 0x00!
|
||||
constexpr std::array<double, NUM_HUES> palColorFactor{
|
||||
0.00000, 0.00450, 0.09962, 0.07603, 0.06978, 0.13023, 0.09638, 0.02268,
|
||||
0.02871, 0.04700, 0.02950, 0.11974, 0.03474, 0.08025, 0.00642, 0.00167
|
||||
}; // ignore black = 0x00!
|
||||
// Calculation weights and params (optimum based on sampled ROMs optimized for PAL-60)
|
||||
constexpr double POWER_FACTOR = 0.17; // Level the color counts (large values become less relevant)
|
||||
constexpr uInt32 SUM_DIV = 20; // Skip too small counts
|
||||
constexpr uInt32 MIN_VALID = 3; // Minimum number of different hues with significant counts
|
||||
constexpr double SUM_FACTOR = 2.0; // Minimum sum difference which triggers a layout change
|
||||
if(detectPal60 || detectNtsc50)
|
||||
{
|
||||
// Multiply each hue's count with its NTSC and PAL stats and aggregate results
|
||||
// If NTSC/PAL results differ significantly, overrule frame result
|
||||
constexpr std::array<double, NUM_HUES> ntscColorFactor{
|
||||
0.00000, 0.05683, 0.06220, 0.05505, 0.06162, 0.02874, 0.03532, 0.03716,
|
||||
0.15568, 0.06471, 0.02886, 0.03224, 0.06903, 0.11478, 0.02632, 0.01675
|
||||
}; // ignore black = 0x00!
|
||||
constexpr std::array<double, NUM_HUES> palColorFactor{
|
||||
0.00000, 0.00450, 0.09962, 0.07603, 0.06978, 0.13023, 0.09638, 0.02268,
|
||||
0.02871, 0.04700, 0.02950, 0.11974, 0.03474, 0.08025, 0.00642, 0.00167
|
||||
}; // ignore black = 0x00!
|
||||
// Calculation weights and params (optimum based on sampled ROMs, optimized for PAL-60)
|
||||
constexpr double POWER_FACTOR = 0.17; // Level the color counts (large values become less relevant)
|
||||
constexpr uInt32 SUM_DIV = 20; // Skip too small counts (could be removed)
|
||||
constexpr uInt32 MIN_VALID = 3; // Minimum number of different hues with significant counts
|
||||
constexpr double OVERRULE_FACTOR = 2.0; // Minimum sum difference which triggers a layout change
|
||||
|
||||
double ntscSum{0}, palSum{0};
|
||||
std::array<double, NUM_HUES> hueSum{0};
|
||||
double totalHueSum = 0;
|
||||
uInt32 validHues = 0;
|
||||
double ntscColSum{ 0 }, paCollSum{ 0 };
|
||||
std::array<double, NUM_HUES> hueSum{ 0 };
|
||||
double totalHueSum = 0;
|
||||
uInt32 validHues = 0;
|
||||
|
||||
// Aggregate hues
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
for(int lum = 0; lum < NUM_LUMS; ++lum)
|
||||
if(hue || lum) // skip 0x00
|
||||
hueSum[hue] += myColorCount[hue * NUM_LUMS + lum];
|
||||
hueSum[hue] = std::pow(hueSum[hue], POWER_FACTOR);
|
||||
totalHueSum += hueSum[hue];
|
||||
}
|
||||
// Calculate hue sums
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
if(hueSum[hue] > totalHueSum / SUM_DIV)
|
||||
validHues++;
|
||||
ntscSum += hueSum[hue] * ntscColorFactor[hue];
|
||||
palSum += hueSum[hue] * palColorFactor[hue];
|
||||
}
|
||||
// Correct layout if enough valid hues and significant sum difference
|
||||
// TODO: Use fractional scanline counts for intermediate values around 285 scanlines, e.g.
|
||||
// Desert Falcon, Dumbo's Flying Circus, Dungeon, Firefox, Millipede, Popeye, RS Basketball, Star Trek, Stunt Cycle
|
||||
if(validHues >= MIN_VALID)
|
||||
{
|
||||
if(detectPal60 && layout == FrameLayout::ntsc && ntscSum * SUM_FACTOR < palSum)
|
||||
// Aggregate hues
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
layout = FrameLayout::pal60;
|
||||
Logger::debug("Changed layout from NTSC into PAL-60");
|
||||
for(int lum = 0; lum < NUM_LUMS; ++lum)
|
||||
if(hue || lum) // skip 0x00
|
||||
hueSum[hue] += myColorCount[hue * NUM_LUMS + lum];
|
||||
hueSum[hue] = std::pow(hueSum[hue], POWER_FACTOR);
|
||||
totalHueSum += hueSum[hue];
|
||||
}
|
||||
// Note: three false positives (Berzerk, Canyon Bomber, Jawbreaker) for NTSC-50 after
|
||||
// optimizing for PAL-60
|
||||
else if(detectNtsc50 && layout == FrameLayout::pal && palSum * SUM_FACTOR < ntscSum)
|
||||
// Calculate hue sums
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
layout = FrameLayout::ntsc50;
|
||||
Logger::debug("Changed layout from PAL into NTSC-50");
|
||||
if(hueSum[hue] > totalHueSum / SUM_DIV)
|
||||
validHues++;
|
||||
ntscColSum += hueSum[hue] * ntscColorFactor[hue];
|
||||
paCollSum += hueSum[hue] * palColorFactor[hue];
|
||||
}
|
||||
|
||||
// Correct the layout if there are enough valid hues and a significant color sum difference.
|
||||
// The required difference depends on the significance of the scanline analyis.
|
||||
if(validHues >= MIN_VALID)
|
||||
{
|
||||
// Use frame analysis results to scale color overrule factor from 1.0 .. OVERRULE_FACTOR
|
||||
const double overRuleFactor = 1.0 + (OVERRULE_FACTOR - 1.0) * 2
|
||||
* (std::max(myNtscFrameSum, myPalFrameSum) / (myNtscFrameSum + myPalFrameSum) - 0.5); // 1.0 .. OVERRULE_FACTOR
|
||||
|
||||
//cerr << overRuleFactor << " * PAL:" << paCollSum << "/NTSC:" << ntscColSum << endl;
|
||||
if(detectPal60 && layout == FrameLayout::ntsc && ntscColSum * overRuleFactor < paCollSum)
|
||||
{
|
||||
layout = FrameLayout::pal60;
|
||||
Logger::debug("TV format changed from NTSC to PAL-60");
|
||||
}
|
||||
// Note: Three false positives (Adventure, Berzerk, Canyon Bomber) for NTSC-50 after
|
||||
// optimizing for PAL-60
|
||||
else if(detectNtsc50 && layout == FrameLayout::pal && paCollSum * overRuleFactor < ntscColSum)
|
||||
{
|
||||
layout = FrameLayout::ntsc50;
|
||||
Logger::debug("TV format changed from PAL to NTSC-50");
|
||||
}
|
||||
}
|
||||
}
|
||||
return layout;
|
||||
|
@ -143,7 +152,7 @@ FrameLayoutDetector::FrameLayoutDetector()
|
|||
void FrameLayoutDetector::onReset()
|
||||
{
|
||||
myState = State::waitForVsyncStart;
|
||||
myNtscFrames = myPalFrames = 0;
|
||||
myNtscFrameSum = myPalFrameSum = 0;
|
||||
myLinesWaitingForVsyncToStart = 0;
|
||||
myColorCount.fill(0);
|
||||
myIsRendering = true;
|
||||
|
@ -223,37 +232,14 @@ void FrameLayoutDetector::finalizeFrame()
|
|||
|
||||
if (myTotalFrames <= Metrics::initialGarbageFrames) return;
|
||||
|
||||
// Calculate the delta between scanline count and the sweet spot for the respective
|
||||
// frame layouts
|
||||
const uInt32
|
||||
deltaNTSC = abs(static_cast<Int32>(myCurrentFrameFinalLines) - static_cast<Int32>(frameLinesNTSC)),
|
||||
deltaPAL = abs(static_cast<Int32>(myCurrentFrameFinalLines) - static_cast<Int32>(frameLinesPAL));
|
||||
|
||||
// Does the scanline count fall into one of our tolerance windows? -> use it
|
||||
if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance)
|
||||
layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal);
|
||||
else if (
|
||||
// If scanline count is odd and lies between the PAL and NTSC windows we assume
|
||||
// it is NTSC (it would cause color loss on PAL CRTs)
|
||||
(myCurrentFrameFinalLines < frameLinesPAL) &&
|
||||
(myCurrentFrameFinalLines > frameLinesNTSC) &&
|
||||
(myCurrentFrameFinalLines % 2)
|
||||
)
|
||||
layout(FrameLayout::ntsc);
|
||||
else
|
||||
// Take the nearest layout if all else fails
|
||||
layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal);
|
||||
|
||||
switch (layout()) {
|
||||
case FrameLayout::ntsc:
|
||||
++myNtscFrames;
|
||||
break;
|
||||
|
||||
case FrameLayout::pal:
|
||||
++myPalFrames;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("cannot happen");
|
||||
}
|
||||
// Calculate how close a frame is to PAL and NTSC based on scanlines. An odd scanline count
|
||||
// results into a penalty of 0.5 for PAL. The result is between 0.0 (<=262 scanlines) and
|
||||
// 1.0 (>=312) and added to PAL and (inverted) NTSC sums.
|
||||
constexpr double ODD_PENALTY = 0.5; // guessed value :)
|
||||
const double palFrame = BSPF::clamp(((myCurrentFrameFinalLines % 2) ? ODD_PENALTY : 1.0)
|
||||
* static_cast<double>(myCurrentFrameFinalLines - frameLinesNTSC)
|
||||
/ static_cast<double>(frameLinesPAL - frameLinesNTSC), 0.0, 1.0);
|
||||
myPalFrameSum += palFrame;
|
||||
myNtscFrameSum += 1.0 - palFrame;
|
||||
//cerr << myCurrentFrameFinalLines << ", " << palFrame << ", " << myPalFrameSum << ", " << myNtscFrameSum << endl;
|
||||
}
|
||||
|
|
|
@ -95,9 +95,6 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
// (exceeding ideal frame height)
|
||||
waitForVsync = 100,
|
||||
|
||||
// tolerance window around ideal frame size for TV mode detection
|
||||
tvModeDetectionTolerance = 20,
|
||||
|
||||
// these frames will not be considered for detection
|
||||
initialGarbageFrames = TIAConstants::initialGarbageFrames
|
||||
};
|
||||
|
@ -121,10 +118,8 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
*/
|
||||
State myState{State::waitForVsyncStart};
|
||||
|
||||
/**
|
||||
* The total number of frames detected as the respective frame layout.
|
||||
*/
|
||||
uInt32 myNtscFrames{0}, myPalFrames{0};
|
||||
// The aggregated likelynesses of respective two frame layouts.
|
||||
double myNtscFrameSum{0}, myPalFrameSum{0};
|
||||
|
||||
/**
|
||||
* We count the number of scanlines we spend waiting for vsync to be
|
||||
|
@ -139,7 +134,6 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
*/
|
||||
static constexpr int NUM_HUES = 16;
|
||||
static constexpr int NUM_LUMS = 8;
|
||||
|
||||
std::array<uInt64, NUM_HUES * NUM_LUMS> myColorCount{0};
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue