saturn: savestates. rather unwieldly, taking ~11MiB in text form and causing a noticable pause to save or load. core changes to support savestating: savestates reverted to version 1 (no movie info and no framebuffer, both of which are handled in bizhawk), and parts dealing with verifiying size through liberal use of fseek() (which doesn't work here) removed

This commit is contained in:
goyuken 2013-05-02 23:35:12 +00:00
parent 99ff09555e
commit b399e87ffe
7 changed files with 185 additions and 33 deletions

View File

@ -38,6 +38,39 @@ namespace BizHawk.Emulation.Consoles.Sega.Saturn
PipeName = "BizHawk-" + Guid.NewGuid().ToString();
}
public void Get(Stream s)
{
if (thr != null)
throw new Exception("Can only serve one thing at a time!");
if (e != null)
throw new Exception("Previous attempt failed!", e);
if (!s.CanWrite)
throw new ArgumentException("Stream must be readable!");
using (var evt = new ManualResetEventSlim())
{
thr = new Thread(delegate()
{
try
{
using (var srv = new NamedPipeServerStream(PipeName, PipeDirection.In))
{
evt.Set();
srv.WaitForConnection();
srv.CopyTo(s);
//srv.Flush();
}
}
catch (Exception ee)
{
e = ee;
}
});
thr.Start();
evt.Wait();
}
}
public void Offer(Stream s)
{
if (thr != null)
@ -47,23 +80,28 @@ namespace BizHawk.Emulation.Consoles.Sega.Saturn
if (!s.CanRead)
throw new ArgumentException("Stream must be readable!");
thr = new Thread(delegate()
{
try
using (var evt = new ManualResetEventSlim())
{
thr = new Thread(delegate()
{
using (var srv = new NamedPipeServerStream(PipeName, PipeDirection.Out))
try
{
srv.WaitForConnection();
s.CopyTo(srv);
srv.WaitForPipeDrain();
using (var srv = new NamedPipeServerStream(PipeName, PipeDirection.Out))
{
evt.Set();
srv.WaitForConnection();
s.CopyTo(srv);
srv.WaitForPipeDrain();
}
}
}
catch (Exception ee)// might want to do something about this...
{
e = ee;
}
});
thr.Start();
catch (Exception ee)
{
e = ee;
}
});
thr.Start();
evt.Wait();
}
}
public Exception GetResults()

View File

