diff --git a/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.Designer.cs b/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.Designer.cs index 0f0edca4d1..0cb07faeec 100644 --- a/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.Designer.cs @@ -39,7 +39,6 @@ this.hScrollBar1 = new System.Windows.Forms.HScrollBar(); this.radioButtonManual = new System.Windows.Forms.RadioButton(); this.radioButtonScanline = new System.Windows.Forms.RadioButton(); - this.radioButtonFrame = new System.Windows.Forms.RadioButton(); this.labelClipboard = new System.Windows.Forms.Label(); this.timerMessage = new System.Windows.Forms.Timer(this.components); this.groupBox1.SuspendLayout(); @@ -90,7 +89,6 @@ this.groupBox1.Controls.Add(this.hScrollBar1); this.groupBox1.Controls.Add(this.radioButtonManual); this.groupBox1.Controls.Add(this.radioButtonScanline); - this.groupBox1.Controls.Add(this.radioButtonFrame); this.groupBox1.Location = new System.Drawing.Point(15, 220); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(134, 133); @@ -141,17 +139,6 @@ this.radioButtonScanline.UseVisualStyleBackColor = true; this.radioButtonScanline.CheckedChanged += new System.EventHandler(this.radioButtonScanline_CheckedChanged); // - // radioButtonFrame - // - this.radioButtonFrame.AutoSize = true; - this.radioButtonFrame.Location = new System.Drawing.Point(6, 19); - this.radioButtonFrame.Name = "radioButtonFrame"; - this.radioButtonFrame.Size = new System.Drawing.Size(54, 17); - this.radioButtonFrame.TabIndex = 0; - this.radioButtonFrame.Text = "Frame"; - this.radioButtonFrame.UseVisualStyleBackColor = true; - this.radioButtonFrame.CheckedChanged += new System.EventHandler(this.radioButtonFrame_CheckedChanged); - // // labelClipboard // this.labelClipboard.AutoSize = true; @@ -205,7 +192,6 @@ private System.Windows.Forms.HScrollBar hScrollBar1; private System.Windows.Forms.RadioButton radioButtonManual; private System.Windows.Forms.RadioButton radioButtonScanline; - private System.Windows.Forms.RadioButton radioButtonFrame; private System.Windows.Forms.Label labelClipboard; private System.Windows.Forms.Timer timerMessage; diff --git a/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.cs b/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.cs index 67b2f8094c..358bd06a86 100644 --- a/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.cs +++ b/BizHawk.Client.EmuHawk/tools/GBA/GBAGPUView.cs @@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk { public partial class GBAGPUView : Form, IToolForm { - GBA gba; + IGBAGPUViewable gba; // emulator memory areas private IntPtr vram; @@ -37,9 +37,8 @@ namespace BizHawk.Client.EmuHawk ColorConversion = new int[65536]; Buffer.BlockCopy(tmp, 0, ColorConversion, 0, sizeof(int) * tmp.Length); Buffer.BlockCopy(tmp, 0, ColorConversion, sizeof(int) * tmp.Length, sizeof(int) * tmp.Length); - + radioButtonManual.Checked = true; GenerateWidgets(); - radioButtonFrame.Checked = true; hScrollBar1_ValueChanged(null, null); RecomputeRefresh(); } @@ -680,10 +679,14 @@ namespace BizHawk.Client.EmuHawk public void Restart() { - gba = Global.Emulator as GBA; + gba = Global.Emulator as IGBAGPUViewable; if (gba != null) { - gba.GetGPUMemoryAreas(out vram, out palram, out oam, out mmio); + var mem = gba.GetMemoryAreas(); + vram = mem.vram; + palram = mem.palram; + oam = mem.oam; + mmio = mem.mmio; } else { @@ -702,17 +705,13 @@ namespace BizHawk.Client.EmuHawk if (_cbscanlineEmu != _cbscanline) { _cbscanlineEmu = _cbscanline; - if (_cbscanline == -2) // manual, do nothing + if (!_cbscanline.HasValue) // manual, deactivate callback { - gba.SetScanlineCallback(null, null); - } - else if (_cbscanline == -1) // end of frame - { - gba.SetScanlineCallback(DrawEverything, null); + gba.SetScanlineCallback(null, 0); } else { - gba.SetScanlineCallback(DrawEverything, _cbscanline); + gba.SetScanlineCallback(DrawEverything, _cbscanline.Value); } } } @@ -751,18 +750,12 @@ namespace BizHawk.Client.EmuHawk #region refresh control - private int _cbscanline; - private int _cbscanlineEmu = 500; + private int? _cbscanline = null; + private int? _cbscanlineEmu = 500; private void RecomputeRefresh() { - if (radioButtonFrame.Checked) - { - hScrollBar1.Enabled = false; - buttonRefresh.Enabled = false; - _cbscanline = -1; - } - else if (radioButtonScanline.Checked) + if (radioButtonScanline.Checked) { hScrollBar1.Enabled = true; buttonRefresh.Enabled = false; @@ -772,7 +765,7 @@ namespace BizHawk.Client.EmuHawk { hScrollBar1.Enabled = false; buttonRefresh.Enabled = true; - _cbscanline = -2; + _cbscanline = null; } } @@ -808,7 +801,7 @@ namespace BizHawk.Client.EmuHawk { if (gba != null) { - gba.SetScanlineCallback(null, null); + gba.SetScanlineCallback(null, 0); gba = null; } } diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 5755c00d99..d8ad73899d 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -237,6 +237,7 @@ + diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/IGBAGPUViewable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/IGBAGPUViewable.cs new file mode 100644 index 0000000000..5b02766743 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/IGBAGPUViewable.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Cores.Nintendo.GBA +{ + public interface IGBAGPUViewable + { + GBAGPUMemoryAreas GetMemoryAreas(); + /// + /// calls correspond to entering hblank (maybe) and in a regular frame, the sequence of calls will be 160, 161, ..., 227, 0, ..., 159 + /// + /// + /// + void SetScanlineCallback(Action callback, int scanline); + } + + public class GBAGPUMemoryAreas + { + public IntPtr vram; + public IntPtr oam; + public IntPtr mmio; + public IntPtr palram; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs index 6977b50dcf..e0acf4f219 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs @@ -130,6 +130,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA [DllImport(dllname, CallingConvention = cc)] public static extern byte SystemBusRead(IntPtr g, int addr); + [UnmanagedFunctionPointer(cc)] + public delegate void StandardCallback(); + + [DllImport(dllname, CallingConvention = cc)] + public static extern void SetScanlineCallback(IntPtr g, StandardCallback cb, int scanline); + [StructLayout(LayoutKind.Sequential)] public class MemoryAreas diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs index b387aae8a6..ca98a34ef0 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA isPorted: true, isReleased: false )] - public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider + public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable { public Dictionary GetCpuFlagsAndRegisters() { @@ -83,8 +83,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA LibMeteor.libmeteor_frameadvance(); if (IsLagFrame) LagCount++; - if (EndOfFrameCallback != null) - EndOfFrameCallback(); } public int Frame { get; private set; } @@ -306,22 +304,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA MemoryDomains = new MemoryDomainList(_MemoryDomains); } - public void GetGPUMemoryAreas(out IntPtr vram, out IntPtr palram, out IntPtr oam, out IntPtr mmio) - { - IntPtr _vram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.vram); - IntPtr _palram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.palram); - IntPtr _oam = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.oam); - IntPtr _mmio = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.io); - - if (_vram == IntPtr.Zero || _palram == IntPtr.Zero || _oam == IntPtr.Zero || _mmio == IntPtr.Zero) - throw new Exception("libmeteor_getmemoryarea() failed!"); - - vram = _vram; - palram = _palram; - oam = _oam; - mmio = _mmio; - } - #endregion /// like libsnes, the library is single-instance @@ -438,40 +420,45 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA CoreComm.Tracer.Put(msg); } - Action EndOfFrameCallback = null; - LibMeteor.ScanlineCallback scanlinecb = null; - - /// - /// - /// - /// null to cancel - /// 0-227, null = end of frame - public void SetScanlineCallback(Action callback, int? scanline) + GBAGPUMemoryAreas IGBAGPUViewable.GetMemoryAreas() { - if (callback == null) + IntPtr _vram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.vram); + IntPtr _palram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.palram); + IntPtr _oam = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.oam); + IntPtr _mmio = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.io); + + if (_vram == IntPtr.Zero || _palram == IntPtr.Zero || _oam == IntPtr.Zero || _mmio == IntPtr.Zero) + throw new Exception("libmeteor_getmemoryarea() failed!"); + + return new GBAGPUMemoryAreas { - LibMeteor.libmeteor_setscanlinecallback(null, 400); - EndOfFrameCallback = null; - scanlinecb = null; - } - else if (scanline == null) - { - LibMeteor.libmeteor_setscanlinecallback(null, 400); - EndOfFrameCallback = callback; - scanlinecb = null; - } - else if (scanline >= 0 && scanline <= 227) - { - scanlinecb = new LibMeteor.ScanlineCallback(callback); - LibMeteor.libmeteor_setscanlinecallback(scanlinecb, (int)scanline); - EndOfFrameCallback = null; - } - else + vram = _vram, + palram = _palram, + oam = _oam, + mmio = _mmio + }; + } + + void IGBAGPUViewable.SetScanlineCallback(Action callback, int scanline) + { + if (scanline < 0 || scanline > 227) { throw new ArgumentOutOfRangeException("Scanline must be in [0, 227]!"); } + if (callback == null) + { + scanlinecb = null; + LibMeteor.libmeteor_setscanlinecallback(null, 0); + } + else + { + scanlinecb = new LibMeteor.ScanlineCallback(callback); + LibMeteor.libmeteor_setscanlinecallback(scanlinecb, scanline); + } } + LibMeteor.ScanlineCallback scanlinecb = null; + void Init() { if (attachedcore != null) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index fb251ba7f5..80eee33b91 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -14,7 +14,7 @@ using BizHawk.Common; namespace BizHawk.Emulation.Cores.Nintendo.GBA { [CoreAttributes("VBA-Next", "TODO", true, false, "cd508312a29ed8c29dacac1b11c2dce56c338a54", "https://github.com/libretro/vba-next")] - public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider + public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable { IntPtr Core; @@ -254,6 +254,39 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA #region Debugging + LibVBANext.StandardCallback scanlinecb; + + GBAGPUMemoryAreas IGBAGPUViewable.GetMemoryAreas() + { + var s = new LibVBANext.MemoryAreas(); + LibVBANext.GetMemoryAreas(Core, s); + return new GBAGPUMemoryAreas + { + mmio = s.mmio, + oam = s.oam, + palram = s.palram, + vram = s.vram + }; + } + + void IGBAGPUViewable.SetScanlineCallback(Action callback, int scanline) + { + if (scanline < 0 || scanline > 227) + { + throw new ArgumentOutOfRangeException("Scanline must be in [0, 227]!"); + } + if (callback == null) + { + scanlinecb = null; + LibVBANext.SetScanlineCallback(Core, scanlinecb, 0); + } + else + { + scanlinecb = new LibVBANext.StandardCallback(callback); + LibVBANext.SetScanlineCallback(Core, scanlinecb, scanline); + } + } + void InitMemoryDomains() { var mm = new List(); diff --git a/output/dll/libvbanext.dll b/output/dll/libvbanext.dll index afa0071028..12ebecefc7 100644 Binary files a/output/dll/libvbanext.dll and b/output/dll/libvbanext.dll differ diff --git a/vbanext/instance.cpp b/vbanext/instance.cpp index 44626f4ca0..1775b9e293 100644 --- a/vbanext/instance.cpp +++ b/vbanext/instance.cpp @@ -12548,6 +12548,8 @@ updateLoop: io_registers[REG_IF] |= 2; UPDATE_REG(0x202, io_registers[REG_IF]); } + if (scanlineCallback && scanlineCallbackLine == io_registers[REG_VCOUNT]) + scanlineCallback(); } if(io_registers[REG_VCOUNT] >= 228) @@ -12565,7 +12567,6 @@ updateLoop: // if in H-Blank, leave it and move to drawing mode io_registers[REG_VCOUNT] += 1; UPDATE_REG(0x06, io_registers[REG_VCOUNT]); - graphics.lcdTicks += 1008; io_registers[REG_DISPSTAT] &= 0xFFFD; if(io_registers[REG_VCOUNT] == 160) @@ -12643,6 +12644,8 @@ updateLoop: io_registers[REG_IF] |= 2; UPDATE_REG(0x202, io_registers[REG_IF]); } + if (scanlineCallback && scanlineCallbackLine == io_registers[REG_VCOUNT]) + scanlineCallback(); } } @@ -12936,6 +12939,9 @@ s16 *systemAudioFrameDest; int *systemAudioFrameSamp; bool lagged; +void (*scanlineCallback)(); +int scanlineCallbackLine; + void systemDrawScreen (void) { // upconvert 555->888 (TODO: BETTER) @@ -13342,6 +13348,17 @@ templatebool SyncBatteryRam(NewState *ns) return CPUReadByte(addr); } + void SetScanlineCallback(void (*cb)(), int scanline) + { + // the sequence of calls in a frame will be: + // 160,161,...,227,0,1,...,160 + // calls coincide with entering hblank, or something like that + if (scanline < 0 || scanline > 227) + cb = nullptr; + scanlineCallback = cb; + scanlineCallbackLine = scanline; + } + }; // class Gigazoid // zeroing mem operators: these are very important @@ -13483,4 +13500,9 @@ EXPORT u8 SystemBusRead(Gigazoid *g, u32 addr) return g->BusRead(addr); } +EXPORT void SetScanlineCallback(Gigazoid *g, void (*cb)(), int scanline) +{ + g->SetScanlineCallback(cb, scanline); +} + #include "optable.inc"