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