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"