mirror of
https://github.com/libretro/Mesen-S.git
synced 2025-03-01 13:16:44 +00:00
Added support for overclocking (by adding extra scanlines before/after NMI)
This commit is contained in:
parent
46a02d4a9a
commit
c880c55d53
@ -78,7 +78,17 @@ uint32_t EmuSettings::GetInputConfigVersion()
|
||||
|
||||
void EmuSettings::SetEmulationConfig(EmulationConfig config)
|
||||
{
|
||||
bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0;
|
||||
bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0;
|
||||
_emulation = config;
|
||||
|
||||
if(prevOverclockEnabled != overclockEnabled) {
|
||||
if(overclockEnabled) {
|
||||
MessageManager::DisplayMessage("Overclock", "OverclockEnabled");
|
||||
} else {
|
||||
MessageManager::DisplayMessage("Overclock", "OverclockDisabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmulationConfig EmuSettings::GetEmulationConfig()
|
||||
|
@ -142,7 +142,7 @@ void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t
|
||||
int iMax = drawBackground ? 3 : 1;
|
||||
int jMin = drawBackground ? -2 : 0;
|
||||
int jMax = drawBackground ? 3 : 1;
|
||||
uint32_t y = evt.Scanline * 2;
|
||||
uint32_t y = std::min(evt.Scanline * 2, 262 * 2);
|
||||
uint32_t x = evt.Cycle * 2;
|
||||
|
||||
for(int i = iMin; i <= iMax; i++) {
|
||||
@ -171,7 +171,7 @@ void EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
|
||||
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256*239)) * sizeof(uint16_t));
|
||||
|
||||
_snapshot = _debugEvents;
|
||||
_snapshotScanline = scanline;
|
||||
_snapshotScanline = _ppu->GetRealScanline();
|
||||
if(options.ShowPreviousFrameEvents && scanline != 0) {
|
||||
for(DebugEventInfo &evt : _prevDebugEvents) {
|
||||
uint32_t evtKey = (evt.Scanline << 9) + evt.Cycle;
|
||||
|
@ -73,8 +73,8 @@ void InternalRegisters::ProcessIrqCounters()
|
||||
|
||||
bool irqLevel = (
|
||||
(_enableHorizontalIrq || _enableVerticalIrq) &&
|
||||
(!_enableHorizontalIrq || (_horizontalTimer <= 339 && (_ppu->GetCycle() == _horizontalTimer) && (_ppu->GetLastScanline() != _ppu->GetScanline() || _horizontalTimer < 339))) &&
|
||||
(!_enableVerticalIrq || _ppu->GetScanline() == _verticalTimer)
|
||||
(!_enableHorizontalIrq || (_horizontalTimer <= 339 && (_ppu->GetCycle() == _horizontalTimer) && (_ppu->GetLastScanline() != _ppu->GetRealScanline() || _horizontalTimer < 339))) &&
|
||||
(!_enableVerticalIrq || _ppu->GetRealScanline() == _verticalTimer)
|
||||
);
|
||||
|
||||
if(!_irqLevel && irqLevel) {
|
||||
@ -114,12 +114,12 @@ uint8_t InternalRegisters::Read(uint16_t addr)
|
||||
case 0x4212: {
|
||||
uint16_t hClock = _memoryManager->GetHClock();
|
||||
uint16_t scanline = _ppu->GetScanline();
|
||||
uint16_t vblankStart = _ppu->GetVblankStart();
|
||||
uint16_t nmiScanline = _ppu->GetNmiScanline();
|
||||
//TODO TIMING (set/clear timing)
|
||||
return (
|
||||
(scanline >= vblankStart ? 0x80 : 0) |
|
||||
(scanline >= nmiScanline ? 0x80 : 0) |
|
||||
((hClock >= 1*4 && hClock <= 274*4) ? 0 : 0x40) |
|
||||
((_enableAutoJoypadRead && scanline >= vblankStart && scanline <= vblankStart + 2) ? 0x01 : 0) | //Auto joypad read in progress
|
||||
((_enableAutoJoypadRead && scanline >= nmiScanline && scanline <= nmiScanline + 2) ? 0x01 : 0) | //Auto joypad read in progress
|
||||
(_memoryManager->GetOpenBus() & 0x3E)
|
||||
);
|
||||
}
|
||||
@ -153,7 +153,7 @@ void InternalRegisters::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0x4200:
|
||||
if((value & 0x30) == 0x20 && !_enableVerticalIrq && _ppu->GetScanline() == _verticalTimer) {
|
||||
if((value & 0x30) == 0x20 && !_enableVerticalIrq && _ppu->GetRealScanline() == _verticalTimer) {
|
||||
//When enabling vertical irqs, if the current scanline matches the target scanline, set the irq flag right away
|
||||
_console->GetCpu()->SetIrqSource(IrqSource::Ppu);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ std::unordered_map<string, string> MessageManager::_enResources = {
|
||||
{ "Patch", u8"Patch" },
|
||||
{ "Movies", u8"Movies" },
|
||||
{ "NetPlay", u8"Net Play" },
|
||||
{ "Overclock", u8"Overclock" },
|
||||
{ "Region", u8"Region" },
|
||||
{ "SaveStates", u8"Save States" },
|
||||
{ "ScreenshotSaved", u8"Screenshot Saved" },
|
||||
@ -51,6 +52,8 @@ std::unordered_map<string, string> MessageManager::_enResources = {
|
||||
{ "MovieRecordingTo", u8"Recording to: %1" },
|
||||
{ "MovieSaved", u8"Movie saved to file: %1" },
|
||||
{ "NetplayVersionMismatch", u8"%1 is not running the same version of Mesen and has been disconnected." },
|
||||
{ "OverclockEnabled", u8"Overclocking enabled." },
|
||||
{ "OverclockDisabled", u8"Overclocking disabled." },
|
||||
{ "PrgSizeWarning", u8"PRG size is smaller than 32kb" },
|
||||
{ "SaveStateEmpty", u8"Slot is empty." },
|
||||
{ "SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen." },
|
||||
@ -74,7 +77,7 @@ std::unordered_map<string, string> MessageManager::_enResources = {
|
||||
std::list<string> MessageManager::_log;
|
||||
SimpleLock MessageManager::_logLock;
|
||||
SimpleLock MessageManager::_messageLock;
|
||||
bool MessageManager::_osdEnabled = false;
|
||||
bool MessageManager::_osdEnabled = true;
|
||||
IMessageManager* MessageManager::_messageManager = nullptr;
|
||||
|
||||
void MessageManager::RegisterMessageManager(IMessageManager* messageManager)
|
||||
|
200
Core/Ppu.cpp
200
Core/Ppu.cpp
@ -51,10 +51,10 @@ void Ppu::PowerOn()
|
||||
{
|
||||
_skipRender = false;
|
||||
_regs = _console->GetInternalRegisters().get();
|
||||
_settings = _console->GetSettings().get();
|
||||
_spc = _console->GetSpc().get();
|
||||
_memoryManager = _console->GetMemoryManager().get();
|
||||
|
||||
_vblankStart = _overscanMode ? 240 : 225;
|
||||
|
||||
_currentBuffer = _outputBuffers[0];
|
||||
|
||||
_layerConfig[0] = {};
|
||||
@ -64,9 +64,9 @@ void Ppu::PowerOn()
|
||||
|
||||
_cgramAddress = 0;
|
||||
|
||||
_console->GetSettings()->InitializeRam(_vram, Ppu::VideoRamSize);
|
||||
_console->GetSettings()->InitializeRam(_cgram, Ppu::CgRamSize);
|
||||
_console->GetSettings()->InitializeRam(_oamRam, Ppu::SpriteRamSize);
|
||||
_settings->InitializeRam(_vram, Ppu::VideoRamSize);
|
||||
_settings->InitializeRam(_cgram, Ppu::CgRamSize);
|
||||
_settings->InitializeRam(_oamRam, Ppu::SpriteRamSize);
|
||||
|
||||
memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes));
|
||||
|
||||
@ -74,6 +74,8 @@ void Ppu::PowerOn()
|
||||
_vramIncrementValue = 1;
|
||||
_vramAddressRemapping = 0;
|
||||
_vramAddrIncrementOnSecondReg = false;
|
||||
|
||||
UpdateNmiScanline();
|
||||
}
|
||||
|
||||
void Ppu::Reset()
|
||||
@ -100,9 +102,14 @@ uint16_t Ppu::GetCycle()
|
||||
return (hClock - ((hClock > 1292) << 1) - ((hClock > 1310) << 1)) >> 2;
|
||||
}
|
||||
|
||||
uint16_t Ppu::GetNmiScanline()
|
||||
{
|
||||
return _nmiScanline;
|
||||
}
|
||||
|
||||
uint16_t Ppu::GetVblankStart()
|
||||
{
|
||||
return _vblankStart;
|
||||
return _vblankStartScanline;
|
||||
}
|
||||
|
||||
PpuState Ppu::GetState()
|
||||
@ -389,70 +396,71 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
|
||||
{
|
||||
if(hClock >= 1364 || (hClock == 1360 && _scanline == 240 && _oddFrame && !_screenInterlace)) {
|
||||
//"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles."
|
||||
if(_scanline < _vblankStart) {
|
||||
if(_scanline < _vblankStartScanline) {
|
||||
RenderScanline();
|
||||
|
||||
if(_mosaicScanlineCounter) {
|
||||
_mosaicScanlineCounter--;
|
||||
if(_mosaicEnabled && !_mosaicScanlineCounter) {
|
||||
_mosaicScanlineCounter = _mosaicSize;
|
||||
}
|
||||
}
|
||||
|
||||
_drawStartX = 0;
|
||||
_drawEndX = 0;
|
||||
_fetchBgStart = 0;
|
||||
_fetchBgEnd = 0;
|
||||
_fetchSpriteStart = 0;
|
||||
_fetchSpriteEnd = 0;
|
||||
_spriteEvalStart = 0;
|
||||
_spriteEvalEnd = 0;
|
||||
_spriteFetchingDone = false;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
_layerData[i].HasPriorityTiles = false;
|
||||
}
|
||||
|
||||
memset(_hasSpritePriority, 0, sizeof(_hasSpritePriority));
|
||||
memcpy(_spritePriority, _spritePriorityCopy, sizeof(_spritePriority));
|
||||
for(int i = 0; i < 255; i++) {
|
||||
if(_spritePriority[i] < 4) {
|
||||
_hasSpritePriority[_spritePriority[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_spritePalette, _spritePaletteCopy, sizeof(_spritePalette));
|
||||
memcpy(_spriteColors, _spriteColorsCopy, sizeof(_spriteColors));
|
||||
|
||||
memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes));
|
||||
|
||||
_pixelsDrawn = 0;
|
||||
_subPixelsDrawn = 0;
|
||||
memset(_rowPixelFlags, 0, sizeof(_rowPixelFlags));
|
||||
memset(_subScreenFilled, 0, sizeof(_subScreenFilled));
|
||||
}
|
||||
|
||||
_scanline++;
|
||||
if(_mosaicScanlineCounter) {
|
||||
_mosaicScanlineCounter--;
|
||||
if(_mosaicEnabled && !_mosaicScanlineCounter) {
|
||||
_mosaicScanlineCounter = _mosaicSize;
|
||||
}
|
||||
}
|
||||
|
||||
_drawStartX = 0;
|
||||
_drawEndX = 0;
|
||||
_fetchBgStart = 0;
|
||||
_fetchBgEnd = 0;
|
||||
_fetchSpriteStart = 0;
|
||||
_fetchSpriteEnd = 0;
|
||||
_spriteEvalStart = 0;
|
||||
_spriteEvalEnd = 0;
|
||||
_spriteFetchingDone = false;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
_layerData[i].HasPriorityTiles = false;
|
||||
}
|
||||
|
||||
memset(_hasSpritePriority, 0, sizeof(_hasSpritePriority));
|
||||
memcpy(_spritePriority, _spritePriorityCopy, sizeof(_spritePriority));
|
||||
for(int i = 0; i < 255; i++) {
|
||||
if(_spritePriority[i] < 4) {
|
||||
_hasSpritePriority[_spritePriority[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_spritePalette, _spritePaletteCopy, sizeof(_spritePalette));
|
||||
memcpy(_spriteColors, _spriteColorsCopy, sizeof(_spriteColors));
|
||||
|
||||
memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes));
|
||||
|
||||
_pixelsDrawn = 0;
|
||||
_subPixelsDrawn = 0;
|
||||
memset(_rowPixelFlags, 0, sizeof(_rowPixelFlags));
|
||||
memset(_subScreenFilled, 0, sizeof(_subScreenFilled));
|
||||
|
||||
if(_scanline == _vblankStart) {
|
||||
if(_scanline == _nmiScanline) {
|
||||
//Reset OAM address at the start of vblank?
|
||||
if(!_forcedVblank) {
|
||||
//TODO, the timing of this may be slightly off? should happen at H=10 based on anomie's docs
|
||||
_internalOamAddress = (_oamRamAddress << 1);
|
||||
}
|
||||
|
||||
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
|
||||
VideoConfig cfg = _settings->GetVideoConfig();
|
||||
_configVisibleLayers = (cfg.HideBgLayer0 ? 0 : 1) | (cfg.HideBgLayer1 ? 0 : 2) | (cfg.HideBgLayer2 ? 0 : 4) | (cfg.HideBgLayer3 ? 0 : 8) | (cfg.HideSprites ? 0 : 16);
|
||||
|
||||
_console->ProcessEvent(EventType::EndFrame);
|
||||
|
||||
_frameCount++;
|
||||
_console->GetSpc()->ProcessEndFrame();
|
||||
_spc->ProcessEndFrame();
|
||||
_regs->SetNmiFlag(true);
|
||||
SendFrame();
|
||||
|
||||
if(_regs->IsNmiEnabled()) {
|
||||
_console->GetCpu()->SetNmiFlag();
|
||||
}
|
||||
} else if(_scanline >= GetLastScanline() + 1) {
|
||||
} else if(_scanline >= _vblankEndScanline + 1) {
|
||||
//"Frames are 262 scanlines in non-interlace mode, while in interlace mode frames with $213f.7=0 are 263 scanlines"
|
||||
_oddFrame ^= 1;
|
||||
_regs->SetNmiFlag(false);
|
||||
@ -462,10 +470,10 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
|
||||
_console->ProcessEvent(EventType::StartFrame);
|
||||
|
||||
_skipRender = (
|
||||
!_console->GetSettings()->GetVideoConfig().DisableFrameSkipping &&
|
||||
!_settings->GetVideoConfig().DisableFrameSkipping &&
|
||||
!_console->GetRewindManager()->IsRewinding() &&
|
||||
!_console->GetVideoRenderer()->IsRecording() &&
|
||||
(_console->GetSettings()->GetEmulationSpeed() == 0 || _console->GetSettings()->GetEmulationSpeed() > 150) &&
|
||||
(_settings->GetEmulationSpeed() == 0 || _settings->GetEmulationSpeed() > 150) &&
|
||||
_frameSkipTimer.GetElapsedMS() < 10
|
||||
);
|
||||
if(!_skipRender) {
|
||||
@ -474,27 +482,87 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
|
||||
}
|
||||
|
||||
_mosaicScanlineCounter = _mosaicEnabled ? _mosaicSize + 1 : 0;
|
||||
|
||||
//Update overclock timings once per frame
|
||||
UpdateNmiScanline();
|
||||
|
||||
//Ensure the SPC is re-enabled for the next frame
|
||||
_spc->SetSpcState(true);
|
||||
}
|
||||
|
||||
UpdateSpcState();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t Ppu::GetLastScanline()
|
||||
void Ppu::UpdateSpcState()
|
||||
{
|
||||
//When using overclocking, turn off the SPC during the extra scanlines
|
||||
if(_overclockEnabled && _scanline > _vblankStartScanline) {
|
||||
EmulationConfig cfg = _settings->GetEmulationConfig();
|
||||
if(_scanline > _adjustedVblankEndScanline) {
|
||||
//Disable APU for extra lines after NMI
|
||||
_spc->SetSpcState(false);
|
||||
} else if(_scanline >= _vblankStartScanline && _scanline < _nmiScanline) {
|
||||
//Disable APU for extra lines before NMI
|
||||
_spc->SetSpcState(false);
|
||||
} else {
|
||||
_spc->SetSpcState(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ppu::UpdateNmiScanline()
|
||||
{
|
||||
EmulationConfig cfg = _settings->GetEmulationConfig();
|
||||
if(_console->GetRegion() == ConsoleRegion::Ntsc) {
|
||||
if(!_screenInterlace || _oddFrame) {
|
||||
return 261;
|
||||
_baseVblankEndScanline = 261;
|
||||
} else {
|
||||
return 262;
|
||||
_baseVblankEndScanline = 262;
|
||||
}
|
||||
} else {
|
||||
if(!_screenInterlace || _oddFrame) {
|
||||
return 311;
|
||||
_baseVblankEndScanline = 311;
|
||||
} else {
|
||||
return 312;
|
||||
_baseVblankEndScanline = 312;
|
||||
}
|
||||
}
|
||||
|
||||
_overclockEnabled = cfg.PpuExtraScanlinesBeforeNmi > 0 || cfg.PpuExtraScanlinesAfterNmi > 0;
|
||||
|
||||
_adjustedVblankEndScanline = _baseVblankEndScanline + cfg.PpuExtraScanlinesBeforeNmi;
|
||||
_vblankEndScanline = _baseVblankEndScanline + cfg.PpuExtraScanlinesAfterNmi + cfg.PpuExtraScanlinesBeforeNmi;
|
||||
_vblankStartScanline = _overscanMode ? 240 : 225;
|
||||
_nmiScanline = _vblankStartScanline + cfg.PpuExtraScanlinesBeforeNmi;
|
||||
}
|
||||
|
||||
uint16_t Ppu::GetRealScanline()
|
||||
{
|
||||
if(!_overclockEnabled) {
|
||||
return _scanline;
|
||||
}
|
||||
|
||||
if(_scanline > _vblankStartScanline && _scanline <= _nmiScanline) {
|
||||
//Pretend to be just before vblank until extra scanlines are over
|
||||
return _vblankStartScanline - 1;
|
||||
} else if(_scanline > _nmiScanline) {
|
||||
if(_scanline > _adjustedVblankEndScanline) {
|
||||
//Pretend to be at the end of vblank until extra scanlines are over
|
||||
return _baseVblankEndScanline;
|
||||
} else {
|
||||
//Number the regular scanlines as they would normally be
|
||||
return _scanline - _nmiScanline + _vblankStartScanline;
|
||||
}
|
||||
}
|
||||
|
||||
return _scanline;
|
||||
}
|
||||
|
||||
uint16_t Ppu::GetLastScanline()
|
||||
{
|
||||
return _baseVblankEndScanline;
|
||||
}
|
||||
|
||||
void Ppu::EvaluateNextLineSprites()
|
||||
@ -1499,7 +1567,7 @@ bool Ppu::IsDoubleWidth()
|
||||
void Ppu::LatchLocationValues()
|
||||
{
|
||||
_horizontalLocation = GetCycle();
|
||||
_verticalLocation = _scanline;
|
||||
_verticalLocation = GetRealScanline();
|
||||
_locationLatched = true;
|
||||
}
|
||||
|
||||
@ -1511,7 +1579,7 @@ void Ppu::UpdateOamAddress()
|
||||
|
||||
uint16_t Ppu::GetOamAddress()
|
||||
{
|
||||
if(_forcedVblank || _scanline >= _vblankStart) {
|
||||
if(_forcedVblank || _scanline >= _vblankStartScanline) {
|
||||
return _internalOamAddress;
|
||||
} else {
|
||||
if(_memoryManager->GetHClock() <= 255 * 4) {
|
||||
@ -1542,7 +1610,7 @@ uint16_t Ppu::GetVramAddress()
|
||||
|
||||
uint8_t Ppu::Read(uint16_t addr)
|
||||
{
|
||||
if(_scanline < _vblankStart) {
|
||||
if(_scanline < _vblankStartScanline) {
|
||||
RenderScanline();
|
||||
}
|
||||
|
||||
@ -1704,13 +1772,13 @@ uint8_t Ppu::Read(uint16_t addr)
|
||||
|
||||
void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
{
|
||||
if(_scanline < _vblankStart) {
|
||||
if(_scanline < _vblankStartScanline) {
|
||||
RenderScanline();
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x2100:
|
||||
if(_forcedVblank && _scanline == _vblankStart) {
|
||||
if(_forcedVblank && _scanline == _nmiScanline) {
|
||||
//"writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur."
|
||||
UpdateOamAddress();
|
||||
}
|
||||
@ -1753,7 +1821,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
if(!_forcedVblank && _scanline < _vblankStart) {
|
||||
if(!_forcedVblank && _scanline < _nmiScanline) {
|
||||
//During rendering the high table is also written to when writing to OAM
|
||||
oamAddr = 0x200 | ((oamAddr & 0x1F0) >> 4);
|
||||
}
|
||||
@ -1864,7 +1932,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
|
||||
case 0x2118:
|
||||
//VMDATAL - VRAM Data Write low byte
|
||||
if(_scanline >= _vblankStart || _forcedVblank) {
|
||||
if(_scanline >= _nmiScanline || _forcedVblank) {
|
||||
//Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed)
|
||||
_console->ProcessPpuWrite(GetVramAddress() << 1, value, SnesMemoryType::VideoRam);
|
||||
_vram[GetVramAddress()] = value | (_vram[GetVramAddress()] & 0xFF00);
|
||||
@ -1878,7 +1946,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
|
||||
case 0x2119:
|
||||
//VMDATAH - VRAM Data Write high byte
|
||||
if(_scanline >= _vblankStart || _forcedVblank) {
|
||||
if(_scanline >= _nmiScanline || _forcedVblank) {
|
||||
//Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed)
|
||||
_console->ProcessPpuWrite((GetVramAddress() << 1) + 1, value, SnesMemoryType::VideoRam);
|
||||
_vram[GetVramAddress()] = (value << 8) | (_vram[GetVramAddress()] & 0xFF);
|
||||
@ -2044,9 +2112,9 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
_mode7.ExtBgEnabled = (value & 0x40) != 0;
|
||||
_hiResMode = (value & 0x08) != 0;
|
||||
_overscanMode = (value & 0x04) != 0;
|
||||
_vblankStart = _overscanMode ? 240 : 225;
|
||||
_objInterlace = (value & 0x02) != 0;
|
||||
_screenInterlace = (value & 0x01) != 0;
|
||||
UpdateNmiScanline();
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2072,8 +2140,8 @@ void Ppu::Serialize(Serializer &s)
|
||||
_windowMaskSub[0], _windowMaskSub[1], _windowMaskSub[2], _windowMaskSub[3], _windowMaskSub[4],
|
||||
_mode7.CenterX, _mode7.CenterY, _mode7.ExtBgEnabled, _mode7.FillWithTile0, _mode7.HorizontalMirroring,
|
||||
_mode7.HScroll, _mode7.LargeMap, _mode7.Matrix[0], _mode7.Matrix[1], _mode7.Matrix[2], _mode7.Matrix[3],
|
||||
_mode7.ValueLatch, _mode7.VerticalMirroring, _mode7.VScroll, unused_oamRenderAddress, _oddFrame, _vblankStart,
|
||||
_cgramAddressLatch, _cgramWriteBuffer
|
||||
_mode7.ValueLatch, _mode7.VerticalMirroring, _mode7.VScroll, unused_oamRenderAddress, _oddFrame, _vblankStartScanline,
|
||||
_cgramAddressLatch, _cgramWriteBuffer, _nmiScanline, _vblankEndScanline, _adjustedVblankEndScanline, _baseVblankEndScanline
|
||||
);
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
|
17
Core/Ppu.h
17
Core/Ppu.h
@ -7,6 +7,8 @@
|
||||
class Console;
|
||||
class InternalRegisters;
|
||||
class MemoryManager;
|
||||
class Spc;
|
||||
class EmuSettings;
|
||||
|
||||
class Ppu : public ISerializable
|
||||
{
|
||||
@ -22,6 +24,8 @@ private:
|
||||
Console* _console;
|
||||
InternalRegisters* _regs;
|
||||
MemoryManager* _memoryManager;
|
||||
Spc* _spc;
|
||||
EmuSettings* _settings;
|
||||
|
||||
//Temporary data used for the tilemap/tile fetching
|
||||
LayerData _layerData[4] = {};
|
||||
@ -49,7 +53,14 @@ private:
|
||||
|
||||
uint16_t _scanline = 0;
|
||||
uint32_t _frameCount = 0;
|
||||
uint16_t _vblankStart;
|
||||
|
||||
uint16_t _vblankStartScanline;
|
||||
uint16_t _vblankEndScanline;
|
||||
uint16_t _baseVblankEndScanline;
|
||||
uint16_t _adjustedVblankEndScanline;
|
||||
uint16_t _nmiScanline;
|
||||
bool _overclockEnabled;
|
||||
|
||||
uint8_t _oddFrame = 0;
|
||||
|
||||
uint16_t _drawStartX = 0;
|
||||
@ -247,14 +258,18 @@ public:
|
||||
void RenderScanline();
|
||||
|
||||
uint32_t GetFrameCount();
|
||||
uint16_t GetRealScanline();
|
||||
uint16_t GetScanline();
|
||||
uint16_t GetCycle();
|
||||
uint16_t GetNmiScanline();
|
||||
uint16_t GetVblankStart();
|
||||
|
||||
PpuState GetState();
|
||||
void GetState(PpuState &state, bool returnPartialState);
|
||||
|
||||
bool ProcessEndOfScanline(uint16_t hClock);
|
||||
void UpdateSpcState();
|
||||
void UpdateNmiScanline();
|
||||
uint16_t GetLastScanline();
|
||||
|
||||
bool IsHighResOutput();
|
||||
|
18
Core/Spc.cpp
18
Core/Spc.cpp
@ -37,6 +37,7 @@ Spc::Spc(Console* console)
|
||||
_tmp3 = 0;
|
||||
_operandA = 0;
|
||||
_operandB = 0;
|
||||
_enabled = true;
|
||||
|
||||
_clockRatio = (double)2048000 / _console->GetMasterClockRate();
|
||||
}
|
||||
@ -74,6 +75,21 @@ void Spc::Reset()
|
||||
_dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1);
|
||||
}
|
||||
|
||||
void Spc::SetSpcState(bool enabled)
|
||||
{
|
||||
//Used by overclocking logic to disable SPC during the extra scanlines added to the PPU
|
||||
if(_enabled != enabled) {
|
||||
if(enabled) {
|
||||
//When re-enabling, adjust the cycle counter to prevent running extra cycles
|
||||
_state.Cycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
|
||||
} else {
|
||||
//Catch up SPC before disabling it
|
||||
Run();
|
||||
}
|
||||
_enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc::Idle()
|
||||
{
|
||||
IncCycleCount(-1);
|
||||
@ -283,7 +299,7 @@ void Spc::CpuWriteRegister(uint32_t addr, uint8_t value)
|
||||
|
||||
void Spc::Run()
|
||||
{
|
||||
if(_state.StopState != CpuStopState::Running) {
|
||||
if(!_enabled || _state.StopState != CpuStopState::Running) {
|
||||
//STOP or SLEEP were executed - execution is stopped forever.
|
||||
return;
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ private:
|
||||
SpcOpStep _opStep;
|
||||
uint8_t _opSubStep;
|
||||
|
||||
bool _enabled;
|
||||
|
||||
SpcState _state;
|
||||
uint8_t* _ram;
|
||||
uint8_t _spcBios[64] {
|
||||
@ -280,6 +282,8 @@ public:
|
||||
Spc(Console* console);
|
||||
virtual ~Spc();
|
||||
|
||||
void SetSpcState(bool enabled);
|
||||
|
||||
void Run();
|
||||
void Reset();
|
||||
|
||||
|
@ -287,7 +287,7 @@
|
||||
|
||||
<Control ID="tpgOverclocking">Overclocking</Control>
|
||||
<Control ID="grpOverclocking">Overclocking</Control>
|
||||
<Control ID="lblOverclockHint">Overclocking can help reduce or remove slowdowns in games (but it can also cause issues). The most compatible way to overclock is by increasing the "Scanline before NMI" value by a few hundred lines (e.g 400+)</Control>
|
||||
<Control ID="lblOverclockHint">Overclocking can help reduce or remove slowdowns in games (but it can also cause issues). To overclock, try setting the "before NMI" value to a few hundred lines (e.g 300+). If this breaks the game, try lowering the value or using the "after NMI" field instead.</Control>
|
||||
<Control ID="lblClockRate">Clock Rate Multiplier:</Control>
|
||||
<Control ID="lblClockRatePercent">% (Default: 100%)</Control>
|
||||
|
||||
|
209
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
209
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
@ -27,6 +27,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmEmulationConfig));
|
||||
this.tabMain = new System.Windows.Forms.TabControl();
|
||||
this.tpgGeneral = new System.Windows.Forms.TabPage();
|
||||
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
|
||||
@ -48,6 +49,16 @@
|
||||
this.flowLayoutPanel8 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblRamPowerOnState = new System.Windows.Forms.Label();
|
||||
this.cboRamPowerOnState = new System.Windows.Forms.ComboBox();
|
||||
this.tpgOverclocking = new System.Windows.Forms.TabPage();
|
||||
this.picHint = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblOverclockHint = new System.Windows.Forms.Label();
|
||||
this.grpPpuTiming = new System.Windows.Forms.GroupBox();
|
||||
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.nudExtraScanlinesAfterNmi = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
this.nudExtraScanlinesBeforeNmi = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
this.lblExtraScanlinesBeforeNmi = new System.Windows.Forms.Label();
|
||||
this.lblExtraScanlinesAfterNmi = new System.Windows.Forms.Label();
|
||||
this.tabMain.SuspendLayout();
|
||||
this.tpgGeneral.SuspendLayout();
|
||||
this.tableLayoutPanel4.SuspendLayout();
|
||||
@ -56,6 +67,11 @@
|
||||
this.flowLayoutPanel10.SuspendLayout();
|
||||
this.tpgAdvanced.SuspendLayout();
|
||||
this.flowLayoutPanel8.SuspendLayout();
|
||||
this.tpgOverclocking.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picHint)).BeginInit();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.grpPpuTiming.SuspendLayout();
|
||||
this.tableLayoutPanel5.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// baseConfigPanel
|
||||
@ -68,11 +84,12 @@
|
||||
//
|
||||
this.tabMain.Controls.Add(this.tpgGeneral);
|
||||
this.tabMain.Controls.Add(this.tpgAdvanced);
|
||||
this.tabMain.Controls.Add(this.tpgOverclocking);
|
||||
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabMain.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabMain.Name = "tabMain";
|
||||
this.tabMain.SelectedIndex = 0;
|
||||
this.tabMain.Size = new System.Drawing.Size(414, 319);
|
||||
this.tabMain.Size = new System.Drawing.Size(414, 290);
|
||||
this.tabMain.TabIndex = 2;
|
||||
//
|
||||
// tpgGeneral
|
||||
@ -323,7 +340,7 @@
|
||||
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgAdvanced.Name = "tpgAdvanced";
|
||||
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgAdvanced.Size = new System.Drawing.Size(406, 293);
|
||||
this.tpgAdvanced.Size = new System.Drawing.Size(406, 264);
|
||||
this.tpgAdvanced.TabIndex = 3;
|
||||
this.tpgAdvanced.Text = "Advanced";
|
||||
this.tpgAdvanced.UseVisualStyleBackColor = true;
|
||||
@ -336,7 +353,7 @@
|
||||
this.flowLayoutPanel8.Location = new System.Drawing.Point(3, 3);
|
||||
this.flowLayoutPanel8.Margin = new System.Windows.Forms.Padding(7, 0, 0, 0);
|
||||
this.flowLayoutPanel8.Name = "flowLayoutPanel8";
|
||||
this.flowLayoutPanel8.Size = new System.Drawing.Size(400, 287);
|
||||
this.flowLayoutPanel8.Size = new System.Drawing.Size(400, 258);
|
||||
this.flowLayoutPanel8.TabIndex = 4;
|
||||
//
|
||||
// lblRamPowerOnState
|
||||
@ -358,6 +375,173 @@
|
||||
this.cboRamPowerOnState.Size = new System.Drawing.Size(176, 21);
|
||||
this.cboRamPowerOnState.TabIndex = 1;
|
||||
//
|
||||
// tpgOverclocking
|
||||
//
|
||||
this.tpgOverclocking.Controls.Add(this.picHint);
|
||||
this.tpgOverclocking.Controls.Add(this.tableLayoutPanel3);
|
||||
this.tpgOverclocking.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgOverclocking.Name = "tpgOverclocking";
|
||||
this.tpgOverclocking.Size = new System.Drawing.Size(406, 264);
|
||||
this.tpgOverclocking.TabIndex = 4;
|
||||
this.tpgOverclocking.Text = "Overclocking";
|
||||
this.tpgOverclocking.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// picHint
|
||||
//
|
||||
this.picHint.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.picHint.BackgroundImage = global::Mesen.GUI.Properties.Resources.Help;
|
||||
this.picHint.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
|
||||
this.picHint.Location = new System.Drawing.Point(8, 20);
|
||||
this.picHint.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
|
||||
this.picHint.Name = "picHint";
|
||||
this.picHint.Size = new System.Drawing.Size(16, 16);
|
||||
this.picHint.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
|
||||
this.picHint.TabIndex = 8;
|
||||
this.picHint.TabStop = false;
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 1;
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblOverclockHint, 0, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.grpPpuTiming, 0, 1);
|
||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 3;
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(406, 264);
|
||||
this.tableLayoutPanel3.TabIndex = 1;
|
||||
//
|
||||
// lblOverclockHint
|
||||
//
|
||||
this.lblOverclockHint.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.lblOverclockHint.Location = new System.Drawing.Point(3, 0);
|
||||
this.lblOverclockHint.Name = "lblOverclockHint";
|
||||
this.lblOverclockHint.Padding = new System.Windows.Forms.Padding(25, 0, 0, 0);
|
||||
this.lblOverclockHint.Size = new System.Drawing.Size(400, 54);
|
||||
this.lblOverclockHint.TabIndex = 1;
|
||||
this.lblOverclockHint.Text = resources.GetString("lblOverclockHint.Text");
|
||||
//
|
||||
// grpPpuTiming
|
||||
//
|
||||
this.grpPpuTiming.Controls.Add(this.tableLayoutPanel5);
|
||||
this.grpPpuTiming.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpPpuTiming.Location = new System.Drawing.Point(3, 57);
|
||||
this.grpPpuTiming.Name = "grpPpuTiming";
|
||||
this.grpPpuTiming.Size = new System.Drawing.Size(400, 71);
|
||||
this.grpPpuTiming.TabIndex = 7;
|
||||
this.grpPpuTiming.TabStop = false;
|
||||
this.grpPpuTiming.Text = "PPU Vertical Blank Configuration";
|
||||
//
|
||||
// tableLayoutPanel5
|
||||
//
|
||||
this.tableLayoutPanel5.ColumnCount = 2;
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel5.Controls.Add(this.nudExtraScanlinesAfterNmi, 1, 1);
|
||||
this.tableLayoutPanel5.Controls.Add(this.nudExtraScanlinesBeforeNmi, 1, 0);
|
||||
this.tableLayoutPanel5.Controls.Add(this.lblExtraScanlinesBeforeNmi, 0, 0);
|
||||
this.tableLayoutPanel5.Controls.Add(this.lblExtraScanlinesAfterNmi, 0, 1);
|
||||
this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 16);
|
||||
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
|
||||
this.tableLayoutPanel5.RowCount = 3;
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel5.Size = new System.Drawing.Size(394, 52);
|
||||
this.tableLayoutPanel5.TabIndex = 0;
|
||||
//
|
||||
// nudExtraScanlinesAfterNmi
|
||||
//
|
||||
this.nudExtraScanlinesAfterNmi.DecimalPlaces = 0;
|
||||
this.nudExtraScanlinesAfterNmi.Increment = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesAfterNmi.Location = new System.Drawing.Point(165, 30);
|
||||
this.nudExtraScanlinesAfterNmi.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
|
||||
this.nudExtraScanlinesAfterNmi.Maximum = new decimal(new int[] {
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesAfterNmi.MaximumSize = new System.Drawing.Size(10000, 20);
|
||||
this.nudExtraScanlinesAfterNmi.Minimum = new decimal(new int[] {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesAfterNmi.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.nudExtraScanlinesAfterNmi.Name = "nudExtraScanlinesAfterNmi";
|
||||
this.nudExtraScanlinesAfterNmi.Size = new System.Drawing.Size(46, 21);
|
||||
this.nudExtraScanlinesAfterNmi.TabIndex = 3;
|
||||
this.nudExtraScanlinesAfterNmi.Value = new decimal(new int[] {
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// nudExtraScanlinesBeforeNmi
|
||||
//
|
||||
this.nudExtraScanlinesBeforeNmi.DecimalPlaces = 0;
|
||||
this.nudExtraScanlinesBeforeNmi.Increment = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesBeforeNmi.Location = new System.Drawing.Point(165, 3);
|
||||
this.nudExtraScanlinesBeforeNmi.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
|
||||
this.nudExtraScanlinesBeforeNmi.Maximum = new decimal(new int[] {
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesBeforeNmi.MaximumSize = new System.Drawing.Size(10000, 20);
|
||||
this.nudExtraScanlinesBeforeNmi.Minimum = new decimal(new int[] {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudExtraScanlinesBeforeNmi.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.nudExtraScanlinesBeforeNmi.Name = "nudExtraScanlinesBeforeNmi";
|
||||
this.nudExtraScanlinesBeforeNmi.Size = new System.Drawing.Size(46, 21);
|
||||
this.nudExtraScanlinesBeforeNmi.TabIndex = 2;
|
||||
this.nudExtraScanlinesBeforeNmi.Value = new decimal(new int[] {
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// lblExtraScanlinesBeforeNmi
|
||||
//
|
||||
this.lblExtraScanlinesBeforeNmi.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblExtraScanlinesBeforeNmi.AutoSize = true;
|
||||
this.lblExtraScanlinesBeforeNmi.Location = new System.Drawing.Point(3, 7);
|
||||
this.lblExtraScanlinesBeforeNmi.Name = "lblExtraScanlinesBeforeNmi";
|
||||
this.lblExtraScanlinesBeforeNmi.Size = new System.Drawing.Size(159, 13);
|
||||
this.lblExtraScanlinesBeforeNmi.TabIndex = 0;
|
||||
this.lblExtraScanlinesBeforeNmi.Text = "Additional scanlines before NMI:";
|
||||
//
|
||||
// lblExtraScanlinesAfterNmi
|
||||
//
|
||||
this.lblExtraScanlinesAfterNmi.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblExtraScanlinesAfterNmi.AutoSize = true;
|
||||
this.lblExtraScanlinesAfterNmi.Location = new System.Drawing.Point(3, 34);
|
||||
this.lblExtraScanlinesAfterNmi.Name = "lblExtraScanlinesAfterNmi";
|
||||
this.lblExtraScanlinesAfterNmi.Size = new System.Drawing.Size(150, 13);
|
||||
this.lblExtraScanlinesAfterNmi.TabIndex = 1;
|
||||
this.lblExtraScanlinesAfterNmi.Text = "Additional scanlines after NMI:";
|
||||
//
|
||||
// frmEmulationConfig
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@ -370,8 +554,8 @@
|
||||
this.Name = "frmEmulationConfig";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Emulation Config";
|
||||
this.Controls.SetChildIndex(this.tabMain, 0);
|
||||
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
|
||||
this.Controls.SetChildIndex(this.tabMain, 0);
|
||||
this.tabMain.ResumeLayout(false);
|
||||
this.tpgGeneral.ResumeLayout(false);
|
||||
this.tpgGeneral.PerformLayout();
|
||||
@ -386,6 +570,13 @@
|
||||
this.tpgAdvanced.ResumeLayout(false);
|
||||
this.flowLayoutPanel8.ResumeLayout(false);
|
||||
this.flowLayoutPanel8.PerformLayout();
|
||||
this.tpgOverclocking.ResumeLayout(false);
|
||||
this.tpgOverclocking.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picHint)).EndInit();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.grpPpuTiming.ResumeLayout(false);
|
||||
this.tableLayoutPanel5.ResumeLayout(false);
|
||||
this.tableLayoutPanel5.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@ -414,5 +605,15 @@
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel8;
|
||||
private System.Windows.Forms.Label lblRamPowerOnState;
|
||||
private System.Windows.Forms.ComboBox cboRamPowerOnState;
|
||||
private System.Windows.Forms.TabPage tpgOverclocking;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Label lblOverclockHint;
|
||||
private System.Windows.Forms.GroupBox grpPpuTiming;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5;
|
||||
private Controls.MesenNumericUpDown nudExtraScanlinesAfterNmi;
|
||||
private Controls.MesenNumericUpDown nudExtraScanlinesBeforeNmi;
|
||||
private System.Windows.Forms.Label lblExtraScanlinesBeforeNmi;
|
||||
private System.Windows.Forms.Label lblExtraScanlinesAfterNmi;
|
||||
private System.Windows.Forms.PictureBox picHint;
|
||||
}
|
||||
}
|
@ -28,6 +28,9 @@ namespace Mesen.GUI.Forms.Config
|
||||
AddBinding(nameof(EmulationConfig.Region), cboRegion);
|
||||
|
||||
AddBinding(nameof(EmulationConfig.RamPowerOnState), cboRamPowerOnState);
|
||||
|
||||
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesBeforeNmi), nudExtraScanlinesBeforeNmi);
|
||||
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesAfterNmi), nudExtraScanlinesAfterNmi);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
|
@ -120,4 +120,7 @@
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<data name="lblOverclockHint.Text" xml:space="preserve">
|
||||
<value>Overclocking can help reduce or remove slowdowns in games (but it can also cause issues). To overclock, try setting the "before NMI" value to a few hundred lines (e.g 300+). If this breaks the game, try lowering the value or using the "after NMI" field instead.</value>
|
||||
</data>
|
||||
</root>
|
Loading…
x
Reference in New Issue
Block a user