Tilemap viewer: Refresh scanline/cycle config

This commit is contained in:
Sour 2021-12-28 20:53:39 -05:00
parent a1e7daec87
commit 368455e503
28 changed files with 344 additions and 92 deletions

View file

@ -88,15 +88,18 @@ public:
void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle);
void RemoveViewer(uint32_t viewerId);
__forceinline bool HasOpenedViewer()
{
return _updateTimings.size() > 0;
}
__forceinline void UpdateViewers(uint16_t scanline, uint16_t cycle)
{
if(_updateTimings.size() > 0) {
for(auto updateTiming : _updateTimings) {
ViewerRefreshConfig cfg = updateTiming.second;
if(cfg.Cycle == cycle && cfg.Scanline == scanline) {
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first);
}
for(auto updateTiming : _updateTimings) {
ViewerRefreshConfig cfg = updateTiming.second;
if(cfg.Cycle == cycle && cfg.Scanline == scanline) {
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first);
}
}
}

View file

@ -247,7 +247,10 @@ void GbDebugger::ProcessPpuCycle()
{
uint8_t scanline = _ppu->GetScanline();
uint16_t cycle = _ppu->GetCycle();
_ppuTools->UpdateViewers(scanline, cycle);
if(_ppuTools->HasOpenedViewer()) {
_ppuTools->UpdateViewers(scanline, cycle);
}
if(cycle == 0 && scanline == _step->BreakScanline) {
_debugger->SleepUntilResume(BreakSource::PpuStep);

View file

@ -479,6 +479,9 @@ PpuFrameInfo Gameboy::GetPpuFrame()
frame.FrameCount = _ppu->GetFrameCount();
frame.Width = 160;
frame.Height = 144;
frame.FirstScanline = 0;
frame.ScanlineCount = 154;
frame.CycleCount = 456;
return frame;
}

View file

@ -231,7 +231,10 @@ void NesDebugger::ProcessPpuCycle()
{
int16_t scanline = _ppu->GetCurrentScanline();
uint16_t cycle = _ppu->GetCurrentCycle();
_ppuTools->UpdateViewers(scanline, cycle);
if(_ppuTools->HasOpenedViewer()) {
_ppuTools->UpdateViewers(scanline, cycle);
}
if(cycle == 0 && scanline == _step->BreakScanline) {
_debugger->SleepUntilResume(BreakSource::PpuStep);

View file

@ -309,6 +309,9 @@ PpuFrameInfo NesConsole::GetPpuFrame()
frame.Width = NesConstants::ScreenWidth;
frame.Height = NesConstants::ScreenHeight;
frame.FrameCount = _ppu->GetFrameCount();
frame.FirstScanline = -1;
frame.ScanlineCount = _ppu->GetScanlineCount();
frame.CycleCount = 341;
return frame;
}

View file

@ -67,8 +67,6 @@ public:
void RunVsSubConsole();
//TODO
bool IsNsf() { return false; }
void DebugSetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly) {}
void SetNextFrameOverclockStatus(bool enabled) {}
// Inherited via IConsole

View file

@ -296,7 +296,7 @@ uint16_t NesCpu::FetchOperand()
_emu->GetDebugger(true)->BreakImmediately(BreakSource::BreakOnCpuCrash);
}
if(_console->IsNsf()) {
if(_console->GetRomFormat() == RomFormat::Nsf) {
//Don't stop emulation on CPU crash when playing NSFs, reset cpu instead
_emu->Reset();
return 0;

View file

@ -452,7 +452,6 @@ template<class T> void NesPpu<T>::WriteRam(uint16_t addr, uint8_t value)
_needStateUpdate = true;
_updateVramAddrDelay = 3;
_updateVramAddr = _tmpVideoRamAddr;
_console->DebugSetLastFramePpuScroll(_updateVramAddr, _xScroll, false);
} else {
uint16_t newAddr = (_tmpVideoRamAddr & ~0xFF00) | ((value & 0x3F) << 8);
ProcessTmpAddrScrollGlitch(newAddr, _console->GetMemoryManager()->GetOpenBus() << 8, 0x0C00);
@ -915,7 +914,6 @@ template<class T> void NesPpu<T>::ProcessScanlineImpl()
if(_prevRenderingEnabled) {
//copy horizontal scrolling value from t
_videoRamAddr = (_videoRamAddr & ~0x041F) | (_tmpVideoRamAddr & 0x041F);
_console->DebugSetLastFramePpuScroll(_videoRamAddr, _xScroll, true);
}
}
if(IsRenderingEnabled()) {
@ -946,9 +944,6 @@ template<class T> void NesPpu<T>::ProcessScanlineImpl()
LoadExtraSprites();
_oamCopybuffer = _secondarySpriteRAM[0];
}
if(_scanline == -1) {
_console->DebugSetLastFramePpuScroll(_videoRamAddr, _xScroll, false);
}
} else if(_prevRenderingEnabled && (_cycle == 328 || _cycle == 336)) {
_lowBitShift <<= 8;
_highBitShift <<= 8;

View file

@ -219,6 +219,9 @@ PpuFrameInfo Console::GetPpuFrame()
frame.Width = 256;
frame.Height = 239;
frame.FrameCount = _ppu->GetFrameCount();
frame.FirstScanline = 0;
frame.ScanlineCount = _ppu->GetVblankEndScanline() + 1;
frame.CycleCount = 341;
return frame;
}

