PPU: Fixed glitches when games turn overscan + interlace on and back off mid-frame
(Chrono Trigger does this for a couple of frames when a battle starts)
This commit is contained in:
parent
8798a73deb
commit
dc6d295b1a
2 changed files with 19 additions and 13 deletions
31
Core/Ppu.cpp
31
Core/Ppu.cpp
|
@ -385,15 +385,16 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
|
||||||
RenderScanline();
|
RenderScanline();
|
||||||
|
|
||||||
if(_scanline == 0) {
|
if(_scanline == 0) {
|
||||||
|
_overscanFrame = _state.OverscanMode;
|
||||||
_mosaicScanlineCounter = _state.MosaicEnabled ? _state.MosaicSize + 1 : 0;
|
_mosaicScanlineCounter = _state.MosaicEnabled ? _state.MosaicSize + 1 : 0;
|
||||||
if(!_skipRender) {
|
if(!_skipRender) {
|
||||||
if(!_interlacedFrame) {
|
if(!_interlacedFrame) {
|
||||||
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
|
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we're not skipping this frame, reset the high resolution flag
|
//If we're not skipping this frame, reset the high resolution/interlace flags
|
||||||
_useHighResOutput = false;
|
_useHighResOutput = IsDoubleWidth() || _state.ScreenInterlace;
|
||||||
_interlacedFrame = false;
|
_interlacedFrame = _state.ScreenInterlace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1335,7 +1336,15 @@ void Ppu::ApplyBrightness()
|
||||||
|
|
||||||
void Ppu::ConvertToHiRes()
|
void Ppu::ConvertToHiRes()
|
||||||
{
|
{
|
||||||
uint16_t scanline = _state.OverscanMode ? (_scanline - 1) : (_scanline + 6);
|
bool useHighResOutput = _useHighResOutput || IsDoubleWidth() || _state.ScreenInterlace;
|
||||||
|
if(!useHighResOutput || _useHighResOutput == useHighResOutput || _scanline >= _vblankStartScanline || _scanline == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert standard res picture to high resolution when the PPU starts drawing in high res mid frame
|
||||||
|
_useHighResOutput = useHighResOutput;
|
||||||
|
|
||||||
|
uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6);
|
||||||
|
|
||||||
if(_drawStartX > 0) {
|
if(_drawStartX > 0) {
|
||||||
for(int x = 0; x < _drawStartX; x++) {
|
for(int x = 0; x < _drawStartX; x++) {
|
||||||
|
@ -1357,14 +1366,7 @@ void Ppu::ConvertToHiRes()
|
||||||
void Ppu::ApplyHiResMode()
|
void Ppu::ApplyHiResMode()
|
||||||
{
|
{
|
||||||
//When overscan mode is off, center the 224-line picture in the center of the 239-line output buffer
|
//When overscan mode is off, center the 224-line picture in the center of the 239-line output buffer
|
||||||
uint16_t scanline = _state.OverscanMode ? (_scanline - 1) : (_scanline + 6);
|
uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6);
|
||||||
|
|
||||||
bool useHighResOutput = _useHighResOutput || IsDoubleWidth() || _state.ScreenInterlace;
|
|
||||||
if(_useHighResOutput != useHighResOutput) {
|
|
||||||
//Convert standard res picture to high resolution when the PPU starts drawing in high res mid frame
|
|
||||||
ConvertToHiRes();
|
|
||||||
_useHighResOutput = useHighResOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!_useHighResOutput) {
|
if(!_useHighResOutput) {
|
||||||
memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, (_drawEndX - _drawStartX + 1) << 1);
|
memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, (_drawEndX - _drawStartX + 1) << 1);
|
||||||
|
@ -1437,7 +1439,7 @@ void Ppu::SendFrame()
|
||||||
uint16_t width = _useHighResOutput ? 512 : 256;
|
uint16_t width = _useHighResOutput ? 512 : 256;
|
||||||
uint16_t height = _useHighResOutput ? 478 : 239;
|
uint16_t height = _useHighResOutput ? 478 : 239;
|
||||||
|
|
||||||
if(!_state.OverscanMode) {
|
if(!_overscanFrame) {
|
||||||
//Clear the top 7 and bottom 8 rows
|
//Clear the top 7 and bottom 8 rows
|
||||||
int top = (_useHighResOutput ? 14 : 7);
|
int top = (_useHighResOutput ? 14 : 7);
|
||||||
int bottom = (_useHighResOutput ? 16 : 8);
|
int bottom = (_useHighResOutput ? 16 : 8);
|
||||||
|
@ -1812,6 +1814,8 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
LogDebug("[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")");
|
LogDebug("[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")");
|
||||||
}
|
}
|
||||||
_state.BgMode = value & 0x07;
|
_state.BgMode = value & 0x07;
|
||||||
|
ConvertToHiRes();
|
||||||
|
|
||||||
_state.Mode1Bg3Priority = (value & 0x08) != 0;
|
_state.Mode1Bg3Priority = (value & 0x08) != 0;
|
||||||
|
|
||||||
_state.Layers[0].LargeTiles = (value & 0x10) != 0;
|
_state.Layers[0].LargeTiles = (value & 0x10) != 0;
|
||||||
|
@ -2092,6 +2096,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
memset(GetPreviousScreenBuffer(), 0, 512 * 478 * sizeof(uint16_t));
|
memset(GetPreviousScreenBuffer(), 0, 512 * 478 * sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ConvertToHiRes();
|
||||||
UpdateNmiScanline();
|
UpdateNmiScanline();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ private:
|
||||||
uint16_t *_currentBuffer = nullptr;
|
uint16_t *_currentBuffer = nullptr;
|
||||||
bool _useHighResOutput = false;
|
bool _useHighResOutput = false;
|
||||||
bool _interlacedFrame = false;
|
bool _interlacedFrame = false;
|
||||||
|
bool _overscanFrame = false;
|
||||||
|
|
||||||
uint8_t _mainScreenFlags[256] = {};
|
uint8_t _mainScreenFlags[256] = {};
|
||||||
uint16_t _mainScreenBuffer[256] = {};
|
uint16_t _mainScreenBuffer[256] = {};
|
||||||
|
|
Loading…
Add table
Reference in a new issue