@ -66,6 +66,28 @@ namespace BizHawk.Emulation.Consoles.Sega.Saturn
[DllImport("libyabause.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void libyabause_softreset();
/// <summary>
/// hard reset, or something like that
/// </summary>
[DllImport("libyabause.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void libyabause_hardreset();
/// <summary>
///
/// </summary>
/// <param name="fn"></param>
/// <returns>success</returns>
[DllImport("libyabause.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool libyabause_loadstate(string fn);
/// <summary>
///
/// </summary>
/// <param name="fn"></param>
/// <returns>success</returns>
[DllImport("libyabause.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool libyabause_savestate(string fn);
/// <summary>
///
/// </summary>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace BizHawk.Emulation.Consoles.Sega.Saturn
{
@ -202,27 +203,100 @@ namespace BizHawk.Emulation.Consoles.Sega.Saturn
IsLagFrame = false;
}
public void SaveStateText(System.IO.TextWriter writer)
#region savestates
void LoadCoreBinary(byte[] data)
{
var fp = new FilePiping();
fp.Offer(data);
bool succeed = LibYabause.libyabause_loadstate(fp.GetPipeNameNative());
var e = fp.GetResults();
if (e != null)
throw e;
if (!succeed)
throw new Exception("libyabause_loadstate() failed");
}
public void LoadStateText(System.IO.TextReader reader)
byte[] SaveCoreBinary()
{
var ms = new MemoryStream();
var fp = new FilePiping();
fp.Get(ms);
bool succeed = LibYabause.libyabause_savestate(fp.GetPipeNameNative());
var e = fp.GetResults();
if (e != null)
throw e;
var ret = ms.ToArray();
ms.Close();
if (!succeed)
throw new Exception("libyabause_savestate() failed");
return ret;
}
public void SaveStateBinary(System.IO.BinaryWriter writer)
// these next 5 functions are all exact copy paste from gambatte.
// if something's wrong here, it's probably wrong there too
public void SaveStateText(TextWriter writer)
{
var temp = SaveStateBinary();
temp.SaveAsHex(writer);
// write extra copy of stuff we don't use
writer.WriteLine("Frame {0}", Frame);
}
public void LoadStateBinary(System.IO.BinaryReader reader)
public void LoadStateText(TextReader reader)
{
string hex = reader.ReadLine();
if (hex.StartsWith("emuVersion")) // movie save
{
do // theoretically, our portion should start right after StartsFromSavestate, maybe...
{
hex = reader.ReadLine();
} while (!hex.StartsWith("StartsFromSavestate"));
hex = reader.ReadLine();
}
byte[] state = new byte[hex.Length / 2];
state.ReadFromHex(hex);
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
}
public void SaveStateBinary(BinaryWriter writer)
{
byte[] data = SaveCoreBinary();
writer.Write(data.Length);
writer.Write(data);
// other variables
writer.Write(IsLagFrame);
writer.Write(LagCount);
writer.Write(Frame);
}
public void LoadStateBinary(BinaryReader reader)
{
int length = reader.ReadInt32();
byte[] data = reader.ReadBytes(length);
LoadCoreBinary(data);
// other variables
IsLagFrame = reader.ReadBoolean();
LagCount = reader.ReadInt32();
Frame = reader.ReadInt32();
}
public byte[] SaveStateBinary()
{
return new byte[0];
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
#endregion
public CoreComm CoreComm { get; private set; }
public IList<MemoryDomain> MemoryDomains

View File

@ -160,6 +160,7 @@ static INLINE int StateWriteHeader(FILE *fp, const char *name, int version) {
}
static INLINE int StateFinishHeader(FILE *fp, int offset) {
/*
IOCheck_struct check;
int size = 0;
size = ftell(fp) - offset;
@ -169,6 +170,8 @@ static INLINE int StateFinishHeader(FILE *fp, int offset) {
ywrite(&check, (void *)&size, sizeof(size), 1, fp); // write true size
fseek(fp, 0, SEEK_END);
return (check.done == check.size) ? (size + 12) : -1;
*/
return 0;
}
static INLINE int StateCheckRetrieveHeader(FILE *fp, const char *name, int *version, int *size) {

View File

@ -177,6 +177,21 @@ extern "C" __declspec(dllexport) void libyabause_softreset()
YabauseResetButton();
}
extern "C" __declspec(dllexport) void libyabause_hardreset()
{
YabauseReset();
}
extern "C" __declspec(dllexport) int libyabause_loadstate(const char *fn)
{
return !YabLoadState(fn);
}
extern "C" __declspec(dllexport) int libyabause_savestate(const char *fn)
{
return !YabSaveState(fn);
}
extern "C" __declspec(dllexport) int libyabause_frameadvance(int *w, int *h, int *nsamp)
{
LagFrameFlag = 1;

View File

@ -1028,7 +1028,7 @@ int YabSaveState(const char *filename)
#endif
// Write version(fix me)
i = 2;
i = 1;//2;
ywrite(&check, (void *)&i, sizeof(i), 1, fp);
// Skip the next 4 bytes for now
@ -1036,10 +1036,10 @@ int YabSaveState(const char *filename)
ywrite(&check, (void *)&i, sizeof(i), 1, fp);
//write frame number
ywrite(&check, (void *)&framecounter, 4, 1, fp);
//ywrite(&check, (void *)&framecounter, 4, 1, fp);
//this will be updated with the movie position later
ywrite(&check, (void *)&framecounter, 4, 1, fp);
//ywrite(&check, (void *)&framecounter, 4, 1, fp);
// Go through each area and write each state
i += CartSaveState(fp);
@ -1071,7 +1071,7 @@ int YabSaveState(const char *filename)
ywrite(&check, (void *)&temp32, sizeof(u32), 1, fp);
ywrite(&check, (void *)&yabsys.CurSH2FreqType, sizeof(int), 1, fp);
ywrite(&check, (void *)&yabsys.IsPal, sizeof(int), 1, fp);
/*
VIDCore->GetGlSize(&outputwidth, &outputheight);
totalsize=outputwidth * outputheight * sizeof(u32);
@ -1097,15 +1097,15 @@ int YabSaveState(const char *filename)
movieposition=ftell(fp);
//write the movie to the end of the savestate
SaveMovieInState(fp, check);
*/
i += StateFinishHeader(fp, offset);
/*
// Go back and update size
fseek(fp, 8, SEEK_SET);
ywrite(&check, (void *)&i, sizeof(i), 1, fp);
fseek(fp, 16, SEEK_SET);
ywrite(&check, (void *)&movieposition, sizeof(movieposition), 1, fp);
*/
fclose(fp);
OSDPushMessage(OSDMSG_STATUS, 150, "STATE SAVED");
@ -1187,14 +1187,14 @@ int YabLoadState(const char *filename)
}
// Make sure size variable matches actual size minus header
fseek(fp, 0, SEEK_END);
//fseek(fp, 0, SEEK_END);
if (size != (ftell(fp) - headersize))
{
fclose(fp);
return -2;
}
fseek(fp, headersize, SEEK_SET);
//if (size != (ftell(fp) - headersize))
//{
// fclose(fp);
// return -2;
//}
//fseek(fp, headersize, SEEK_SET);
// Verify version here