PPU: Added option to emulate OAM row corruption when disabling rendering at certain points during rendering
This commit is contained in:
parent
bf6d161e1a
commit
59fddb7008
17 changed files with 1008 additions and 904 deletions
|
@ -23,6 +23,8 @@ enum EmulationFlags : uint64_t
|
|||
|
||||
PauseOnMovieEnd = 0x0100,
|
||||
|
||||
EnablePpuOamRowCorruption = 0x0200,
|
||||
|
||||
AllowBackgroundInput = 0x0400,
|
||||
ReduceSoundInBackground = 0x0800,
|
||||
MuteSoundInBackground = 0x1000,
|
||||
|
|
60
Core/PPU.cpp
60
Core/PPU.cpp
|
@ -30,6 +30,9 @@ PPU::PPU(shared_ptr<Console> console)
|
|||
0x09, 0x01, 0x34, 0x03, 0x00, 0x04, 0x00, 0x14, 0x08, 0x3A, 0x00, 0x02, 0x00, 0x20, 0x2C, 0x08 };
|
||||
memcpy(_paletteRAM, paletteRamBootValues, sizeof(_paletteRAM));
|
||||
|
||||
//This should (presumably) persist across resets
|
||||
memset(_corruptOamRow, 0, sizeof(_corruptOamRow));
|
||||
|
||||
_console->InitializeRam(_spriteRAM, 0x100);
|
||||
_console->InitializeRam(_secondarySpriteRAM, 0x20);
|
||||
|
||||
|
@ -546,6 +549,11 @@ void PPU::SetMaskRegister(uint8_t value)
|
|||
|
||||
if(_renderingEnabled != (_flags.BackgroundEnabled | _flags.SpritesEnabled)) {
|
||||
_needStateUpdate = true;
|
||||
|
||||
if(_renderingEnabled && _scanline < 240) {
|
||||
//Rendering was just disabled by the write
|
||||
SetOamCorruptionFlags();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMinimumDrawCycles();
|
||||
|
@ -1222,6 +1230,49 @@ void PPU::DebugUpdateFrameBuffer(bool toGrayscale)
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::SetOamCorruptionFlags()
|
||||
{
|
||||
if(!_settings->CheckFlag(EmulationFlags::EnablePpuOamRowCorruption)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Note: Still pending more research, but this currently matches a portion of the issues that have been observed
|
||||
//When rendering is disabled in some sections of the screen, either:
|
||||
// A- During Secondary OAM clear (first ~64 cycles)
|
||||
// B- During OAM tile fetching (cycle ~256 to cycle ~320)
|
||||
//then OAM memory gets corrupted the next time the PPU starts rendering again (usually at the start of the next frame)
|
||||
//This usually causes the first "row" of OAM (the first 8 bytes) to get copied over another, causing some sprites to be missing
|
||||
//and causing an extra set of the first 2 sprites to appear on the screen (not possible to see them except via any overflow they may cause)
|
||||
|
||||
if(_cycle >= 1 && _cycle < 65) {
|
||||
//Every 2 dots causes the corruption to shift down 1 OAM row (8 bytes)
|
||||
_corruptOamRow[(_cycle - 1) >> 1] = true;
|
||||
} else if(_cycle >= 257 && _cycle < 321) {
|
||||
//This section is in 8-dot segments.
|
||||
//The first 3 dot increment the corrupted row by 1, and then the last 5 dots corrupt the next row for 5 dots.
|
||||
uint8_t base = (_cycle - 257) >> 3;
|
||||
uint8_t offset = std::min<uint8_t>(3, (_cycle - 257) & 0x07);
|
||||
_corruptOamRow[base * 4 + offset] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ProcessOamCorruption()
|
||||
{
|
||||
if(!_settings->CheckFlag(EmulationFlags::EnablePpuOamRowCorruption)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Copy first OAM row over another row, as needed by corruption flags (can be over itself, which causes no actual harm)
|
||||
for(int i = 0; i < 32; i++) {
|
||||
if(_corruptOamRow[i]) {
|
||||
if(i > 0) {
|
||||
memcpy(_spriteRAM + i * 8, _spriteRAM, 8);
|
||||
}
|
||||
_corruptOamRow[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::Exec()
|
||||
{
|
||||
if(_cycle > 339) {
|
||||
|
@ -1233,6 +1284,10 @@ void PPU::Exec()
|
|||
//Force prerender scanline sprite fetches to load the dummy $FF tiles (fixes shaking in Ninja Gaiden 3 stage 1 after beating boss)
|
||||
_spriteCount = 0;
|
||||
|
||||
if(_renderingEnabled) {
|
||||
ProcessOamCorruption();
|
||||
}
|
||||
|
||||
UpdateMinimumDrawCycles();
|
||||
}
|
||||
|
||||
|
@ -1297,6 +1352,9 @@ void PPU::UpdateState()
|
|||
_prevRenderingEnabled = _renderingEnabled;
|
||||
if(_renderingEnabled != (_flags.BackgroundEnabled | _flags.SpritesEnabled)) {
|
||||
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
||||
if(_renderingEnabled) {
|
||||
ProcessOamCorruption();
|
||||
}
|
||||
}
|
||||
if(_prevRenderingEnabled != _renderingEnabled) {
|
||||
_needStateUpdate = true;
|
||||
|
@ -1436,6 +1494,8 @@ void PPU::StreamState(bool saving)
|
|||
_oamDecayCycles[i] = _console->GetCpu()->GetCycleCount();
|
||||
}
|
||||
|
||||
memset(_corruptOamRow, 0, sizeof(_corruptOamRow));
|
||||
|
||||
for(int i = 0; i < 257; i++) {
|
||||
_hasSprite[i] = true;
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
|
||||
uint64_t _oamDecayCycles[0x40];
|
||||
bool _enableOamDecay;
|
||||
bool _corruptOamRow[32];
|
||||
|
||||
void UpdateStatusFlag();
|
||||
|
||||
|
@ -140,6 +141,9 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
|
||||
__forceinline uint8_t ReadSpriteRam(uint8_t addr);
|
||||
__forceinline void WriteSpriteRam(uint8_t addr, uint8_t value);
|
||||
|
||||
void SetOamCorruptionFlags();
|
||||
void ProcessOamCorruption();
|
||||
|
||||
void UpdateMinimumDrawCycles();
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Mesen.GUI.Config
|
|||
public bool RandomizeCpuPpuAlignment = false;
|
||||
public bool EnablePpu2006ScrollGlitch = false;
|
||||
public bool EnablePpu2000ScrollGlitch = false;
|
||||
public bool EnablePpuOamRowCorruption = false;
|
||||
|
||||
public bool UseAlternativeMmc3Irq = false;
|
||||
|
||||
|
@ -65,6 +66,7 @@ namespace Mesen.GUI.Config
|
|||
InteropEmu.SetFlag(EmulationFlags.RandomizeCpuPpuAlignment, emulationInfo.RandomizeCpuPpuAlignment);
|
||||
InteropEmu.SetFlag(EmulationFlags.EnablePpu2000ScrollGlitch, emulationInfo.EnablePpu2000ScrollGlitch);
|
||||
InteropEmu.SetFlag(EmulationFlags.EnablePpu2006ScrollGlitch, emulationInfo.EnablePpu2006ScrollGlitch);
|
||||
InteropEmu.SetFlag(EmulationFlags.EnablePpuOamRowCorruption, emulationInfo.EnablePpuOamRowCorruption);
|
||||
|
||||
InteropEmu.SetPpuNmiConfig(emulationInfo.PpuExtraScanlinesBeforeNmi, emulationInfo.PpuExtraScanlinesAfterNmi);
|
||||
|
||||
|
|
|
@ -328,6 +328,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on/reset CPU/PPU alignment</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Enable PPU $2006 scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Enable PPU $2000/$2005/$2006 first-write scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Forçament</Control>
|
||||
<Control ID="grpOverclocking">Forçament de CPU</Control>
|
||||
|
|
|
@ -317,7 +317,7 @@
|
|||
<Control ID="lblMiscSettings">Miscellaneous Settings</Control>
|
||||
<Control ID="chkUseAlternativeMmc3Irq">Use alternative MMC3 IRQ behavior</Control>
|
||||
<Control ID="chkAllowInvalidInput">Allow invalid input (e.g Down + Up or Left + Right at the same time)</Control>
|
||||
<Control ID="chkEnableOamDecay">Enable OAM RAM decay</Control>
|
||||
<Control ID="chkEnableOamDecay">Enable PPU OAM decay</Control>
|
||||
<Control ID="chkDisablePpu2004Reads">Disable PPU $2004 reads (Famicom behavior)</Control>
|
||||
<Control ID="chkDisableOamAddrBug">Disable PPU OAMADDR bug emulation</Control>
|
||||
<Control ID="chkDisablePaletteRead">Disable PPU palette reads</Control>
|
||||
|
@ -327,7 +327,8 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on/reset CPU/PPU alignment</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Enable PPU $2006 scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Enable PPU $2000/$2005/$2006 first-write scroll glitch emulation</Control>
|
||||
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Default power on state for RAM:</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Overclocking</Control>
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Aleatorizar el encendido/reinicio de la alineación CPU/PPU</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Habilitar el fallo de emulación de scroll PPU $2006</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Habilitar el fallo de emulación de scroll de primera escritura PPU $2000/$2005/$2006</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Overclocking</Control>
|
||||
<Control ID="grpOverclocking">Overclocking de CPU</Control>
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Démarrer le jeu avec un alignement CPU/PPU aléatoire</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Simuler le bug de scrolling lors de l'écriture à $2006</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Simuler le bug de scrolling lors de l'écriture à $2000/$2005/$2006</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Simuler le bug de corruption de la rangée OAM</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">État initial de la mémoire au démarrage : </Control>
|
||||
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on/reset CPU/PPU alignment</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Enable PPU $2006 scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Enable PPU $2000/$2005/$2006 first-write scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Stato di accensione predefinito per la RAM:</Control>
|
||||
|
||||
|
|
|
@ -326,6 +326,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">ランダムなCPU/PPUアラインメントでゲームを起動する</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">$2006に書き込む時に発生するスクロールバグを再現する</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">$2000・$2005・$2006に書き込む時に発生するスクロールバグを再現する</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">OAM行のデータの汚染を再現する</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">起動時のメモリの状態 : </Control>
|
||||
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Aleatorizar o ligar/reiniciar do alinhamento da CPU/PPU</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Ativar emulação do erro gráfico PPU $2006 na rolagem</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Ativar emulação do erro gráfico PPU $2000/$2005/$2006 na rolagem na primeira escrita</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Estado inicial da RAM durante o início:</Control>
|
||||
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Рандомизировать включение/перезагрузку выравнивания CPU/PPU</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Включить PPU $2006 scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Включить PPU $2000/$2005/$2006 first-write scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Разгон</Control>
|
||||
<Control ID="grpOverclocking">Разгон CPU</Control>
|
||||
|
|
|
@ -327,6 +327,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on/reset CPU/PPU alignment</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">Enable PPU $2006 scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">Enable PPU $2000/$2005/$2006 first-write scroll glitch emulation</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Розгін</Control>
|
||||
<Control ID="grpOverclocking">Розгін CPU</Control>
|
||||
|
|
|
@ -353,6 +353,7 @@
|
|||
<Control ID="chkRandomizeCpuPpuAlignment">随机 CPU/PPU 开机对齐</Control>
|
||||
<Control ID="chkEnablePpu2006ScrollGlitch">模拟 PPU $2006 卷轴故障</Control>
|
||||
<Control ID="chkEnablePpu2000ScrollGlitch">模拟首次写入 PPU $2000/$2005/$2006 卷轴故障</Control>
|
||||
<Control ID="chkEnablePpuOamRowCorruption">Enable PPU OAM row corruption emulation</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">默认开机 RAM 状态:</Control>
|
||||
<Control ID="tpgOverclocking">超频</Control>
|
||||
|
|
1827
GUI.NET/Forms/Config/frmEmulationConfig.Designer.cs
generated
1827
GUI.NET/Forms/Config/frmEmulationConfig.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,7 @@ namespace Mesen.GUI.Forms.Config
|
|||
AddBinding("RandomizeCpuPpuAlignment", chkRandomizeCpuPpuAlignment);
|
||||
AddBinding("EnablePpu2006ScrollGlitch", chkEnablePpu2006ScrollGlitch);
|
||||
AddBinding("EnablePpu2000ScrollGlitch", chkEnablePpu2000ScrollGlitch);
|
||||
AddBinding("EnablePpuOamRowCorruption", chkEnablePpuOamRowCorruption);
|
||||
|
||||
AddBinding("PpuExtraScanlinesBeforeNmi", nudExtraScanlinesBeforeNmi);
|
||||
AddBinding("PpuExtraScanlinesAfterNmi", nudExtraScanlinesAfterNmi);
|
||||
|
|
|
@ -1619,6 +1619,8 @@ namespace Mesen.GUI
|
|||
|
||||
PauseOnMovieEnd = 0x0100,
|
||||
|
||||
EnablePpuOamRowCorruption = 0x0200,
|
||||
|
||||
AllowBackgroundInput = 0x0400,
|
||||
ReduceSoundInBackground = 0x0800,
|
||||
MuteSoundInBackground = 0x1000,
|
||||
|
|
Loading…
Add table
Reference in a new issue