diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 58d70a305f..810328def3 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -235,7 +235,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
uint samplesEmitted = TICKSINFRAME - frameOverflow; // according to gambatte docs, this is the nominal length of a frame in 2mhz clocks
System.Diagnostics.Debug.Assert(samplesEmitted * 2 <= soundbuff.Length);
- LibGambatte.gambatte_runfor(GambatteState, VideoBuffer, 160, soundbuff, ref samplesEmitted);
+ if (LibGambatte.gambatte_runfor(GambatteState, soundbuff, ref samplesEmitted) > 0)
+ {
+ LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160);
+ }
_cycleCount += (ulong)samplesEmitted;
frameOverflow += samplesEmitted;
@@ -431,7 +434,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
uint nlen = 0;
IntPtr ndata = IntPtr.Zero;
- if (!LibGambatte.gambatte_savestate(GambatteState, VideoBuffer, 160, ref ndata, ref nlen))
+ if (!LibGambatte.gambatte_savestate(GambatteState, ref ndata, ref nlen))
throw new Exception("Gambatte failed to save the savestate!");
if (nlen == 0)
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
index 1027f30636..460ba48429 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
@@ -151,13 +151,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
while (nL < target)
{
uint nsamp = (uint)(target - nL);
- LibGambatte.gambatte_runfor(L.GambatteState, leftvbuff, pitch, leftsbuff + nL * 2, ref nsamp);
+ if (LibGambatte.gambatte_runfor(L.GambatteState, leftsbuff + nL * 2, ref nsamp) > 0)
+ LibGambatte.gambatte_blitto(L.GambatteState, leftvbuff, pitch);
nL += (int)nsamp;
}
while (nR < target)
{
uint nsamp = (uint)(target - nR);
- LibGambatte.gambatte_runfor(R.GambatteState, rightvbuff, pitch, rightsbuff + nR * 2, ref nsamp);
+ if (LibGambatte.gambatte_runfor(R.GambatteState, rightsbuff + nR * 2, ref nsamp) > 0)
+ LibGambatte.gambatte_blitto(R.GambatteState, rightvbuff, pitch);
nR += (int)nsamp;
}
// poll link cable statuses
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
index cffd2462b4..d4a57ed26b 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
@@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// Use GBA intial CPU register values when in CGB mode.
GBA_CGB = 2,
/// Use heuristics to detect and support some multicart MBCs disguised as MBC1.
- MULTICART_COMPAT = 4
+ MULTICART_COMPAT = 4
}
///
@@ -60,15 +60,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// exact time (in number of samples) at which it was drawn.
///
/// opaque state pointer
- /// 160x144 RGB32 (native endian) video frame buffer or null
- /// distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
/// buffer with space >= samples + 2064
/// in: number of stereo samples to produce, out: actual number of samples produced
/// sample number at which the video frame was produced. -1 means no frame was produced.
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int gambatte_runfor(IntPtr core, int[] videobuf, int pitch, short[] soundbuf, ref uint samples);
+ public static extern int gambatte_runfor(IntPtr core, short[] soundbuf, ref uint samples);
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- unsafe public static extern int gambatte_runfor(IntPtr core, int* videobuf, int pitch, short* soundbuf, ref uint samples);
+ unsafe public static extern int gambatte_runfor(IntPtr core, short* soundbuf, ref uint samples);
+
+ ///
+ /// blit from internal framebuffer to provided framebuffer
+ ///
+ /// opaque state pointer
+ ///
+ /// in pixels
+ [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
+ unsafe public static extern void gambatte_blitto(IntPtr core, int* videobuf, int pitch);
+ ///
+ /// blit from internal framebuffer to provided framebuffer
+ ///
+ /// opaque state pointer
+ ///
+ /// in pixels
+ [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gambatte_blitto(IntPtr core, int[] videobuf, int pitch);
///
/// Reset to initial state.
@@ -112,7 +127,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
///
[Flags]
public enum Buttons
- {
+ {
A = 0x01,
B = 0x02,
SELECT = 0x04,
@@ -268,13 +283,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// Saves emulator state to a byte array
///
/// opaque state pointer
- /// 160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail. NOT USED ANYMORE
- /// distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
/// private savestate data returned by the core
/// the length of the data in bytes
/// success
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern bool gambatte_savestate(IntPtr core, int[] videobuf, int pitch, ref IntPtr data, ref uint len);
+ public static extern bool gambatte_savestate(IntPtr core, ref IntPtr data, ref uint len);
///
/// destroy data returned by gambatte_savestate() to avoid memory leaks
@@ -293,43 +306,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gambatte_loadstate(IntPtr core, byte[] data, uint len);
- ///
- /// Saves emulator state to the file given by 'filepath'.
- ///
- /// opaque state pointer
- /// 160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail.
- /// distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
- ///
- /// success
- //[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- //public static extern bool gambatte_savestate_file(IntPtr core, int[] videobuf, int pitch, string filepath);
-
- ///
- /// Loads emulator state from the file given by 'filepath'.
- ///
- /// opaque state pointer
- ///
- /// success
- //[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- //public static extern bool gambatte_loadstate_file(IntPtr core, string filepath);
-
- ///
- /// Selects which state slot to save state to or load state from.
- /// There are 10 such slots, numbered from 0 to 9 (periodically extended for all n).
- ///
- /// opaque state pointer
- ///
- //[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- //public static extern void gambatte_selectstate(IntPtr core, int n);
-
- ///
- /// Current state slot selected with selectState(). Returns a value between 0 and 9 inclusive.
- ///
- /// opaque state pointer
- ///
- //[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- //public static extern int gambatte_currentstate(IntPtr core);
-
///
/// ROM header title of currently loaded ROM image.
///
diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
index 51868a5b2e..2e4a65dd2b 100644
--- a/libgambatte/include/gambatte.h
+++ b/libgambatte/include/gambatte.h
@@ -62,15 +62,14 @@ public:
* The return value indicates whether a new video frame has been drawn, and the
* exact time (in number of samples) at which it was drawn.
*
- * @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0
- * @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
* @param soundBuf buffer with space >= samples + 2064
* @param samples in: number of stereo samples to produce, out: actual number of samples produced
* @return sample number at which the video frame was produced. -1 means no frame was produced.
*/
- long runFor(gambatte::uint_least32_t *videoBuf, int pitch,
- gambatte::uint_least32_t *soundBuf, unsigned &samples);
-
+ long runFor(gambatte::uint_least32_t *soundBuf, unsigned &samples);
+
+ void blitTo(gambatte::uint_least32_t *videoBuf, int pitch);
+
/** Reset to initial state.
* Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
*/
@@ -109,20 +108,6 @@ public:
// 0 = vram, 1 = rom, 2 = wram, 3 = cartram, 4 = oam, 5 = hram
bool getMemoryArea(int which, unsigned char **data, int *length);
-
- /** Saves emulator state to the state slot selected with selectState().
- * The data will be stored in the directory given by setSaveDir().
- *
- * @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail.
- * @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
- * @return success
- */
- //bool saveState(const gambatte::uint_least32_t *videoBuf, int pitch);
-
- /** Loads emulator state from the state slot selected with selectState().
- * @return success
- */
- //bool loadState();
/** Saves emulator state to the file given by 'filepath'.
*
@@ -130,7 +115,7 @@ public:
* @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
* @return success
*/
- bool saveState(const gambatte::uint_least32_t *videoBuf, int pitch, std::ostream &file);
+ bool saveState(std::ostream &file);
/** Loads emulator state from the file given by 'filepath'.
* @return success
diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp
index 4e72a1f7c8..242dda2aef 100644
--- a/libgambatte/src/cinterface.cpp
+++ b/libgambatte/src/cinterface.cpp
@@ -24,15 +24,21 @@ __declspec(dllexport) int gambatte_load(void *core, const char *romfiledata, uns
return ret;
}
-__declspec(dllexport) long gambatte_runfor(void *core, unsigned long *videobuf, int pitch, short *soundbuf, unsigned *samples)
+__declspec(dllexport) long gambatte_runfor(void *core, short *soundbuf, unsigned *samples)
{
GB *g = (GB *) core;
unsigned sampv = *samples;
- long ret = g->runFor((unsigned int*)videobuf, pitch, (unsigned int *) soundbuf, sampv);
+ long ret = g->runFor((unsigned int *) soundbuf, sampv);
*samples = sampv;
return ret;
}
+__declspec(dllexport) void gambatte_blitto(void *core, unsigned long *videobuf, int pitch)
+{
+ GB *g = (GB *) core;
+ g->blitTo((unsigned int *)videobuf, pitch);
+}
+
__declspec(dllexport) void gambatte_reset(void *core, long long now)
{
GB *g = (GB *) core;
@@ -151,26 +157,12 @@ __declspec(dllexport) int gambatte_savesavedatalength(void *core)
return g->saveSavedataLength();
}
-/*
-__declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch)
-{
- GB *g = (GB *) core;
- return g->saveState(videobuf, pitch);
-}
-
-__declspec(dllexport) int gambatte_loadstate(void *core)
-{
- GB *g = (GB *) core;
- return g->loadState();
-}
-*/
-
-__declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch, char **data, unsigned *len)
+__declspec(dllexport) int gambatte_savestate(void *core, char **data, unsigned *len)
{
GB *g = (GB *) core;
std::ostringstream os = std::ostringstream(std::ios_base::binary | std::ios_base::out);
- if (!g->saveState((const unsigned int*)videobuf, pitch, os))
+ if (!g->saveState(os))
return 0;
os.flush();
@@ -193,20 +185,6 @@ __declspec(dllexport) int gambatte_loadstate(void *core, const char *data, unsig
return g->loadState(std::istringstream(std::string(data, len), std::ios_base::binary | std::ios_base::in));
}
-/*
-__declspec(dllexport) void gambatte_selectstate(void *core, int n)
-{
- GB *g = (GB *) core;
- g->selectState(n);
-}
-
-__declspec(dllexport) int gambatte_currentstate(void *core)
-{
- GB *g = (GB *) core;
- return g->currentState();
-}
-*/
-
static char horriblebuff[64];
__declspec(dllexport) const char *gambatte_romtitle(void *core)
{
diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h
index 3f0bae5056..57cc1e16f2 100644
--- a/libgambatte/src/cinterface.h
+++ b/libgambatte/src/cinterface.h
@@ -10,7 +10,8 @@ extern "C"
__declspec(dllexport) int gambatte_load(void *core, const char *romfiledata, unsigned romfilelength, long long now, unsigned flags);
- __declspec(dllexport) long gambatte_runfor(void *core, unsigned long *videobuf, int pitch, short *soundbuf, unsigned *samples);
+ __declspec(dllexport) long gambatte_runfor(void *core, short *soundbuf, unsigned *samples);
+ __declspec(dllexport) void gambatte_blitto(void *core, unsigned long *videobuf, int pitch);
__declspec(dllexport) void gambatte_reset(void *core, long long now);
@@ -46,7 +47,7 @@ extern "C"
//__declspec(dllexport) int gambatte_loadstate(void *core);
- __declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch, char **data, unsigned *len);
+ __declspec(dllexport) int gambatte_savestate(void *core, char **data, unsigned *len);
__declspec(dllexport) void gambatte_savestate_destroy(char *data);
__declspec(dllexport) int gambatte_loadstate(void *core, const char *data, unsigned len);
diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
index 5676ac2c8f..89a00dbfe1 100644
--- a/libgambatte/src/gambatte.cpp
+++ b/libgambatte/src/gambatte.cpp
@@ -39,8 +39,18 @@ struct GB::Priv {
CPU cpu;
int stateNo;
bool gbaCgbMode;
+
+ gambatte::uint_least32_t *vbuff;
- Priv() : stateNo(1), gbaCgbMode(false) {}
+ Priv() : stateNo(1), gbaCgbMode(false)
+ {
+ vbuff = new gambatte::uint_least32_t[160*144];
+ }
+
+ ~Priv()
+ {
+ delete[] vbuff;
+ }
};
GB::GB() : p_(new Priv) {}
@@ -52,14 +62,13 @@ GB::~GB() {
delete p_;
}
-long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch,
- gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
+long GB::runFor(gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
if (!p_->cpu.loaded()) {
samples = 0;
return -1;
}
- p_->cpu.setVideoBuffer(videoBuf, pitch);
+ p_->cpu.setVideoBuffer(p_->vbuff, 160);
p_->cpu.setSoundBuffer(soundBuf);
const long cyclesSinceBlit = p_->cpu.runFor(samples * 2);
samples = p_->cpu.fillSoundBuffer();
@@ -67,6 +76,19 @@ long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch,
return cyclesSinceBlit < 0 ? cyclesSinceBlit : static_cast(samples) - (cyclesSinceBlit >> 1);
}
+void GB::blitTo(gambatte::uint_least32_t *videoBuf, int pitch)
+{
+ gambatte::uint_least32_t *src = p_->vbuff;
+ gambatte::uint_least32_t *dst = videoBuf;
+
+ for (int i = 0; i < 144; i++)
+ {
+ std::memcpy(dst, src, sizeof(gambatte::uint_least32_t) * 160);
+ src += 160;
+ dst += pitch;
+ }
+}
+
void GB::reset(const std::uint32_t now) {
if (p_->cpu.loaded()) {
@@ -201,37 +223,23 @@ bool GB::loadState(std::istream &file) {
if (StateSaver::loadState(state, file)) {
p_->cpu.loadState(state);
+ file.read((char *)p_->vbuff, 160 * 144 * 4); // yes, sloppy
return true;
}
}
return false;
}
-/*
-bool GB::saveState(const gambatte::uint_least32_t *const videoBuf, const int pitch) {
- if (saveState(videoBuf, pitch, statePath(p_->cpu.saveBasePath(), p_->stateNo))) {
- p_->cpu.setOsdElement(newStateSavedOsdElement(p_->stateNo));
- return true;
- }
- return false;
-}
-
-bool GB::loadState() {
- if (loadState(statePath(p_->cpu.saveBasePath(), p_->stateNo))) {
- p_->cpu.setOsdElement(newStateLoadedOsdElement(p_->stateNo));
- return true;
- }
-
- return false;
-}
-*/
-bool GB::saveState(const gambatte::uint_least32_t *const videoBuf, const int pitch, std::ostream &file) {
+bool GB::saveState(std::ostream &file) {
if (p_->cpu.loaded()) {
SaveState state;
p_->cpu.setStatePtrs(state);
p_->cpu.saveState(state);
- return StateSaver::saveState(state, videoBuf, pitch, file);
+ bool ret = StateSaver::saveState(state, file);
+ if (ret)
+ file.write((const char *)p_->vbuff, 160 * 144 * 4); // yes, sloppy
+ return ret;
}
return false;
diff --git a/libgambatte/src/statesaver.cpp b/libgambatte/src/statesaver.cpp
index 1640b82428..d8c3131a13 100644
--- a/libgambatte/src/statesaver.cpp
+++ b/libgambatte/src/statesaver.cpp
@@ -410,9 +410,7 @@ static SaverList list;
namespace gambatte {
-bool StateSaver::saveState(const SaveState &state,
- const uint_least32_t *const videoBuf,
- const int pitch, std::ostream &file) {
+bool StateSaver::saveState(const SaveState &state, std::ostream &file) {
//std::ostream file(filename.c_str(), std::ios_base::binary);
if (file.fail())
diff --git a/libgambatte/src/statesaver.h b/libgambatte/src/statesaver.h
index dec12fc998..46f2817603 100644
--- a/libgambatte/src/statesaver.h
+++ b/libgambatte/src/statesaver.h
@@ -35,8 +35,7 @@ public:
enum { SS_WIDTH = 160 >> SS_SHIFT };
enum { SS_HEIGHT = 144 >> SS_SHIFT };
- static bool saveState(const SaveState &state,
- const uint_least32_t *videoBuf, int pitch, std::ostream &file);
+ static bool saveState(const SaveState &state, std::ostream &file);
static bool loadState(SaveState &state, std::istream &file);
};
diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll
index 9b974c9fd8..2f5e11e7ed 100644
Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