Debugger: Allow multiple PPU viewer windows to refresh at different scanline/cycle timings
This commit is contained in:
parent
1809c5becc
commit
1e47897ca6
10 changed files with 88 additions and 56 deletions
|
@ -435,6 +435,8 @@ void Console::Run()
|
|||
|
||||
UpdateNesModel(true);
|
||||
|
||||
_running = true;
|
||||
|
||||
bool crashed = false;
|
||||
try {
|
||||
while(true) {
|
||||
|
@ -511,6 +513,10 @@ void Console::Run()
|
|||
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
||||
}
|
||||
|
||||
_running = false;
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::BeforeEmulationStop);
|
||||
|
||||
if(!crashed) {
|
||||
SaveStateManager::SaveRecentGame(GetMapperInfo().RomName, _romFilepath, _patchFilename);
|
||||
}
|
||||
|
@ -559,12 +565,12 @@ void Console::Run()
|
|||
|
||||
bool Console::IsRunning()
|
||||
{
|
||||
return !Instance->_stopLock.IsFree();
|
||||
return !Instance->_stopLock.IsFree() && Instance->_running;
|
||||
}
|
||||
|
||||
bool Console::IsPaused()
|
||||
{
|
||||
return _runLock.IsFree() || !_pauseLock.IsFree();
|
||||
return _runLock.IsFree() || !_pauseLock.IsFree() || !_running;
|
||||
}
|
||||
|
||||
void Console::UpdateNesModel(bool sendNotification)
|
||||
|
|
|
@ -57,6 +57,7 @@ class Console
|
|||
string _patchFilename;
|
||||
|
||||
bool _stop = false;
|
||||
bool _running = false;
|
||||
|
||||
bool _disableOcNextFrame = false;
|
||||
|
||||
|
|
|
@ -79,9 +79,6 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_ppuScrollX = 0;
|
||||
_ppuScrollY = 0;
|
||||
|
||||
_ppuViewerScanline = 241;
|
||||
_ppuViewerCycle = 0;
|
||||
|
||||
_flags = 0;
|
||||
|
||||
_runToCycle = 0;
|
||||
|
@ -104,6 +101,8 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_hasScript = false;
|
||||
_nextScriptId = 0;
|
||||
|
||||
UpdatePpuCyclesToProcess();
|
||||
|
||||
Debugger::Instance = this;
|
||||
}
|
||||
|
||||
|
@ -468,9 +467,14 @@ void Debugger::ProcessStepConditions(uint16_t addr)
|
|||
|
||||
void Debugger::PrivateProcessPpuCycle()
|
||||
{
|
||||
if(PPU::GetCurrentCycle() == (uint32_t)_ppuViewerCycle && PPU::GetCurrentScanline() == _ppuViewerScanline) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame);
|
||||
if(_proccessPpuCycle[PPU::GetCurrentCycle()]) {
|
||||
int32_t currentCycle = (PPU::GetCurrentCycle() << 9) + PPU::GetCurrentScanline();
|
||||
for(auto updateCycle : _ppuViewerUpdateCycle) {
|
||||
if(updateCycle.second == currentCycle) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
|
||||
}
|
||||
}
|
||||
|
||||
if(PPU::GetCurrentCycle() == 0) {
|
||||
if(_breakOnScanline == PPU::GetCurrentScanline()) {
|
||||
Step(1);
|
||||
|
@ -482,6 +486,7 @@ void Debugger::PrivateProcessPpuCycle()
|
|||
ProcessEvent(EventType::StartFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead };
|
||||
|
||||
|
@ -1128,10 +1133,27 @@ void Debugger::GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTyp
|
|||
info->Type = PpuAddressType::None;
|
||||
}
|
||||
|
||||
void Debugger::SetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle)
|
||||
void Debugger::UpdatePpuCyclesToProcess()
|
||||
{
|
||||
_ppuViewerScanline = scanline;
|
||||
_ppuViewerCycle = cycle;
|
||||
memset(_proccessPpuCycle, 0, sizeof(_proccessPpuCycle));
|
||||
for(auto updateCycle : _ppuViewerUpdateCycle) {
|
||||
_proccessPpuCycle[updateCycle.second] = true;
|
||||
}
|
||||
_proccessPpuCycle[0] = true;
|
||||
}
|
||||
|
||||
void Debugger::SetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
_ppuViewerUpdateCycle[ppuViewerId] = (cycle << 9) + scanline;
|
||||
UpdatePpuCyclesToProcess();
|
||||
}
|
||||
|
||||
void Debugger::ClearPpuViewerSettings(int32_t ppuViewer)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
_ppuViewerUpdateCycle.erase(ppuViewer);
|
||||
UpdatePpuCyclesToProcess();
|
||||
}
|
||||
|
||||
void Debugger::SetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly)
|
||||
|
|
|
@ -107,8 +107,8 @@ private:
|
|||
|
||||
atomic<int32_t> _breakOnScanline;
|
||||
|
||||
int32_t _ppuViewerScanline;
|
||||
int32_t _ppuViewerCycle;
|
||||
bool _proccessPpuCycle[341];
|
||||
std::unordered_map<int, int> _ppuViewerUpdateCycle;
|
||||
|
||||
uint16_t _ppuScrollX;
|
||||
uint16_t _ppuScrollY;
|
||||
|
@ -142,6 +142,8 @@ private:
|
|||
|
||||
void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
|
||||
|
||||
void UpdatePpuCyclesToProcess();
|
||||
|
||||
public:
|
||||
Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<APU> apu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper);
|
||||
~Debugger();
|
||||
|
@ -186,7 +188,9 @@ public:
|
|||
shared_ptr<CodeDataLogger> GetCodeDataLogger();
|
||||
|
||||
void SetNextStatement(uint16_t addr);
|
||||
void SetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle);
|
||||
|
||||
void SetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle);
|
||||
void ClearPpuViewerSettings(int32_t ppuViewer);
|
||||
|
||||
bool IsExecutionStopped();
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ enum class ConsoleNotificationType
|
|||
ExecuteShortcut = 16,
|
||||
EmulationStopped = 17,
|
||||
EventViewerDisplayFrame = 18,
|
||||
BeforeEmulationStop = 19,
|
||||
};
|
||||
|
||||
class INotificationListener
|
||||
|
|
|
@ -711,24 +711,7 @@ void MessageManager::UnregisterNotificationListener(INotificationListener* notif
|
|||
void MessageManager::SendNotification(ConsoleNotificationType type, void* parameter)
|
||||
{
|
||||
auto lock = _notificationLock.AcquireSafe();
|
||||
|
||||
//Iterate on a copy to prevent issues if a notification causes a listener to unregister itself
|
||||
vector<INotificationListener*> listeners = MessageManager::_notificationListeners;
|
||||
vector<INotificationListener*> processedListeners;
|
||||
|
||||
for(size_t i = 0, len = listeners.size(); i < len; i++) {
|
||||
INotificationListener* notificationListener = listeners[i];
|
||||
if(std::find(processedListeners.begin(), processedListeners.end(), notificationListener) == processedListeners.end()) {
|
||||
//Only send notification if it hasn't been processed already
|
||||
for(INotificationListener *notificationListener : MessageManager::_notificationListeners) {
|
||||
notificationListener->ProcessNotification(type, parameter);
|
||||
}
|
||||
processedListeners.push_back(notificationListener);
|
||||
|
||||
if(len != MessageManager::_notificationListeners.size()) {
|
||||
//Vector changed, start from the beginning again (can occur when sending a notification caused listeners to unregister themselves)
|
||||
i = 0;
|
||||
len = MessageManager::_notificationListeners.size();
|
||||
listeners = MessageManager::_notificationListeners;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,16 @@ namespace Mesen.GUI.Debugger
|
|||
private TabPage _selectedTab;
|
||||
private bool _refreshing = false;
|
||||
|
||||
private static int _nextPpuViewerId = 0;
|
||||
private int _ppuViewerId = 0;
|
||||
|
||||
public frmPpuViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_ppuViewerId = _nextPpuViewerId;
|
||||
_nextPpuViewerId++;
|
||||
|
||||
this._selectedTab = this.tpgNametableViewer;
|
||||
this.mnuAutoRefresh.Checked = ConfigManager.Config.DebugInfo.PpuAutoRefresh;
|
||||
this.mnuRefreshOnBreak.Checked = ConfigManager.Config.DebugInfo.PpuRefreshOnBreak;
|
||||
|
@ -49,7 +55,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.nudScanline.Value = ConfigManager.Config.DebugInfo.PpuDisplayScanline;
|
||||
this.nudCycle.Value = ConfigManager.Config.DebugInfo.PpuDisplayCycle;
|
||||
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle((int)this.nudScanline.Value, (int)this.nudCycle.Value);
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle(_ppuViewerId, (int)this.nudScanline.Value, (int)this.nudCycle.Value);
|
||||
|
||||
this.ctrlNametableViewer.GetData();
|
||||
this.ctrlChrViewer.GetData();
|
||||
|
@ -67,6 +73,7 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
base.OnFormClosing(e);
|
||||
this._notifListener.OnNotification -= this._notifListener_OnNotification;
|
||||
InteropEmu.DebugClearPpuViewerSettings(_ppuViewerId);
|
||||
}
|
||||
|
||||
private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
|
||||
|
@ -81,17 +88,19 @@ namespace Mesen.GUI.Debugger
|
|||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.PpuViewerDisplayFrame:
|
||||
if(e.Parameter.ToInt32() == _ppuViewerId) {
|
||||
if(ConfigManager.Config.DebugInfo.PpuAutoRefresh && !_refreshing && (DateTime.Now - _lastUpdate).Milliseconds > 66) {
|
||||
//Update at 15 fps most
|
||||
this.GetData();
|
||||
this.BeginInvoke((MethodInvoker)(() => this.RefreshViewers()));
|
||||
_lastUpdate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.GameLoaded:
|
||||
//Configuration is lost when debugger is restarted (when switching game or power cycling)
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle(ConfigManager.Config.DebugInfo.PpuDisplayScanline, ConfigManager.Config.DebugInfo.PpuDisplayCycle);
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle(_ppuViewerId, ConfigManager.Config.DebugInfo.PpuDisplayScanline, ConfigManager.Config.DebugInfo.PpuDisplayCycle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +161,7 @@ namespace Mesen.GUI.Debugger
|
|||
scanline = Math.Min(260, Math.Max(-1, scanline));
|
||||
cycle = Math.Min(340, Math.Max(0, cycle));
|
||||
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle(scanline, cycle);
|
||||
InteropEmu.DebugSetPpuViewerScanlineCycle(_ppuViewerId, scanline, cycle);
|
||||
ConfigManager.Config.DebugInfo.PpuDisplayScanline = scanline;
|
||||
ConfigManager.Config.DebugInfo.PpuDisplayCycle = cycle;
|
||||
ConfigManager.ApplyChanges();
|
||||
|
|
|
@ -608,8 +608,8 @@ namespace Mesen.GUI.Forms
|
|||
}));
|
||||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.EmulationStopped:
|
||||
this.BeginInvoke((Action)(() => {
|
||||
case InteropEmu.ConsoleNotificationType.BeforeEmulationStop:
|
||||
this.Invoke((Action)(() => {
|
||||
DebugWindowManager.CloseAll();
|
||||
}));
|
||||
break;
|
||||
|
@ -777,7 +777,7 @@ namespace Mesen.GUI.Forms
|
|||
case EmulatorShortcut.Pause: PauseEmu(); break;
|
||||
case EmulatorShortcut.Reset: this.ResetEmu(); break;
|
||||
case EmulatorShortcut.PowerCycle: this.PowerCycleEmu(); break;
|
||||
case EmulatorShortcut.PowerOff: InteropEmu.Stop(); break;
|
||||
case EmulatorShortcut.PowerOff: Task.Run(() => InteropEmu.Stop()); break;
|
||||
case EmulatorShortcut.Exit: this.Close(); break;
|
||||
|
||||
case EmulatorShortcut.ToggleCheats: ToggleCheats(); break;
|
||||
|
|
|
@ -253,7 +253,8 @@ namespace Mesen.GUI
|
|||
}
|
||||
|
||||
[DllImport(DLLPath)] public static extern void DebugGetAbsoluteAddressAndType(UInt32 relativeAddr, ref AddressTypeInfo addressTypeInfo);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetPpuViewerScanlineCycle(Int32 scanline, Int32 cycle);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetPpuViewerScanlineCycle(Int32 ppuViewerId, Int32 scanline, Int32 cycle);
|
||||
[DllImport(DLLPath)] public static extern void DebugClearPpuViewerSettings(Int32 ppuViewerId);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void DebugSetFreezeState(UInt16 address, [MarshalAs(UnmanagedType.I1)]bool frozen);
|
||||
|
||||
|
@ -876,6 +877,7 @@ namespace Mesen.GUI
|
|||
ExecuteShortcut = 16,
|
||||
EmulationStopped = 17,
|
||||
EventViewerDisplayFrame = 18,
|
||||
BeforeEmulationStop = 19,
|
||||
}
|
||||
|
||||
public enum ControllerType
|
||||
|
@ -1049,7 +1051,10 @@ namespace Mesen.GUI
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
Task.Run(() => {
|
||||
//Unregister the callback in another thread, to prevent deadlocks
|
||||
InteropEmu.UnregisterNotificationCallback(_notificationListener);
|
||||
});
|
||||
}
|
||||
|
||||
public void ProcessNotification(int type, IntPtr parameter)
|
||||
|
|
|
@ -51,7 +51,8 @@ extern "C"
|
|||
DllExport void __stdcall DebugBreakOnScanline(int32_t scanline) { GetDebugger()->BreakOnScanline(scanline); }
|
||||
DllExport const char* __stdcall DebugGetCode(uint32_t &length) { return GetDebugger()->GetCode(length); }
|
||||
|
||||
DllExport void __stdcall DebugSetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle) { return GetDebugger()->SetPpuViewerScanlineCycle(scanline, cycle); }
|
||||
DllExport void __stdcall DebugSetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle) { return GetDebugger()->SetPpuViewerScanlineCycle(ppuViewerId, scanline, cycle); }
|
||||
DllExport void __stdcall DebugClearPpuViewerSettings(int32_t ppuViewerId) { return GetDebugger()->ClearPpuViewerSettings(ppuViewerId); }
|
||||
|
||||
DllExport void __stdcall DebugSetNextStatement(uint16_t addr) { GetDebugger()->SetNextStatement(addr); }
|
||||
DllExport void __stdcall DebugSetMemoryState(DebugMemoryType type, uint8_t *buffer) { GetDebugger()->GetMemoryDumper()->SetMemoryState(type, buffer); }
|
||||
|
|
Loading…
Add table
Reference in a new issue