mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Debugger: Tilemap viewer - Mode 7 overlay
This commit is contained in:
parent
d1e11a1fde
commit
7df142e420
13 changed files with 165 additions and 2 deletions
|
@ -188,6 +188,8 @@ protected:
|
|||
public:
|
||||
PpuTools(Debugger* debugger, Emulator *emu);
|
||||
|
||||
virtual void GetPpuToolsState(BaseState& state) {};
|
||||
|
||||
virtual DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) = 0;
|
||||
|
||||
void GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, const uint32_t* palette, uint32_t *outBuffer);
|
||||
|
|
|
@ -12,6 +12,21 @@ static constexpr uint8_t layerBpp[8][4] = {
|
|||
|
||||
SnesPpuTools::SnesPpuTools(Debugger* debugger, Emulator *emu) : PpuTools(debugger, emu)
|
||||
{
|
||||
_state = {};
|
||||
}
|
||||
|
||||
void SnesPpuTools::GetPpuToolsState(BaseState& state)
|
||||
{
|
||||
(SnesPpuToolsState&)state = _state;
|
||||
}
|
||||
|
||||
void SnesPpuTools::SetPpuScanlineState(uint16_t scanline, uint8_t mode, int32_t mode7startX, int32_t mode7startY, int32_t mode7endX, int32_t mode7endY)
|
||||
{
|
||||
_state.ScanlineBgMode[scanline] = mode;
|
||||
_state.Mode7StartX[scanline] = mode7startX;
|
||||
_state.Mode7StartY[scanline] = mode7startY;
|
||||
_state.Mode7EndX[scanline] = mode7endX;
|
||||
_state.Mode7EndY[scanline] = mode7endY;
|
||||
}
|
||||
|
||||
DebugTilemapInfo SnesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
|
||||
|
|
|
@ -6,14 +6,28 @@ class Debugger;
|
|||
class Emulator;
|
||||
struct BaseState;
|
||||
|
||||
struct SnesPpuToolsState
|
||||
{
|
||||
uint8_t ScanlineBgMode[239];
|
||||
int32_t Mode7StartX[239];
|
||||
int32_t Mode7StartY[239];
|
||||
int32_t Mode7EndX[239];
|
||||
int32_t Mode7EndY[239];
|
||||
};
|
||||
|
||||
class SnesPpuTools final : public PpuTools
|
||||
{
|
||||
private:
|
||||
SnesPpuToolsState _state;
|
||||
|
||||
void GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, GetSpritePreviewOptions& options, SnesPpuState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette);
|
||||
|
||||
public:
|
||||
SnesPpuTools(Debugger* debugger, Emulator *emu);
|
||||
|
||||
void GetPpuToolsState(BaseState& state) override;
|
||||
void SetPpuScanlineState(uint16_t scanline, uint8_t mode, int32_t mode7startX, int32_t mode7startY, int32_t mode7endX, int32_t mode7endY);
|
||||
|
||||
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer) override;
|
||||
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
|
||||
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "SNES/InternalRegisters.h"
|
||||
#include "SNES/SnesControlManager.h"
|
||||
#include "SNES/SnesDmaController.h"
|
||||
#include "SNES/Debugger/SnesPpuTools.h"
|
||||
#include "Debugger/Debugger.h"
|
||||
#include "Shared/Emulator.h"
|
||||
#include "Shared/EmuSettings.h"
|
||||
#include "Shared/Video/VideoDecoder.h"
|
||||
|
@ -19,6 +21,7 @@
|
|||
#include "Utilities/HexUtilities.h"
|
||||
#include "Utilities/Serializer.h"
|
||||
|
||||
//TODO remove
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( disable : 4127 ) //conditional expression is constant
|
||||
#endif
|
||||
|
@ -443,6 +446,10 @@ bool SnesPpu::ProcessEndOfScanline(uint16_t& hClock)
|
|||
|
||||
memset(_mainScreenFlags, 0, sizeof(_mainScreenFlags));
|
||||
memset(_subScreenPriority, 0, sizeof(_subScreenPriority));
|
||||
|
||||
if(!_skipRender && _emu->IsDebugging()) {
|
||||
DebugProcessMode7Overlay();
|
||||
}
|
||||
}
|
||||
|
||||
_scanline++;
|
||||
|
@ -1141,6 +1148,14 @@ void SnesPpu::RenderTilemapMode7()
|
|||
xStep = -xStep;
|
||||
yStep = -yStep;
|
||||
}
|
||||
|
||||
if(_drawStartX == 0) {
|
||||
//Keep start/end values - used by tilemap viewer
|
||||
_debugMode7StartX = xValue;
|
||||
_debugMode7StartY = yValue;
|
||||
_debugMode7EndX = xValue + xStep * 256;
|
||||
_debugMode7EndY = yValue + yStep * 256;
|
||||
}
|
||||
|
||||
xValue += xStep * _drawStartX;
|
||||
yValue += yStep * _drawStartX;
|
||||
|
@ -1501,6 +1516,19 @@ void SnesPpu::DebugSendFrame()
|
|||
_emu->GetVideoDecoder()->UpdateFrame(frame, false, false);
|
||||
}
|
||||
|
||||
void SnesPpu::DebugProcessMode7Overlay()
|
||||
{
|
||||
//Store mode 7 related information in ppu tools to allow tilemap viewer to display mode 7 overlay
|
||||
SnesPpuTools* ppuTools = ((SnesPpuTools*)_emu->InternalGetDebugger()->GetPpuTools(CpuType::Snes));
|
||||
ppuTools->SetPpuScanlineState(_scanline, _state.ForcedBlank ? 0 : _state.BgMode, _debugMode7StartX, _debugMode7StartY, _debugMode7EndX, _debugMode7EndY);
|
||||
if(_scanline == _vblankStartScanline - 1) {
|
||||
for(int i = _scanline + 1; i < 239; i++) {
|
||||
ppuTools->SetPpuScanlineState(i, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
_debugMode7StartX = _debugMode7StartY = _debugMode7EndX = _debugMode7EndY = 0;
|
||||
}
|
||||
|
||||
bool SnesPpu::IsHighResOutput()
|
||||
{
|
||||
return _useHighResOutput;
|
||||
|
|
|
@ -116,6 +116,11 @@ private:
|
|||
uint8_t _spritePaletteCopy[256] = {};
|
||||
uint8_t _spriteColorsCopy[256] = {};
|
||||
|
||||
int32_t _debugMode7StartX = 0;
|
||||
int32_t _debugMode7StartY = 0;
|
||||
int32_t _debugMode7EndX = 0;
|
||||
int32_t _debugMode7EndY = 0;
|
||||
|
||||
void RenderSprites(const uint8_t priorities[4]);
|
||||
|
||||
template<bool hiResMode>
|
||||
|
@ -204,6 +209,8 @@ private:
|
|||
|
||||
void RandomizeState();
|
||||
|
||||
__noinline void DebugProcessMode7Overlay();
|
||||
|
||||
public:
|
||||
SnesPpu(Emulator* emu, SnesConsole* console);
|
||||
virtual ~SnesPpu();
|
||||
|
|
|
@ -226,6 +226,7 @@ public:
|
|||
void StopDebugger();
|
||||
DebuggerRequest GetDebugger(bool autoInit = false);
|
||||
bool IsDebugging();
|
||||
Debugger* InternalGetDebugger() { return _debugger.get(); }
|
||||
|
||||
thread::id GetEmulationThreadId();
|
||||
bool IsEmulationThread();
|
||||
|
|
|
@ -150,6 +150,7 @@ extern "C"
|
|||
|
||||
DllExport void __stdcall GetTileView(CpuType cpuType, GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint32_t* colors, uint32_t* buffer) { WithToolVoid(GetPpuTools(cpuType), GetTileView(options, source, srcSize, colors, buffer)); }
|
||||
|
||||
DllExport void __stdcall GetPpuToolsState(CpuType cpuType, BaseState& state) { return WithToolVoid(GetPpuTools(cpuType), GetPpuToolsState(state)); }
|
||||
DllExport DebugTilemapInfo __stdcall GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t* outputBuffer) { return WithTool(DebugTilemapInfo, GetPpuTools(cpuType), GetTilemap(options, state, vram, palette, outputBuffer)); }
|
||||
DllExport FrameInfo __stdcall GetTilemapSize(CpuType cpuType, GetTilemapOptions options, BaseState& state) { return WithTool(FrameInfo, GetPpuTools(cpuType), GetTilemapSize(options, state)); }
|
||||
DllExport DebugTilemapTileInfo __stdcall GetTilemapTileInfo(uint32_t x, uint32_t y, CpuType cpuType, GetTilemapOptions options, uint8_t* vram, BaseState& state) { return WithTool(DebugTilemapTileInfo, GetPpuTools(cpuType), GetTilemapTileInfo(x, y, vram, options, state)); }
|
||||
|
|
|
@ -151,7 +151,8 @@ namespace Mesen.Debugger.Controls
|
|||
AffectsRender<PictureViewer>(
|
||||
SourceProperty, ZoomProperty, GridSizeXProperty, GridSizeYProperty,
|
||||
ShowGridProperty, SelectionRectProperty, OverlayRectProperty,
|
||||
HighlightRectsProperty, MouseOverRectProperty, GridHighlightProperty
|
||||
HighlightRectsProperty, MouseOverRectProperty, GridHighlightProperty,
|
||||
OverlayLinesProperty
|
||||
);
|
||||
|
||||
SourceProperty.Changed.AddClassHandler<PictureViewer>((x, e) => {
|
||||
|
@ -408,7 +409,7 @@ namespace Mesen.Debugger.Controls
|
|||
|
||||
if(OverlayLines?.Count > 0) {
|
||||
foreach(PictureViewerLine line in OverlayLines) {
|
||||
Pen pen = new Pen(line.Color.ToUint32(), 2, line.DashStyle);
|
||||
Pen pen = new Pen(line.Color.ToUint32(), line.Width ?? 2, line.DashStyle);
|
||||
context.DrawLine(pen, line.Start * Zoom, line.End * Zoom);
|
||||
}
|
||||
}
|
||||
|
@ -491,6 +492,7 @@ namespace Mesen.Debugger.Controls
|
|||
public Point Start;
|
||||
public Point End;
|
||||
public Color Color;
|
||||
public int? Width;
|
||||
public IDashStyle? DashStyle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
[Reactive] public TilemapViewerTab SelectedTab { get; set; }
|
||||
|
||||
[Reactive] public Rect ScrollOverlayRect { get; private set; } = Rect.Empty;
|
||||
[Reactive] public List<PictureViewerLine>? OverlayLines { get; private set; } = null;
|
||||
|
||||
public List<object> FileMenuActions { get; } = new();
|
||||
public List<object> ViewMenuActions { get; } = new();
|
||||
|
@ -53,6 +54,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
private PictureViewer _picViewer;
|
||||
private UInt64 _masterClock;
|
||||
private BaseState? _ppuState;
|
||||
private BaseState? _ppuToolsState;
|
||||
private byte[] _prevVram = Array.Empty<byte>();
|
||||
private byte[] _vram = Array.Empty<byte>();
|
||||
private UInt32[] _rgbPalette = Array.Empty<UInt32>();
|
||||
|
@ -374,6 +376,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
BaseState ppuState = DebugApi.GetPpuState(CpuType);
|
||||
_ppuState = ppuState;
|
||||
_ppuToolsState = DebugApi.GetPpuToolsState(CpuType);
|
||||
_prevVram = _vram;
|
||||
_vram = DebugApi.GetMemoryState(GetVramMemoryType());
|
||||
_accessCounters = DebugApi.GetMemoryAccessCounts(GetVramMemoryType());
|
||||
|
@ -439,8 +442,11 @@ namespace Mesen.Debugger.ViewModels
|
|||
_tilemapInfo.ScrollWidth,
|
||||
_tilemapInfo.ScrollHeight
|
||||
);
|
||||
|
||||
DrawMode7Overlay();
|
||||
} else {
|
||||
ScrollOverlayRect = Rect.Empty;
|
||||
OverlayLines = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -563,6 +569,46 @@ namespace Mesen.Debugger.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
private void DrawMode7Overlay()
|
||||
{
|
||||
if(_ppuToolsState is SnesPpuToolsState toolsState && _ppuState is SnesPpuState ppuState) {
|
||||
List<PictureViewerLine> lines = new();
|
||||
|
||||
HslColor baseColor = ColorHelper.RgbToHsl(Color.FromRgb(255, 0, 255));
|
||||
for(int i = 0; i < 239; i++) {
|
||||
if(toolsState.ScanlineBgMode[i] == 7) {
|
||||
Color lineColor = ColorHelper.HslToRgb(baseColor);
|
||||
Color alphaColor = Color.FromArgb(0xA0, lineColor.R, lineColor.G, lineColor.B);
|
||||
|
||||
int startX = toolsState.Mode7StartX[i] >> 8;
|
||||
int startY = toolsState.Mode7StartY[i] >> 8;
|
||||
int endX = toolsState.Mode7EndX[i] >> 8;
|
||||
int endY = toolsState.Mode7EndY[i] >> 8;
|
||||
|
||||
lines.Add(new PictureViewerLine() { Start = new Point(startX, startY), End = new Point(endX, endY), Width = 1, Color = alphaColor });
|
||||
if(!ppuState.Mode7.LargeMap) {
|
||||
void Translate(ref int start, ref int end, int offset, Func<int, bool> predicate) {
|
||||
while(predicate(start) || predicate(end)) {
|
||||
start += offset;
|
||||
end += offset;
|
||||
lines.Add(new PictureViewerLine() { Start = new Point(startX, startY), End = new Point(endX, endY), Width = 1, Color = alphaColor });
|
||||
}
|
||||
}
|
||||
|
||||
Translate(ref startX, ref endX, 1024, x => x < 0);
|
||||
Translate(ref startY, ref endY, 1024, x => x < 0);
|
||||
Translate(ref startX, ref endX, -1024, x => x >= 1024);
|
||||
Translate(ref startY, ref endY, -1024, x => x >= 1024);
|
||||
}
|
||||
}
|
||||
baseColor.H--;
|
||||
}
|
||||
OverlayLines = lines;
|
||||
} else {
|
||||
OverlayLines = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
_inGameLoaded = true;
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
AltGridSizeX="16"
|
||||
AltGridSizeY="16"
|
||||
ShowAltGrid="{CompiledBinding Config.ShowAltGrid}"
|
||||
OverlayLines="{CompiledBinding OverlayLines}"
|
||||
/>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
|
|
|
@ -136,6 +136,25 @@ namespace Mesen.Interop
|
|||
};
|
||||
}
|
||||
|
||||
[DllImport(DllPath)] private static extern void GetPpuToolsState(CpuType cpuType, IntPtr state);
|
||||
public unsafe static T GetPpuToolsState<T>(CpuType cpuType) where T : struct, BaseState
|
||||
{
|
||||
byte* ptr = stackalloc byte[Marshal.SizeOf(typeof(T))];
|
||||
DebugApi.GetPpuToolsState(cpuType, (IntPtr)ptr);
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
|
||||
public static BaseState GetPpuToolsState(CpuType cpuType)
|
||||
{
|
||||
return cpuType switch {
|
||||
CpuType.Snes => GetPpuToolsState<SnesPpuToolsState>(cpuType),
|
||||
CpuType.Nes => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
|
||||
CpuType.Gameboy => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
|
||||
CpuType.Pce => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
|
||||
_ => throw new Exception("Unsupport cpu type")
|
||||
};
|
||||
}
|
||||
|
||||
[DllImport(DllPath)] private static extern void SetPpuState(IntPtr state, CpuType cpuType);
|
||||
public unsafe static void SetPpuState(BaseState state, CpuType cpuType)
|
||||
{
|
||||
|
|
|
@ -958,6 +958,28 @@ namespace Mesen.Interop
|
|||
public AluState Alu;
|
||||
}
|
||||
|
||||
public struct EmptyPpuToolsState : BaseState
|
||||
{
|
||||
}
|
||||
|
||||
public struct SnesPpuToolsState : BaseState
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 239)]
|
||||
public byte[] ScanlineBgMode;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 239)]
|
||||
public Int32[] Mode7StartX;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 239)]
|
||||
public Int32[] Mode7StartY;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 239)]
|
||||
public Int32[] Mode7EndX;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 239)]
|
||||
public Int32[] Mode7EndY;
|
||||
}
|
||||
|
||||
public struct NesPpuStatusFlags
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)] public bool SpriteOverflow;
|
||||
|
|
|
@ -47,6 +47,11 @@ public:
|
|||
_shared = ptr;
|
||||
}
|
||||
|
||||
T* get()
|
||||
{
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return _ptr != nullptr;
|
||||
|
|
Loading…
Add table
Reference in a new issue