View file

@ -270,10 +270,11 @@ void CpuDebugger::ProcessPpuCycle()
}
uint16_t scanline = _ppu->GetScanline();
uint16_t cycle = _memoryManager->GetHClock();
_ppuTools->UpdateViewers(scanline, cycle);
if(_ppuTools->HasOpenedViewer()) {
_ppuTools->UpdateViewers(scanline, _ppu->GetCycle());
}
if(cycle == 0 && scanline == _step->BreakScanline) {
if(scanline == _step->BreakScanline && _memoryManager->GetHClock() == 0) {
_debugger->SleepUntilResume(BreakSource::PpuStep);
} else if(_step->PpuStepCount > 0) {
_step->PpuStepCount--;

View file

@ -497,7 +497,11 @@ uint32_t Emulator::GetCrc32()
PpuFrameInfo Emulator::GetPpuFrame()
{
return _console->GetPpuFrame();
if(_console) {
return _console->GetPpuFrame();
} else {
return {};
}
}
ConsoleRegion Emulator::GetRegion()
@ -535,11 +539,18 @@ vector<CpuType> Emulator::GetCpuTypes()
TimingInfo Emulator::GetTimingInfo()
{
TimingInfo info;
info.MasterClock = GetMasterClock();
info.MasterClockRate = GetMasterClockRate();
info.FrameCount = GetFrameCount();
info.Fps = GetFps();
TimingInfo info = {};
if(_console) {
info.MasterClock = GetMasterClock();
info.MasterClockRate = GetMasterClockRate();
info.FrameCount = GetFrameCount();
info.Fps = GetFps();
PpuFrameInfo frameInfo = GetPpuFrame();
info.CycleCount = frameInfo.CycleCount;
info.ScanlineCount = frameInfo.ScanlineCount;
info.FirstScanline = frameInfo.FirstScanline;
}
return info;
}

View file

@ -22,10 +22,13 @@ enum class LoadRomResult
struct PpuFrameInfo
{
uint8_t* FrameBuffer;
uint32_t Width;
uint32_t Height;
uint32_t FrameCount;
uint8_t* FrameBuffer;
uint32_t ScanlineCount;
int32_t FirstScanline;
uint32_t CycleCount;
};
class IConsole : public ISerializable

View file

@ -7,4 +7,8 @@ struct TimingInfo
uint64_t MasterClock;
uint32_t MasterClockRate;
uint32_t FrameCount;
uint32_t ScanlineCount;
int32_t FirstScanline;
uint32_t CycleCount;
};

View file

@ -10,6 +10,7 @@ namespace Mesen.Config
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
[Reactive] public bool AutoRefresh { get; set; } = true;
[Reactive] public RefreshTimingConfig RefreshTiming { get; set; } = new();
public SnesEventViewerConfig SnesConfig { get; set; } = new SnesEventViewerConfig();
public NesEventViewerConfig NesConfig { get; set; } = new NesEventViewerConfig();

View file

@ -0,0 +1,18 @@
using Mesen.Interop;
using ReactiveUI.Fody.Helpers;
namespace Mesen.Config
{
public class RefreshTimingConfig : BaseConfig<RefreshTimingConfig>
{
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
[Reactive] public bool AutoRefresh { get; set; } = true;
[Reactive] public int RefreshScanline { get; set; } = 240;
[Reactive] public int RefreshCycle { get; set; } = 0;
public RefreshTimingConfig()
{
}
}
}

View file

@ -1,14 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using Avalonia;
using Mesen.Debugger;
using Mesen.Interop;
using Mesen.Interop;
using ReactiveUI.Fody.Helpers;
namespace Mesen.Config
@ -26,10 +16,7 @@ namespace Mesen.Config
[Reactive] public bool HighlightAttributeChanges { get; set; }
[Reactive] public TilemapDisplayMode DisplayMode { get; set; } = TilemapDisplayMode.Default;
[Reactive] public bool AutoRefresh { get; set; } = true;
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
[Reactive] public int RefreshScanline { get; set; } = 240;
[Reactive] public int RefreshCycle { get; set; } = 0;
[Reactive] public RefreshTimingConfig RefreshTiming { get; set; } = new();
public TilemapViewerConfig()
{

View file

@ -13,12 +13,15 @@
<ItemsControl.Template>
<ControlTemplate>
<StackPanel>
<TextBlock
Text="{Binding Header, ElementName=root}"
Foreground="Gray"
FontSize="13"
Margin="0 0 0 5"
/>
<StackPanel Orientation="Horizontal">
<TextBlock
Text="{Binding Header, ElementName=root}"
Foreground="Gray"
FontSize="13"
Margin="0 0 0 5"
/>
<ContentControl Content="{Binding Button, ElementName=root}" />
</StackPanel>
<StackPanel Margin="10 0 0 0">
<ItemsPresenter Items="{Binding Items, ElementName=root}" />
</StackPanel>

View file

@ -7,6 +7,7 @@ namespace Mesen.Controls
public class OptionSection : ItemsControl
{
public static readonly StyledProperty<string> HeaderProperty = AvaloniaProperty.Register<OptionSection, string>(nameof(Header));
public static readonly StyledProperty<object> ButtonProperty = AvaloniaProperty.Register<OptionSection, object>(nameof(Button));
public string Header
{
@ -14,6 +15,12 @@ namespace Mesen.Controls
set { SetValue(HeaderProperty, value); }
}
public object Button
{
get { return GetValue(ButtonProperty); }
set { SetValue(ButtonProperty, value); }
}
public OptionSection()
{
InitializeComponent();

View file

@ -0,0 +1,74 @@
using Avalonia.Controls;
using System;
using Mesen.Interop;
using Mesen.Config;
using System.Collections.Generic;
using System.Threading;
namespace Mesen.Debugger.Utilities
{
public static class ToolRefreshHelper
{
class ToolInfo
{
internal int ViewerId { get; set; } = 0;
internal int Scanline { get; set; } = 0;
internal int Cycle { get; set; } = 0;
}
private static Dictionary<Window, ToolInfo> _activeWindows = new();
private static int _nextId = 0;
private static int RegisterWindow(Window wnd, RefreshTimingConfig cfg, CpuType cpuType)
{
if(_activeWindows.ContainsKey(wnd)) {
throw new Exception("Register window called twice");
}
int newId = Interlocked.Increment(ref _nextId);
wnd.Closed += (s, e) => {
_activeWindows.Remove(wnd);
//TODO
//DebugApi.RemoveViewer(newId);
};
_activeWindows.Add(wnd, new ToolInfo() { ViewerId = newId, Scanline = cfg.RefreshScanline, Cycle = cfg.RefreshCycle });
DebugApi.SetViewerUpdateTiming(newId, cfg.RefreshScanline, cfg.RefreshCycle, cpuType);
return newId;
}
private static int GetViewerId(Window wnd, RefreshTimingConfig cfg, CpuType cpuType)
{
if(_activeWindows.TryGetValue(wnd, out ToolInfo? toolInfo)) {
if(cfg.RefreshScanline != toolInfo.Scanline || cfg.RefreshCycle != toolInfo.Cycle) {
toolInfo.Scanline = cfg.RefreshScanline;
toolInfo.Cycle = cfg.RefreshCycle;
DebugApi.SetViewerUpdateTiming(toolInfo.ViewerId, cfg.RefreshScanline, cfg.RefreshCycle, cpuType);
}
return toolInfo.ViewerId;
} else {
return RegisterWindow(wnd, cfg, cpuType);
}
}
public static void ProcessNotification(Window wnd, NotificationEventArgs e, RefreshTimingConfig cfg, CpuType cpuType, Action refresh)
{
int viewerId = GetViewerId(wnd, cfg, cpuType);
switch(e.NotificationType) {
case ConsoleNotificationType.ViewerRefresh:
if(cfg.AutoRefresh && e.Parameter.ToInt32() == viewerId) {
refresh();
}
break;
case ConsoleNotificationType.CodeBreak:
if(cfg.RefreshOnBreakPause) {
refresh();
}
break;
}
}
}
}

View file

@ -0,0 +1,51 @@
using Mesen.Config;
using Mesen.Interop;
using Mesen.ViewModels;
using ReactiveUI;
using System;
using System.Reactive;
namespace Mesen.Debugger.ViewModels
{
public class RefreshTimingViewModel : ViewModelBase
{
public RefreshTimingConfig Config { get; }
public int MinScanline { get; }
public int MaxScanline { get; }
public int MaxCycle { get; }
public ReactiveCommand<Unit, Unit> ResetCommand { get; }
[Obsolete("For designer only")]
public RefreshTimingViewModel() : this(new RefreshTimingConfig()) { }
public RefreshTimingViewModel(RefreshTimingConfig config)
{
Config = config;
TimingInfo timing = EmuApi.GetTimingInfo();
MinScanline = timing.FirstScanline;
MaxScanline = (int)timing.ScanlineCount + timing.FirstScanline - 1;
MaxCycle = (int)timing.CycleCount - 1;
config.RefreshScanline = Math.Max(MinScanline, Math.Min(MaxScanline, config.RefreshScanline));
config.RefreshCycle = Math.Min(MaxCycle, config.RefreshCycle);
ResetCommand = ReactiveCommand.Create(Reset);
}
public void Reset()
{
Config.RefreshScanline = EmuApi.GetRomInfo().ConsoleType switch {
ConsoleType.Snes => 240,
ConsoleType.Nes => 241,
ConsoleType.Gameboy => 144,
ConsoleType.GameboyColor => 144,
_ => throw new Exception("Invalid console type")
};
Config.RefreshCycle = 0;
}
}
}

View file

@ -23,6 +23,7 @@ namespace Mesen.Debugger.ViewModels
public ConsoleType ConsoleType { get; }
public TilemapViewerConfig Config { get; }
public RefreshTimingViewModel RefreshTiming { get; }
[Reactive] public Rect SelectionRect { get; set; }
@ -49,6 +50,8 @@ namespace Mesen.Debugger.ViewModels
public TilemapViewerViewModel(CpuType cpuType, ConsoleType consoleType, PictureViewer picViewer, Window? wnd)
{
Config = ConfigManager.Config.Debug.TilemapViewer;
RefreshTiming = new RefreshTimingViewModel(Config.RefreshTiming);
CpuType = cpuType;
ConsoleType = consoleType;
@ -98,13 +101,13 @@ namespace Mesen.Debugger.ViewModels
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.EnableAutoRefresh,
IsSelected = () => Config.AutoRefresh,
OnClick = () => Config.AutoRefresh = !Config.AutoRefresh
IsSelected = () => Config.RefreshTiming.AutoRefresh,
OnClick = () => Config.RefreshTiming.AutoRefresh = !Config.RefreshTiming.AutoRefresh
},
new ContextMenuAction() {
ActionType = ActionType.RefreshOnBreakPause,
IsSelected = () => Config.RefreshOnBreakPause,
OnClick = () => Config.RefreshOnBreakPause = !Config.RefreshOnBreakPause
IsSelected = () => Config.RefreshTiming.RefreshOnBreakPause,
OnClick = () => Config.RefreshTiming.RefreshOnBreakPause = !Config.RefreshTiming.RefreshOnBreakPause
},
new Separator(),
new ContextMenuAction() {
@ -177,13 +180,18 @@ namespace Mesen.Debugger.ViewModels
return;
}
GetTilemapOptions options = GetOptions(_prevVram);
BaseState ppuState = _ppuState;
byte[]? prevVram = _prevVram;
byte[] vram = _vram;
uint[] palette = _palette;
GetTilemapOptions options = GetOptions(prevVram);
FrameInfo size = DebugApi.GetTilemapSize(CpuType, options, _ppuState);
FrameInfo size = DebugApi.GetTilemapSize(CpuType, options, ppuState);
InitBitmap((int)size.Width, (int)size.Height);
using(var framebuffer = ViewerBitmap.Lock()) {
DebugApi.GetTilemap(CpuType, options, _ppuState, _vram, _palette, framebuffer.Address);
DebugApi.GetTilemap(CpuType, options, ppuState, vram, palette, framebuffer.Address);
}
_picViewer.InvalidateVisual();

View file

@ -0,0 +1,48 @@
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cfg="using:Mesen.Config"
xmlns:c="using:Mesen.Controls"
xmlns:dc="using:Mesen.Debugger.Controls"
xmlns:dvm="using:Mesen.Debugger.ViewModels"
xmlns:l="using:Mesen.Localization"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="410"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
x:DataType="dvm:RefreshTimingViewModel"
x:Class="Mesen.Debugger.Views.RefreshTimingView"
>
<Design.DataContext>
<dvm:RefreshTimingViewModel />
</Design.DataContext>
<c:OptionSection Header="{l:Translate lblTitle}">
<c:OptionSection.Button>
<c:IconButton
ToolTip.Tip="Reset to default"
Icon="Assets/Refresh.png"
Margin="5 0 0 2"
Command="{CompiledBinding ResetCommand}"
/>
</c:OptionSection.Button>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto">
<TextBlock VerticalAlignment="Center" Text="{l:Translate lblScanline}" />
<NumericUpDown
Grid.Column="1"
Value="{CompiledBinding Config.RefreshScanline}"
Minimum="{CompiledBinding MinScanline}"
Maximum="{CompiledBinding MaxScanline}"
/>
<TextBlock Grid.Row="2" VerticalAlignment="Center" Text="{l:Translate lblCycle}" />
<NumericUpDown
Grid.Row="2"
Grid.Column="1"
Value="{CompiledBinding Config.RefreshCycle}"
Minimum="0"
Maximum="{CompiledBinding MaxCycle}"
/>
</Grid>
</c:OptionSection>
</UserControl>

View file

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Mesen.Debugger.Views
{
public class RefreshTimingView : UserControl
{
public RefreshTimingView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View file

@ -9,9 +9,10 @@
xmlns:c="using:Mesen.Controls"
xmlns:i="using:Mesen.Interop"
xmlns:l="using:Mesen.Localization"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dvm="using:Mesen.Debugger.ViewModels"
xmlns:dc="using:Mesen.Debugger.Controls"
xmlns:dv="using:Mesen.Debugger.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="600"
x:Class="Mesen.Debugger.Windows.TilemapViewerWindow"
x:DataType="dvm:TilemapViewerViewModel"
@ -43,32 +44,34 @@
Icon="Assets/Settings.png"
/>
</Panel>
<StackPanel DockPanel.Dock="Right" IsVisible="{CompiledBinding Config.ShowSettingsPanel}">
<Grid
ColumnDefinitions="Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
Margin="5 0 5 0"
Width="180"
>
<TextBlock Text="{l:Translate lblDisplayMode}" />
<c:EnumComboBox Grid.Row="0" Grid.Column="1" EnumType="{x:Type i:TilemapDisplayMode}" SelectedItem="{CompiledBinding Config.DisplayMode}" />
<CheckBox Grid.Row="1" Grid.ColumnSpan="2" Content="{l:Translate chkShowGrid}" IsChecked="{CompiledBinding Config.ShowGrid}" />
<CheckBox Grid.Row="2" Grid.ColumnSpan="2" Content="{l:Translate chkShowAltGrid}" IsChecked="{CompiledBinding Config.ShowAltGrid}" />
<CheckBox Grid.Row="3" Grid.ColumnSpan="2" Content="{l:Translate chkHighlightTileChanges}" IsChecked="{CompiledBinding Config.HighlightTileChanges}" />
<CheckBox Grid.Row="4" Grid.ColumnSpan="2" Content="{l:Translate chkHighlightAttributeChanges}" IsChecked="{CompiledBinding Config.HighlightAttributeChanges}" />
</Grid>
<Panel DockPanel.Dock="Right" IsVisible="{CompiledBinding Config.ShowSettingsPanel}">
<ScrollViewer>
<StackPanel Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{l:Translate lblDisplayMode}" />
<c:EnumComboBox Grid.Row="0" Grid.Column="1" EnumType="{x:Type i:TilemapDisplayMode}" SelectedItem="{CompiledBinding Config.DisplayMode}" Width="100" />
</StackPanel>
<CheckBox Content="{l:Translate chkShowGrid}" IsChecked="{CompiledBinding Config.ShowGrid}" />
<CheckBox Content="{l:Translate chkShowAltGrid}" IsChecked="{CompiledBinding Config.ShowAltGrid}" />
<CheckBox Content="{l:Translate chkShowScrollOverlay}" IsChecked="{CompiledBinding Config.ShowScrollOverlay}" />
<CheckBox Content="{l:Translate chkHighlightTileChanges}" IsChecked="{CompiledBinding Config.HighlightTileChanges}" />
<CheckBox Content="{l:Translate chkHighlightAttributeChanges}" IsChecked="{CompiledBinding Config.HighlightAttributeChanges}" />
<Border
BorderBrush="Gray"
BorderThickness="1"
Margin="3"
Padding="3"
IsVisible="{CompiledBinding PreviewPanel, Converter={x:Static ObjectConverters.IsNotNull}}"
>
<ContentControl Content="{CompiledBinding PreviewPanel}" Margin="0 0 10 0"/>
</Border>
</StackPanel>
<dv:RefreshTimingView DataContext="{CompiledBinding RefreshTiming}" />
<Border
BorderBrush="Gray"
BorderThickness="1"
Margin="0 10"
Padding="3"
IsVisible="{CompiledBinding PreviewPanel, Converter={x:Static ObjectConverters.IsNotNull}}"
>
<ContentControl Content="{CompiledBinding PreviewPanel}" Margin="0 0 10 0"/>
</Border>
</StackPanel>
</ScrollViewer>
</Panel>
<TabControl
Items="{CompiledBinding Tabs}"
SelectedItem="{CompiledBinding SelectedTab}"

View file

@ -13,6 +13,7 @@ using Mesen.Interop;
using System.ComponentModel;
using Avalonia.Input;
using Avalonia.Interactivity;
using Mesen.Debugger.Utilities;
namespace Mesen.Debugger.Windows
{
@ -35,6 +36,7 @@ namespace Mesen.Debugger.Windows
_picViewer = this.FindControl<PictureViewer>("picViewer");
_model = new TilemapViewerViewModel(cpuType, consoleType, _picViewer, this);
DataContext = _model;
_model.Config.LoadWindowSettings(this);
_listener = new NotificationListener();
@ -103,19 +105,7 @@ namespace Mesen.Debugger.Windows
private void listener_OnNotification(NotificationEventArgs e)
{
switch(e.NotificationType) {
case ConsoleNotificationType.EventViewerRefresh:
if(_model.Config.AutoRefresh) {
_model.RefreshData();
}
break;
case ConsoleNotificationType.CodeBreak:
if(_model.Config.RefreshOnBreakPause) {
_model.RefreshData();
}
break;
}
ToolRefreshHelper.ProcessNotification(this, e, _model.Config.RefreshTiming, _model.CpuType, _model.RefreshData);
}
}
}

View file

@ -124,6 +124,10 @@ namespace Mesen.Interop
public UInt64 MasterClock;
public UInt32 MasterClockRate;
public UInt32 FrameCount;
public UInt32 ScanlineCount;
public Int32 FirstScanline;
public UInt32 CycleCount;
}
public struct FrameInfo

View file

@ -794,6 +794,7 @@
<Control ID="chkShowAltGrid">Show attribute grid</Control>
<Control ID="chkHighlightTileChanges">Highlight tile changes</Control>
<Control ID="chkHighlightAttributeChanges">Highlight attribute changes</Control>
<Control ID="chkShowScrollOverlay">Show scroll overlay</Control>
</Form>
<Form ID="SpriteViewerWindow">
@ -910,6 +911,12 @@
<Control ID="lblSize">Size: </Control>
</Form>
<Form ID="RefreshTimingView">
<Control ID="lblTitle">Auto-refresh timing</Control>
<Control ID="lblScanline">Scanline (V): </Control>
<Control ID="lblCycle">Cycle (H): </Control>
</Form>
<Form ID="DebuggerConfigWindow">
<Control ID="tabDebugger">Debugger</Control>
<Control ID="lblGeneralSettings">General settings</Control>

View file

@ -216,6 +216,9 @@
<Compile Update="Debugger\Views\DebuggerOptionsView.axaml.cs">
<DependentUpon>DebuggerOptionsView.axaml</DependentUpon>
</Compile>
<Compile Update="Debugger\Views\RefreshTimingView.axaml.cs">
<DependentUpon>RefreshTimingView.axaml</DependentUpon>
</Compile>
<Compile Update="Debugger\Views\FontOptionsView.axaml.cs">
<DependentUpon>FontOptionsView.axaml</DependentUpon>
</Compile>