Skip to content
Merged
2 changes: 1 addition & 1 deletion Core/BaseVideoFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
{
_frameLock.Acquire();
_overscan = _console->GetSettings()->GetOverscanDimensions();
_isOddFrame = frameNumber % 2;
_isOddFrame = frameNumber & 0x01;
UpdateBufferSize();
OnBeforeApplyFilter();
ApplyFilter(ppuOutputBuffer);
Expand Down
2 changes: 1 addition & 1 deletion Core/BaseVideoFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ class BaseVideoFilter

virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
virtual void OnBeforeApplyFilter();
bool IsOddFrame();

public:
BaseVideoFilter(shared_ptr<Console> console);
virtual ~BaseVideoFilter();

uint32_t* GetOutputBuffer();
bool IsOddFrame();
void SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
void TakeScreenshot(string romName, VideoFilterType filterType);
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr, bool rawScreenshot = false);
Expand Down
5 changes: 2 additions & 3 deletions Core/BisqwitNtscFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ BisqwitNtscFilter::BisqwitNtscFilter(shared_ptr<Console> console, int resDivider
} else {
outputBuffer += GetOverscan().GetScreenWidth() * 64 / _resDivider / _resDivider * (120 - GetOverscan().Top);
}

DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, (IsOddFrame() ? 8 : 0) + 327360);
DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, ((_console->GetModel() == NesModel::NTSC ? _console->GetStartingPhase() : 0) * 4) + 327360);

_workDone = true;
}
Expand All @@ -71,7 +70,7 @@ void BisqwitNtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)

_workDone = false;
_waitWork.Signal();
DecodeFrame(GetOverscan().Top, 120, ppuOutputBuffer, GetOutputBuffer(), (IsOddFrame() ? 8 : 0) + GetOverscan().Top*341*8);
DecodeFrame(GetOverscan().Top, 120, ppuOutputBuffer, GetOutputBuffer(), ((_console->GetModel() == NesModel::NTSC ? _console->GetStartingPhase() : 0) * 4) + GetOverscan().Top * 341 * 8);
while(!_workDone) {}
}

Expand Down
5 changes: 5 additions & 0 deletions Core/Console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,11 @@ uint32_t Console::GetFrameCount()
return _ppu ? _ppu->GetFrameCount() : 0;
}

uint8_t Console::GetStartingPhase()
{
return _ppu ? _ppu->GetStartingPhase() : 0;
}

NesModel Console::GetModel()
{
return _model;
Expand Down
2 changes: 2 additions & 0 deletions Core/Console.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ class Console : public std::enable_shared_from_this<Console>
VirtualFile GetPatchFile();
RomInfo GetRomInfo();
uint32_t GetFrameCount();
// https://forums.nesdev.org/viewtopic.php?p=30625#p30625
uint8_t GetStartingPhase();
NesModel GetModel();

uint32_t GetLagCounter();
Expand Down
28 changes: 18 additions & 10 deletions Core/NtscFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ NtscFilter::NtscFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
memset(_palette, 0, sizeof(_palette));
memset(&_ntscData, 0, sizeof(_ntscData));
_ntscSetup = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
_ntscBuffer = new uint32_t[NES_NTSC_OUT_WIDTH(256) * 240];
_ntscBuffer = new uint32_t[NES_NTSC_OUT_WIDTH(256) * 240]();
}

FrameInfo NtscFilter::GetFrameInfo()
Expand Down Expand Up @@ -55,14 +55,7 @@ void NtscFilter::OnBeforeApplyFilter()
}
}

if (_console->GetModel() == NesModel::NTSC) {
// BG color borders on NTSC machines
_ntsc_border = _console->GetPpu()->GetCurrentBgColor();
}
else {
// black borders on other machines
_ntsc_border = 15;
}
_ntscBorder = (_console->GetModel() == NesModel::NTSC);

PictureSettings pictureSettings = _console->GetSettings()->GetPictureSettings();
NtscFilterSettings ntscSettings = _console->GetSettings()->GetNtscFilterSettings();
Expand Down Expand Up @@ -132,7 +125,22 @@ void NtscFilter::OnBeforeApplyFilter()

void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
nes_ntsc_blit(&_ntscData, ppuOutputBuffer, _ntsc_border, PPU::ScreenWidth, IsOddFrame() ? 0 : 1, PPU::ScreenWidth, 240, _ntscBuffer, NES_NTSC_OUT_WIDTH(PPU::ScreenWidth)*4);
uint8_t phase = _console->GetModel() == NesModel::NTSC ? _console->GetStartingPhase() : 0;
for (int i = 0; i < 240; i++) {
nes_ntsc_blit(&_ntscData,
// input += in_row_width;
ppuOutputBuffer + PPU::ScreenWidth * i,
_ntscBorder ? _console->GetPpu()->GetCurrentBgColor() : 0x0F,
PPU::ScreenWidth,
phase,
PPU::ScreenWidth,
1,
// rgb_out = (char*) rgb_out + out_pitch;
reinterpret_cast<char*>(_ntscBuffer) + (NES_NTSC_OUT_WIDTH(PPU::ScreenWidth) * 4 * i),
NES_NTSC_OUT_WIDTH(PPU::ScreenWidth) * 4);

phase = (phase + 1) % 3;
}
GenerateArgbFrame(_ntscBuffer);
}

