mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Debugger: Added "draw partial frame" option
This commit is contained in:
parent
b438d9dde0
commit
60889176b7
25 changed files with 140 additions and 22 deletions
|
@ -256,6 +256,10 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
|
|||
_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints = true;
|
||||
}
|
||||
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::DrawPartialFrame)) {
|
||||
_debuggers[(int)sourceCpu].Debugger->DrawPartialFrame();
|
||||
}
|
||||
|
||||
//Only trigger code break event if the pause was caused by user action
|
||||
BreakEvent evt = {};
|
||||
evt.SourceCpu = sourceCpu;
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
virtual void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) {}
|
||||
|
||||
virtual void DrawPartialFrame() { }
|
||||
|
||||
virtual DebuggerFeatures GetSupportedFeatures() { return {}; }
|
||||
|
||||
virtual uint32_t GetProgramCounter(bool getInstPc) = 0;
|
||||
|
|
|
@ -253,6 +253,11 @@ void GbDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void GbDebugger::DrawPartialFrame()
|
||||
{
|
||||
_ppu->DebugSendFrame();
|
||||
}
|
||||
|
||||
void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
||||
{
|
||||
AddressInfo src = _gameboy->GetAbsoluteAddress(_prevProgramCounter);
|
||||
|
|
|
@ -66,7 +66,9 @@ public:
|
|||
|
||||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
|
||||
void DrawPartialFrame() override;
|
||||
|
||||
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
|
||||
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
|
|
|
@ -653,12 +653,8 @@ void GbPpu::SendFrame()
|
|||
_isFirstFrame = false;
|
||||
|
||||
RenderedFrame frame(_currentBuffer, GbConstants::ScreenWidth, GbConstants::ScreenHeight, 1.0, _state.FrameCount, _gameboy->GetControlManager()->GetPortStates());
|
||||
#ifdef LIBRETRO
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, true, false);
|
||||
#else
|
||||
bool rewinding = _emu->GetRewindManager()->IsRewinding();
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, rewinding, rewinding);
|
||||
#endif
|
||||
|
||||
_emu->ProcessEndOfFrame();
|
||||
_gameboy->ProcessEndOfFrame();
|
||||
|
@ -666,6 +662,26 @@ void GbPpu::SendFrame()
|
|||
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
|
||||
}
|
||||
|
||||
void GbPpu::DebugSendFrame()
|
||||
{
|
||||
if(_gameboy->IsSgb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lastPixel = std::max(0, _state.IrqMode == PpuMode::HBlank ? 160 : _drawnPixels);
|
||||
int offset = std::max(0, (int)(lastPixel + 1 + _state.Scanline * GbConstants::ScreenWidth));
|
||||
int pixelsToClear = GbConstants::PixelCount - offset;
|
||||
if(pixelsToClear > 0) {
|
||||
memset(_currentBuffer + offset, 0, pixelsToClear * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
RenderedFrame frame(_currentBuffer, GbConstants::ScreenWidth, GbConstants::ScreenHeight, 1.0, _state.FrameCount);
|
||||
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
//Send twice to prevent LCD blending behavior
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
void GbPpu::UpdatePalette()
|
||||
{
|
||||
if(!_gameboy->IsCgb()) {
|
||||
|
|
|
@ -110,6 +110,8 @@ public:
|
|||
|
||||
uint8_t ReadCgbRegister(uint16_t addr);
|
||||
void WriteCgbRegister(uint16_t addr, uint8_t value);
|
||||
|
||||
|
||||
void DebugSendFrame();
|
||||
|
||||
void Serialize(Serializer& s) override;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseNesPpu.h"
|
||||
#include "NES/BaseNesPpu.h"
|
||||
#include "NES/NesTypes.h"
|
||||
#include "NES/NesConstants.h"
|
||||
#include "NES/NesConsole.h"
|
||||
#include "Shared/Emulator.h"
|
||||
#include "Shared/Video/VideoDecoder.h"
|
||||
#include "Shared/SettingTypes.h"
|
||||
|
||||
void BaseNesPpu::GetState(NesPpuState& state)
|
||||
|
@ -98,6 +101,18 @@ void BaseNesPpu::WritePaletteRam(uint16_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
void BaseNesPpu::DebugSendFrame()
|
||||
{
|
||||
int offset = std::max(0, (int)(_cycle + _scanline * NesConstants::ScreenWidth));
|
||||
int pixelsToClear = NesConstants::ScreenPixelCount - offset;
|
||||
if(pixelsToClear > 0) {
|
||||
memset(_currentOutputBuffer + offset, 0, pixelsToClear * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount);
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
/* Applies the effect of grayscale/intensify bits to the output buffer (batched) */
|
||||
void BaseNesPpu::UpdateGrayscaleAndIntensifyBits()
|
||||
{
|
||||
|
|
|
@ -140,6 +140,8 @@ public:
|
|||
uint8_t ReadPaletteRam(uint16_t addr);
|
||||
void WritePaletteRam(uint16_t addr, uint8_t value);
|
||||
|
||||
void DebugSendFrame();
|
||||
|
||||
virtual PpuModel GetPpuModel() = 0;
|
||||
virtual uint32_t GetPixelBrightness(uint8_t x, uint8_t y) = 0;
|
||||
|
||||
|
|
|
@ -268,6 +268,11 @@ void NesDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void NesDebugger::DrawPartialFrame()
|
||||
{
|
||||
_ppu->DebugSendFrame();
|
||||
}
|
||||
|
||||
void NesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
||||
{
|
||||
AddressInfo src = _mapper->GetAbsoluteAddress(_prevProgramCounter);
|
||||
|
|
|
@ -77,6 +77,8 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
void DrawPartialFrame() override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
|
|
@ -1035,12 +1035,6 @@ template<class T> void NesPpu<T>::WriteSpriteRam(uint8_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
template<class T> void NesPpu<T>::DebugSendFrame()
|
||||
{
|
||||
RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount);
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
template<class T> uint16_t* NesPpu<T>::GetScreenBuffer(bool previousBuffer)
|
||||
{
|
||||
return previousBuffer ? ((_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0]) : _currentOutputBuffer;
|
||||
|
@ -1066,9 +1060,6 @@ template<class T> void NesPpu<T>::SendFrame()
|
|||
RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
|
||||
frame.Data = frameData; //HD packs
|
||||
|
||||
#ifdef LIBRETRO
|
||||
_console->GetVideoDecoder()->UpdateFrame(frame, true, false);
|
||||
#else
|
||||
if(_console->GetVsMainConsole() || _console->GetVsSubConsole()) {
|
||||
SendFrameVsDualSystem();
|
||||
if(_console->IsVsMainConsole()) {
|
||||
|
@ -1081,7 +1072,6 @@ template<class T> void NesPpu<T>::SendFrame()
|
|||
}
|
||||
|
||||
_enableOamDecay = _settings->GetNesConfig().EnableOamDecay;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class T> void NesPpu<T>::SendFrameVsDualSystem()
|
||||
|
|
|
@ -105,7 +105,6 @@ public:
|
|||
|
||||
void Reset() override;
|
||||
|
||||
void DebugSendFrame();
|
||||
uint16_t* GetScreenBuffer(bool previousBuffer) override;
|
||||
void DebugCopyOutputBuffer(uint16_t* target);
|
||||
void DebugUpdateFrameBuffer(bool toGrayscale);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "PCE/PceCpu.h"
|
||||
#include "PCE/PceVdc.h"
|
||||
#include "PCE/PceVce.h"
|
||||
#include "PCE/PceVpc.h"
|
||||
#include "PCE/PceMemoryManager.h"
|
||||
#include "PCE/Debugger/PceDebugger.h"
|
||||
#include "PCE/Debugger/PceTraceLogger.h"
|
||||
|
@ -40,6 +41,7 @@ PceDebugger::PceDebugger(Debugger* debugger)
|
|||
_cpu = console->GetCpu();
|
||||
_vdc = console->GetVdc();
|
||||
_vce = console->GetVce();
|
||||
_vpc = console->GetVpc();
|
||||
_memoryManager = console->GetMemoryManager();
|
||||
|
||||
_traceLogger.reset(new PceTraceLogger(debugger, this, _vdc));
|
||||
|
@ -243,6 +245,11 @@ void PceDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void PceDebugger::DrawPartialFrame()
|
||||
{
|
||||
_vpc->DebugSendFrame();
|
||||
}
|
||||
|
||||
void PceDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
||||
{
|
||||
AddressInfo src = _memoryManager->GetAbsoluteAddress(_prevProgramCounter);
|
||||
|
|
|
@ -21,6 +21,7 @@ class Emulator;
|
|||
class PceCpu;
|
||||
class PceVdc;
|
||||
class PceVce;
|
||||
class PceVpc;
|
||||
class PceMemoryManager;
|
||||
class DummyPceCpu;
|
||||
|
||||
|
@ -38,6 +39,7 @@ class PceDebugger final : public IDebugger
|
|||
PceCpu* _cpu;
|
||||
PceVdc* _vdc;
|
||||
PceVce* _vce;
|
||||
PceVpc* _vpc;
|
||||
PceMemoryManager* _memoryManager;
|
||||
|
||||
unique_ptr<CodeDataLogger> _codeDataLogger;
|
||||
|
@ -76,6 +78,8 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
void DrawPartialFrame() override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
|
|
@ -19,6 +19,7 @@ PceVpc::PceVpc(Emulator* emu, PceConsole* console, PceVce* vce)
|
|||
_outBuffer[0] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_outBuffer[1] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_currentOutBuffer = _outBuffer[0];
|
||||
_currentClockDividers = _rowVceClockDivider[0];
|
||||
|
||||
memset(_outBuffer[0], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
memset(_outBuffer[1], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
|
@ -249,6 +250,26 @@ void PceVpc::SendFrame(PceVdc* vdc)
|
|||
_console->GetControlManager()->UpdateControlDevices();
|
||||
}
|
||||
|
||||
void PceVpc::DebugSendFrame()
|
||||
{
|
||||
uint16_t scanline = _vdc1->GetScanline();
|
||||
if(scanline >= 14 && scanline < 256) {
|
||||
DrawScanline();
|
||||
ProcessScanlineEnd(_vdc1, scanline, _vdc1->GetRowBuffer());
|
||||
|
||||
uint32_t lastPixel = _vdc1->GetHClock() / _vce->GetClockDivider();
|
||||
int offset = std::max(0, (int)(lastPixel + (scanline - 14) * PceConstants::MaxScreenWidth));
|
||||
int pixelsToClear = PceConstants::MaxScreenWidth * PceConstants::ScreenHeight - offset;
|
||||
if(pixelsToClear > 0) {
|
||||
memset(_currentOutBuffer + offset, 0, pixelsToClear * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
RenderedFrame frame(_currentOutBuffer, 512, PceConstants::ScreenHeight * 2, 0.5, _vdc1->GetState().FrameCount);
|
||||
frame.Data = _currentClockDividers;
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
void PceVpc::UpdateIrqState()
|
||||
{
|
||||
if(_hasIrqVdc1 || _hasIrqVdc2) {
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
void ProcessScanlineStart(PceVdc* vdc, uint16_t scanline);
|
||||
void ProcessScanlineEnd(PceVdc* vdc, uint16_t scanline, uint16_t* rowBuffer);
|
||||
void SendFrame(PceVdc* vdc);
|
||||
|
||||
void DebugSendFrame();
|
||||
|
||||
void SetIrq(PceVdc* vdc);
|
||||
void ClearIrq(PceVdc* vdc);
|
||||
|
|
|
@ -289,6 +289,11 @@ void SnesDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void SnesDebugger::DrawPartialFrame()
|
||||
{
|
||||
_ppu->DebugSendFrame();
|
||||
}
|
||||
|
||||
void SnesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
||||
{
|
||||
AddressInfo src = _memoryMappings->GetAbsoluteAddress(_prevProgramCounter);
|
||||
|
|
|
@ -94,6 +94,8 @@ public:
|
|||
|
||||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
void DrawPartialFrame() override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
|
|
|
@ -1480,21 +1480,41 @@ void SnesPpu::SendFrame()
|
|||
bool isRewinding = _emu->GetRewindManager()->IsRewinding();
|
||||
|
||||
RenderedFrame frame(_currentBuffer, width, height, _useHighResOutput ? 0.5 : 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
|
||||
#ifdef LIBRETRO
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, true, isRewinding);
|
||||
#else
|
||||
if(isRewinding || _interlacedFrame) {
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, true, isRewinding);
|
||||
} else {
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!_skipRender) {
|
||||
_frameSkipTimer.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SnesPpu::DebugSendFrame()
|
||||
{
|
||||
if(_interlacedFrame) {
|
||||
//Not supported
|
||||
return;
|
||||
}
|
||||
|
||||
RenderScanline();
|
||||
|
||||
uint16_t width = _useHighResOutput ? 512 : 256;
|
||||
uint16_t height = _useHighResOutput ? 478 : 239;
|
||||
|
||||
int lastDrawnPixel = _drawEndX * (_useHighResOutput ? 2 : 1);
|
||||
int scanline = _overscanFrame ? ((int)_scanline - 1) : ((int)_scanline + 6);
|
||||
|
||||
int offset = std::max(0, lastDrawnPixel + 1 + scanline * width);
|
||||
int pixelsToClear = width * height - offset;
|
||||
if(pixelsToClear > 0) {
|
||||
memset(_currentBuffer + offset, 0, pixelsToClear * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
RenderedFrame frame(_currentBuffer, width, height, _useHighResOutput ? 0.5 : 1.0, _frameCount);
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
bool SnesPpu::IsHighResOutput()
|
||||
{
|
||||
|
|
|
@ -237,6 +237,8 @@ public:
|
|||
uint8_t* GetCgRam();
|
||||
uint8_t* GetSpriteRam();
|
||||
|
||||
void DebugSendFrame();
|
||||
|
||||
void SetLocationLatchRequest(uint16_t x, uint16_t y);
|
||||
void ProcessLocationLatchRequest();
|
||||
void LatchLocationValues();
|
||||
|
|
|
@ -770,6 +770,7 @@ enum class DebuggerFlags : uint64_t
|
|||
BreakOnUninitRead = (1 << 4),
|
||||
|
||||
ShowJumpLabels = (1 << 5),
|
||||
DrawPartialFrame = (1 << 6),
|
||||
|
||||
ShowVerifiedData = (1 << 8),
|
||||
DisassembleVerifiedData = (1 << 9),
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace Mesen.Config
|
|||
[Reactive] public bool UseLowerCaseDisassembly { get; set; } = false;
|
||||
|
||||
[Reactive] public bool ShowJumpLabels { get; set; } = false;
|
||||
[Reactive] public bool DrawPartialFrame { get; set; } = false;
|
||||
|
||||
[Reactive] public SnesDebuggerConfig Snes { get; set; } = new();
|
||||
[Reactive] public NesDebuggerConfig Nes { get; set; } = new();
|
||||
|
@ -89,6 +90,7 @@ namespace Mesen.Config
|
|||
ConfigApi.SetDebuggerFlag(DebuggerFlags.BreakOnUninitRead, BreakOnUninitRead);
|
||||
|
||||
ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowJumpLabels, ShowJumpLabels);
|
||||
ConfigApi.SetDebuggerFlag(DebuggerFlags.DrawPartialFrame, DrawPartialFrame);
|
||||
|
||||
ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Show);
|
||||
ConfigApi.SetDebuggerFlag(DebuggerFlags.DisassembleUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Disassemble);
|
||||
|
|
|
@ -158,6 +158,12 @@
|
|||
IsChecked="{CompiledBinding Config.BringToFrontOnBreak}"
|
||||
Content="{l:Translate chkBringToFrontOnBreak}"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{CompiledBinding Config.DrawPartialFrame}"
|
||||
Content="{l:Translate chkDrawPartialFrame}"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{CompiledBinding Config.UsePredictiveBreakpoints}"
|
||||
Content="{l:Translate chkUsePredictiveBreakpoints}"
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace Mesen.Interop
|
|||
BreakOnUninitRead = (1 << 4),
|
||||
|
||||
ShowJumpLabels = (1 << 5),
|
||||
DrawPartialFrame = (1 << 6),
|
||||
|
||||
ShowVerifiedData = (1 << 8),
|
||||
DisassembleVerifiedData = (1 << 9),
|
||||
|
|
|
@ -988,6 +988,7 @@
|
|||
|
||||
<Control ID="lblMiscSettings">Misc. settings</Control>
|
||||
<Control ID="chkBringToFrontOnBreak">Bring to front on break</Control>
|
||||
<Control ID="chkDrawPartialFrame">Draw partial frame</Control>
|
||||
<Control ID="chkUsePredictiveBreakpoints">Use predictive breakpoints</Control>
|
||||
<Control ID="chkSingleBreakpointPerInstruction">Break once per instruction</Control>
|
||||
</Form>
|
||||
|
|
Loading…
Add table
Reference in a new issue