Expand Down
2 changes: 1 addition & 1 deletion Core/NtscFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class NtscFilter : public BaseVideoFilter
bool _useExternalPalette = true;
uint8_t _palette[512 * 3];
uint32_t* _ntscBuffer;
uint16_t _ntsc_border;
bool _ntscBorder = true;

void GenerateArgbFrame(uint32_t *outputBuffer);

Expand Down
40 changes: 25 additions & 15 deletions Core/PPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,37 +105,46 @@ void PPU::Reset()
memset(_oamDecayCycles, 0, sizeof(_oamDecayCycles));
_enableOamDecay = _settings->CheckFlag(EmulationFlags::EnableOamDecay);

_startingPhase = 0;

UpdateMinimumDrawCycles();
}

void PPU::SetNesModel(NesModel model)
{
_nesModel = model;

// https://www.nesdev.org/wiki/Cycle_reference_chart
switch(_nesModel) {
case NesModel::Auto:
//Should never be Auto
break;

case NesModel::NTSC:
_nmiScanline = 241;
_vblankEnd = 260;
_standardNmiScanline = 241;
_standardVblankEnd = 260;
// picture height + postrender blanking lines
_nmiScanline = 240 + 1;
// picture height + (postrender blanking lines - 1) + vblank length
_vblankEnd = 240 + 20;
_standardNmiScanline = _nmiScanline;
_standardVblankEnd = _vblankEnd;
_masterClockDivider = 4;
break;
case NesModel::PAL:
_nmiScanline = 241;
_vblankEnd = 310;
_standardNmiScanline = 241;
_standardVblankEnd = 310;
// (picture height + border line) + postrender blanking lines
_nmiScanline = 240 + 1;
// (picture height + border line) + (postrender blanking lines - 1) + vblank length + 50
_vblankEnd = 240 + 20 + 50;
_standardNmiScanline = _nmiScanline;
_standardVblankEnd = _vblankEnd;
_masterClockDivider = 5;
break;
case NesModel::Dendy:
_nmiScanline = 291;
_vblankEnd = 310;
_standardNmiScanline = 291;
_standardVblankEnd = 310;
// (picture height + border line) + postrender blanking lines + 50
_nmiScanline = 240 + 1 + 50;
// (picture height + border line) + (postrender blanking lines - 1) + 50 + vblank length
_vblankEnd = 240 + 50 + 20;
_standardNmiScanline = _nmiScanline;
_standardVblankEnd = _vblankEnd;
_masterClockDivider = 5;
break;
}
Expand Down Expand Up @@ -999,10 +1008,9 @@ void PPU::ProcessScanline()
LoadTileInfo();
}
} else if(_cycle == 337 || _cycle == 339) {
if(IsRenderingEnabled()) {
if (IsRenderingEnabled()) {
ReadVram(GetNameTableAddr());

if(_scanline == -1 && _cycle == 339 && (_frameCount & 0x01) && _nesModel == NesModel::NTSC && _settings->GetPpuModel() == PpuModel::Ppu2C02) {
if (_scanline == -1 && _cycle == 339 && (_frameCount & 0x01) && _nesModel == NesModel::NTSC && _settings->GetPpuModel() == PpuModel::Ppu2C02) {
//This behavior is NTSC-specific - PAL frames are always the same number of cycles
//"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340)
_cycle = 340;
Expand Down Expand Up @@ -1347,6 +1355,8 @@ void PPU::Exec()
if(_needStateUpdate) {
UpdateState();
}

_startingPhase = _cycle % 3;
}

void PPU::UpdateState()
Expand Down
8 changes: 8 additions & 0 deletions Core/PPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class PPU : public IMemoryHandler, public Snapshotable
bool _enableOamDecay;
bool _corruptOamRow[32];

// https://forums.nesdev.org/viewtopic.php?p=30625#p30625
uint8_t _startingPhase;

void UpdateStatusFlag();

void SetControlRegister(uint8_t value);
Expand Down Expand Up @@ -217,6 +220,11 @@ class PPU : public IMemoryHandler, public Snapshotable
return _frameCount;
}

uint8_t GetStartingPhase()
{
return _startingPhase;
}

uint32_t GetFrameCycle()
{
return ((_scanline + 1) * 341) + _cycle;
Expand Down