flycast/core/nullDC.cpp

728 lines
18 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
// nullDC.cpp : Makes magic cookies
//
//initialse Emu
#include "types.h"
#include "oslib/oslib.h"
#include "oslib/audiostream.h"
2013-12-19 17:10:14 +00:00
#include "hw/mem/_vmem.h"
#include "stdclass.h"
#include "cfg/cfg.h"
#include "types.h"
#include "hw/maple/maple_cfg.h"
#include "hw/sh4/sh4_mem.h"
#include "webui/server.h"
#include "hw/naomi/naomi_cart.h"
#include "reios/reios.h"
2018-09-02 13:49:23 +00:00
#include "hw/sh4/dyna/blockmanager.h"
2018-09-23 14:18:35 +00:00
#include "hw/pvr/Renderer_if.h"
2013-12-19 17:10:14 +00:00
settings_t settings;
2018-09-02 13:49:23 +00:00
static bool performed_serialization = false;
static cMutex mtx_serialization ;
static cMutex mtx_mainloop ;
2013-12-19 17:10:14 +00:00
/*
libndc
//initialise (and parse the command line)
ndc_init(argc,argv);
...
//run a dreamcast slice
//either a frame, or up to 25 ms of emulation
//returns 1 if the frame is ready (fb needs to be flipped -- i'm looking at you android)
ndc_step();
...
//terminate (and free everything)
ndc_term()
*/
#if HOST_OS==OS_WINDOWS
#include <windows.h>
#endif
2018-09-02 13:49:23 +00:00
/**
* cpu_features_get_time_usec:
*
* Gets time in microseconds.
*
* Returns: time in microseconds.
**/
int64_t get_time_usec(void)
{
#if HOST_OS==OS_WINDOWS
static LARGE_INTEGER freq;
LARGE_INTEGER count;
/* Frequency is guaranteed to not change. */
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
return 0;
if (!QueryPerformanceCounter(&count))
return 0;
return count.QuadPart * 1000000 / freq.QuadPart;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__) || HOST_OS==OS_LINUX
struct timespec tv = {0};
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
return 0;
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
#elif defined(EMSCRIPTEN)
return emscripten_get_now() * 1000;
#elif defined(__mips__) || defined(DJGPP)
struct timeval tv;
gettimeofday(&tv,NULL);
return (1000000 * tv.tv_sec + tv.tv_usec);
#else
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
#endif
}
int GetFile(char *szFileName, char *szParse=0, u32 flags=0)
2013-12-19 17:10:14 +00:00
{
cfgLoadStr("config","image",szFileName,"null");
if (strcmp(szFileName,"null")==0)
{
#if HOST_OS==OS_WINDOWS
OPENFILENAME ofn;
ZeroMemory( &ofn , sizeof( ofn));
ofn.lStructSize = sizeof ( ofn );
ofn.hwndOwner = NULL ;
ofn.lpstrFile = szFileName ;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter = "All\0*.*\0\0";
ofn.nFilterIndex =1;
ofn.lpstrFileTitle = NULL ;
ofn.nMaxFileTitle = 0 ;
ofn.lpstrInitialDir=NULL ;
ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ;
if (GetOpenFileNameA(&ofn))
{
//already there
//strcpy(szFileName,ofn.lpstrFile);
}
#endif
}
return 1;
2013-12-19 17:10:14 +00:00
}
s32 plugins_Init()
{
if (s32 rv = libPvr_Init())
return rv;
2018-07-16 15:19:45 +00:00
#ifndef TARGET_DISPFRAME
2013-12-19 17:10:14 +00:00
if (s32 rv = libGDR_Init())
return rv;
2018-07-16 15:19:45 +00:00
#endif
#if DC_PLATFORM == DC_PLATFORM_NAOMI
if (!naomi_cart_SelectFile(libPvr_GetRenderTarget()))
2013-12-19 17:10:14 +00:00
return rv_serror;
#endif
if (s32 rv = libAICA_Init())
return rv;
2013-12-19 17:10:14 +00:00
if (s32 rv = libARM_Init())
return rv;
2013-12-19 17:10:14 +00:00
//if (s32 rv = libExtDevice_Init())
// return rv;
return rv_ok;
}
void plugins_Term()
{
//term all plugins
//libExtDevice_Term();
libARM_Term();
libAICA_Term();
libGDR_Term();
libPvr_Term();
}
void plugins_Reset(bool Manual)
{
libPvr_Reset(Manual);
libGDR_Reset(Manual);
libAICA_Reset(Manual);
libARM_Reset(Manual);
//libExtDevice_Reset(Manual);
}
2018-09-04 16:47:12 +00:00
#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS)
2013-12-19 17:10:14 +00:00
void* webui_th(void* p)
{
webui_start();
return 0;
}
cThread webui_thd(&webui_th,0);
#endif
void LoadSpecialSettings()
{
// Tony Hawk's Pro Skater 2
if (!strncmp("T13008D", reios_product_number, 7) || !strncmp("T13006N", reios_product_number, 7)
// Tony Hawk's Pro Skater 1
2018-09-05 13:32:25 +00:00
|| !strncmp("T40205N", reios_product_number, 7)
// Tony Hawk's Skateboarding
|| !strncmp("T40204D", reios_product_number, 7))
settings.rend.RenderToTextureBuffer = 1;
if (!strncmp("HDR-0176", reios_product_number, 8) || !strncmp("RDC-0057", reios_product_number, 8))
// Cosmic Smash
settings.rend.TranslucentPolygonDepthMask = 1;
// Pro Pinball Trilogy
if (!strncmp("T30701D", reios_product_number, 7)
// Demolition Racer
|| !strncmp("T15112N", reios_product_number, 7)
// Star Wars - Episode I - Racer (United Kingdom)
|| !strncmp("T23001D", reios_product_number, 7)
// Record of Lodoss War (EU)
|| !strncmp("T7012D", reios_product_number, 6)
// Record of Lodoss War (USA)
|| !strncmp("T40218N", reios_product_number, 7)
// Surf Rocket Racers
|| !strncmp("T40216N", reios_product_number, 7))
{
printf("Enabling Dynarec safe mode for game %s\n", reios_product_number);
settings.dynarec.safemode = 1;
}
}
#if defined(_ANDROID)
int reios_init_value;
void reios_init(int argc,wchar* argv[])
#else
2013-12-19 17:10:14 +00:00
int dc_init(int argc,wchar* argv[])
#endif
2013-12-19 17:10:14 +00:00
{
setbuf(stdin,0);
setbuf(stdout,0);
setbuf(stderr,0);
if (!_vmem_reserve())
{
printf("Failed to alloc mem\n");
#if defined(_ANDROID)
reios_init_value = -1;
return;
#else
2013-12-19 17:10:14 +00:00
return -1;
#endif
2013-12-19 17:10:14 +00:00
}
2018-09-04 16:47:12 +00:00
#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS)
webui_thd.Start();
#endif
2013-12-19 17:10:14 +00:00
if(ParseCommandLine(argc,argv))
{
#if defined(_ANDROID)
reios_init_value = 69;
return;
#else
return 69;
#endif
2013-12-19 17:10:14 +00:00
}
if(!cfgOpen())
{
msgboxf("Unable to open config file",MBX_ICONERROR);
#if defined(_ANDROID)
reios_init_value = -4;
return;
#else
2013-12-19 17:10:14 +00:00
return -4;
#endif
2013-12-19 17:10:14 +00:00
}
LoadSettings();
#ifndef _ANDROID
2013-12-19 17:10:14 +00:00
os_CreateWindow();
#endif
int rv = 0;
2013-12-19 17:10:14 +00:00
2015-05-16 08:04:30 +00:00
#if HOST_OS != OS_DARWIN
#define DATA_PATH "/data/"
#else
#define DATA_PATH "/"
#endif
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
2013-12-19 17:10:14 +00:00
{
if (!LoadHle(get_readonly_data_path(DATA_PATH)))
{
#if defined(_ANDROID)
reios_init_value = -4;
return;
#else
return -3;
#endif
}
else
{
printf("Did not load bios, using reios\n");
}
2013-12-19 17:10:14 +00:00
}
plugins_Init();
#if defined(_ANDROID)
}
int dc_init()
{
int rv = 0;
if (reios_init_value != 0)
return reios_init_value;
#else
LoadCustom();
#endif
2015-07-25 06:39:35 +00:00
#if FEAT_SHREC != DYNAREC_NONE
2013-12-19 17:10:14 +00:00
if(settings.dynarec.Enable)
{
Get_Sh4Recompiler(&sh4_cpu);
printf("Using Recompiler\n");
}
else
#endif
{
Get_Sh4Interpreter(&sh4_cpu);
printf("Using Interpreter\n");
}
InitAudio();
2013-12-19 17:10:14 +00:00
sh4_cpu.Init();
mem_Init();
mem_map_default();
os_SetupInput();
#if DC_PLATFORM == DC_PLATFORM_NAOMI
mcfg_CreateNAOMIJamma();
#endif
2013-12-19 17:10:14 +00:00
plugins_Reset(false);
mem_Reset(false);
sh4_cpu.Reset(false);
return rv;
}
2018-07-16 15:19:45 +00:00
#ifndef TARGET_DISPFRAME
2018-09-02 13:49:23 +00:00
bool dc_is_running()
{
return sh4_cpu.IsCpuRunning();
}
2013-12-19 17:10:14 +00:00
void dc_run()
{
2018-09-02 13:49:23 +00:00
while ( true )
{
performed_serialization = false ;
mtx_mainloop.Lock() ;
sh4_cpu.Run();
mtx_mainloop.Unlock() ;
mtx_serialization.Lock() ;
mtx_serialization.Unlock() ;
if (!performed_serialization)
break ;
}
2013-12-19 17:10:14 +00:00
}
2018-07-16 15:19:45 +00:00
#endif
2013-12-19 17:10:14 +00:00
void dc_term()
{
sh4_cpu.Term();
plugins_Term();
_vmem_release();
#ifndef _ANDROID
2013-12-19 17:10:14 +00:00
SaveSettings();
#endif
SaveRomFiles(get_writable_data_path("/data/"));
2018-07-24 12:27:58 +00:00
TermAudio();
2018-09-07 10:57:26 +00:00
#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS)
extern void sighandler(int sig);
sighandler(0);
webui_thd.WaitToEnd();
#endif
2013-12-19 17:10:14 +00:00
}
#if defined(_ANDROID)
void dc_pause()
{
SaveRomFiles(get_writable_data_path("/data/"));
}
#endif
void dc_stop()
{
sh4_cpu.Stop();
2013-12-19 17:10:14 +00:00
}
2018-09-02 13:49:23 +00:00
void dc_start()
{
sh4_cpu.Start();
}
2013-12-19 17:10:14 +00:00
void LoadSettings()
{
#ifndef _ANDROID
2013-12-19 17:10:14 +00:00
settings.dynarec.Enable = cfgLoadInt("config","Dynarec.Enabled", 1)!=0;
settings.dynarec.idleskip = cfgLoadInt("config","Dynarec.idleskip",1)!=0;
settings.dynarec.unstable_opt = cfgLoadInt("config","Dynarec.unstable-opt",0);
settings.dynarec.safemode = cfgLoadInt("config", "Dynarec.safe-mode", 0);
//disable_nvmem can't be loaded, because nvmem init is before cfg load
Squash changes from andoidui into single commit Integrate previously locked settings with valid user warning Put a note about the beta compile link in the README.md Add a super fancy about that supports Github commit logs Revise about with git log, Highlight current build in commits Check for a null value when getting the current commit sha Chinese Simplified Translation from @weihan1102 Rename Simplified Chinese res folder for proper complie Add links to the website and beta compile site from about Add option for custom mapping to set joystick to non-dpad Fix a missing check for the user saved value of the A button The Moga only operates one way, there is no variation test Add region values, Set cable to match formatting of others Reduce the number of random string array calls, jsCompat It was unnecessary to keep getting the array, It was even less necessary to keep getting the preference values. The port identification letters are set multi-lingual values. Label the about links to prevent any confusion (Not mirrors) Missing a check on the motion events to determine compat Add a check to verify Kitkat, Remove the standard override The new API verification complains about the Override, so this is a preventative step for if and when it is updated. It may also prevent some issues with compatibility. Run organize imports to reduce the amount of excess code Add a controller option to go to custom layout from selection Prevent a leak where multiple items were highlighted in list @AndroidGX French Translation resources
2014-01-27 15:52:23 +00:00
settings.dreamcast.cable = cfgLoadInt("config","Dreamcast.Cable",3);
2013-12-19 17:10:14 +00:00
settings.dreamcast.RTC = cfgLoadInt("config","Dreamcast.RTC",GetRTC_now());
settings.dreamcast.region = cfgLoadInt("config","Dreamcast.Region",3);
settings.dreamcast.broadcast = cfgLoadInt("config","Dreamcast.Broadcast",4);
settings.aica.LimitFPS = cfgLoadInt("config","aica.LimitFPS",1);
settings.aica.NoBatch = cfgLoadInt("config","aica.NoBatch",0);
settings.aica.NoSound = cfgLoadInt("config","aica.NoSound",0);
2013-12-19 17:10:14 +00:00
settings.rend.UseMipmaps = cfgLoadInt("config","rend.UseMipmaps",1);
settings.rend.WideScreen = cfgLoadInt("config","rend.WideScreen",0);
settings.rend.ShowFPS = cfgLoadInt("config", "rend.ShowFPS", 0);
settings.rend.RenderToTextureBuffer = cfgLoadInt("config", "rend.RenderToTextureBuffer", 0);
settings.rend.RenderToTextureUpscale = cfgLoadInt("config", "rend.RenderToTextureUpscale", 1);
settings.rend.TranslucentPolygonDepthMask = cfgLoadInt("config", "rend.TranslucentPolygonDepthMask", 0);
settings.rend.ModifierVolumes = cfgLoadInt("config","rend.ModifierVolumes",1);
settings.rend.Clipping = cfgLoadInt("config","rend.Clipping",1);
2018-08-01 17:43:01 +00:00
settings.rend.TextureUpscale = cfgLoadInt("config","rend.TextureUpscale", 1);
settings.rend.MaxFilteredTextureSize = cfgLoadInt("config","rend.MaxFilteredTextureSize", 256);
char extra_depth_scale_str[128];
cfgLoadStr("config","rend.ExtraDepthScale", extra_depth_scale_str, "1");
settings.rend.ExtraDepthScale = atof(extra_depth_scale_str);
if (settings.rend.ExtraDepthScale == 0)
settings.rend.ExtraDepthScale = 1.f;
2018-08-01 17:43:01 +00:00
2013-12-19 17:10:14 +00:00
settings.pvr.subdivide_transp = cfgLoadInt("config","pvr.Subdivide",0);
settings.pvr.ta_skip = cfgLoadInt("config","ta.skip",0);
settings.pvr.rend = cfgLoadInt("config","pvr.rend",0);
settings.pvr.MaxThreads = cfgLoadInt("config", "pvr.MaxThreads", 3);
settings.pvr.SynchronousRender = cfgLoadInt("config", "pvr.SynchronousRendering", 0);
settings.debug.SerialConsole = cfgLoadInt("config", "Debug.SerialConsoleEnabled", 0) != 0;
2015-03-22 00:16:28 +00:00
settings.bios.UseReios = cfgLoadInt("config", "bios.UseReios", 0);
settings.reios.ElfFile = cfgLoadStr("reios", "ElfFile", "");
settings.validate.OpenGlChecks = cfgLoadInt("validate", "OpenGlChecks", 0) != 0;
2018-09-18 07:27:16 +00:00
settings.input.DCKeyboard = cfgLoadInt("input", "DCKeyboard", 0);
2018-09-18 07:27:16 +00:00
settings.input.DCMouse = cfgLoadInt("input", "DCMouse", 0);
settings.input.MouseSensitivity = cfgLoadInt("input", "MouseSensitivity", 100);
#else
// TODO Expose this with JNI
settings.rend.Clipping = 1;
2018-09-04 21:38:00 +00:00
settings.rend.ExtraDepthScale = 1.f;
// Configured on a per-game basis
settings.dynarec.safemode = 0;
#endif
2013-12-19 17:10:14 +00:00
settings.pvr.HashLogFile = cfgLoadStr("testing", "ta.HashLogFile", "");
settings.pvr.HashCheckFile = cfgLoadStr("testing", "ta.HashCheckFile", "");
2016-03-02 05:48:34 +00:00
#if SUPPORT_DISPMANX
settings.dispmanx.Width = cfgLoadInt("dispmanx","width",640);
settings.dispmanx.Height = cfgLoadInt("dispmanx","height",480);
settings.dispmanx.Keep_Aspect = cfgLoadBool("dispmanx","maintain_aspect",true);
2016-03-02 05:48:34 +00:00
#endif
#if (HOST_OS != OS_LINUX || defined(_ANDROID) || defined(TARGET_PANDORA))
2013-12-19 17:10:14 +00:00
settings.aica.BufferSize=2048;
#else
settings.aica.BufferSize=1024;
#endif
2016-03-02 05:48:34 +00:00
#if USE_OMX
settings.omx.Audio_Latency = cfgLoadInt("omx","audio_latency",100);
settings.omx.Audio_HDMI = cfgLoadBool("omx","audio_hdmi",true);
2016-03-02 05:48:34 +00:00
#endif
2013-12-19 17:10:14 +00:00
/*
//make sure values are valid
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);
settings.dreamcast.region = min(max(settings.dreamcast.region, 0),3);
settings.dreamcast.broadcast= min(max(settings.dreamcast.broadcast,0),4);
*/
}
void LoadCustom()
{
char *reios_id = reios_disk_id();
char *p = reios_id + strlen(reios_id) - 1;
while (p >= reios_id && *p == ' ')
*p-- = '\0';
if (*p == '\0')
return;
LoadSpecialSettings(); // Default per-game settings
if (reios_software_name[0] != '\0')
cfgSaveStr(reios_id, "software.name", reios_software_name);
settings.dynarec.Enable = cfgGameInt(reios_id,"Dynarec.Enabled", settings.dynarec.Enable ? 1 : 0) != 0;
settings.dynarec.idleskip = cfgGameInt(reios_id,"Dynarec.idleskip", settings.dynarec.idleskip ? 1 : 0) != 0;
settings.dynarec.unstable_opt = cfgGameInt(reios_id,"Dynarec.unstable-opt", settings.dynarec.unstable_opt);
settings.dynarec.safemode = cfgGameInt(reios_id,"Dynarec.safe-mode", settings.dynarec.safemode);
settings.rend.ModifierVolumes = cfgGameInt(reios_id,"rend.ModifierVolumes", settings.rend.ModifierVolumes);
settings.rend.Clipping = cfgGameInt(reios_id,"rend.Clipping", settings.rend.Clipping);
settings.pvr.subdivide_transp = cfgGameInt(reios_id,"pvr.Subdivide", settings.pvr.subdivide_transp);
settings.pvr.ta_skip = cfgGameInt(reios_id,"ta.skip", settings.pvr.ta_skip);
settings.pvr.rend = cfgGameInt(reios_id,"pvr.rend", settings.pvr.rend);
settings.pvr.MaxThreads = cfgGameInt(reios_id, "pvr.MaxThreads", settings.pvr.MaxThreads);
settings.pvr.SynchronousRender = cfgGameInt(reios_id, "pvr.SynchronousRendering", settings.pvr.SynchronousRender);
settings.dreamcast.cable = cfgGameInt(reios_id, "Dreamcast.Cable", settings.dreamcast.cable);
settings.dreamcast.region = cfgGameInt(reios_id, "Dreamcast.Region", settings.dreamcast.region);
settings.dreamcast.broadcast = cfgGameInt(reios_id, "Dreamcast.Broadcast", settings.dreamcast.broadcast);
}
2013-12-19 17:10:14 +00:00
void SaveSettings()
{
cfgSaveInt("config","Dynarec.Enabled", settings.dynarec.Enable);
cfgSaveInt("config","Dreamcast.Cable", settings.dreamcast.cable);
cfgSaveInt("config","Dreamcast.RTC", settings.dreamcast.RTC);
cfgSaveInt("config","Dreamcast.Region", settings.dreamcast.region);
cfgSaveInt("config","Dreamcast.Broadcast", settings.dreamcast.broadcast);
2013-12-19 17:10:14 +00:00
}
2018-09-02 13:49:23 +00:00
bool wait_until_dc_running()
{
int64_t start_time = get_time_usec() ;
const int64_t FIVE_SECONDS = 5*1000000 ;
while(!dc_is_running())
{
if ( start_time+FIVE_SECONDS < get_time_usec() )
{
//timeout elapsed - dc not getting a chance to run - just bail
return false ;
}
}
return true ;
}
bool acquire_mainloop_lock()
{
bool result = false ;
int64_t start_time = get_time_usec() ;
const int64_t FIVE_SECONDS = 5*1000000 ;
2018-09-23 14:18:35 +00:00
while ( ( start_time+FIVE_SECONDS > get_time_usec() ) && !(result = mtx_mainloop.TryLock()) )
{
rend_cancel_emu_wait() ;
}
2018-09-02 13:49:23 +00:00
2018-09-23 14:18:35 +00:00
return result ;
2018-09-02 13:49:23 +00:00
}
void cleanup_serialize(void *data)
{
if ( data != NULL )
free(data) ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
mtx_mainloop.Unlock() ;
}
2018-09-20 20:41:10 +00:00
static string get_savestate_file_path()
{
char image_path[512];
cfgLoadStr("config", "image", image_path, "./");
string state_file = image_path;
size_t lastindex = state_file.find_last_of("/");
if (lastindex != -1)
state_file = state_file.substr(lastindex + 1);
lastindex = state_file.find_last_of(".");
if (lastindex != -1)
state_file = state_file.substr(0, lastindex);
state_file = state_file + ".state";
return get_writable_data_path("/data/") + state_file;
}
2018-09-02 13:49:23 +00:00
void* dc_savestate_thread(void* p)
{
2018-09-20 20:41:10 +00:00
string filename;
2018-09-02 13:49:23 +00:00
unsigned int total_size = 0 ;
void *data = NULL ;
void *data_ptr = NULL ;
FILE *f ;
mtx_serialization.Lock() ;
if ( !wait_until_dc_running()) {
printf("Failed to save state - dc loop kept running\n") ;
mtx_serialization.Unlock() ;
return NULL;
}
dc_stop() ;
if ( !acquire_mainloop_lock() )
{
printf("Failed to save state - could not acquire main loop lock\n") ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
return NULL;
}
if ( ! dc_serialize(&data, &total_size) )
{
printf("Failed to save state - could not initialize total size\n") ;
cleanup_serialize(data) ;
return NULL;
}
data = malloc(total_size) ;
if ( data == NULL )
{
printf("Failed to save state - could not malloc %d bytes", total_size) ;
cleanup_serialize(data) ;
return NULL;
}
data_ptr = data ;
if ( ! dc_serialize(&data_ptr, &total_size) )
{
printf("Failed to save state - could not serialize data\n") ;
cleanup_serialize(data) ;
return NULL;
}
2018-09-20 20:41:10 +00:00
filename = get_savestate_file_path();
f = fopen(filename.c_str(), "wb") ;
2018-09-02 13:49:23 +00:00
if ( f == NULL )
{
2018-09-20 20:41:10 +00:00
printf("Failed to save state - could not open %s for writing\n", filename.c_str()) ;
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return NULL;
}
fwrite(data, 1, total_size, f) ;
fclose(f);
cleanup_serialize(data) ;
2018-09-20 20:41:10 +00:00
printf("Saved state to %s\n size %d", filename.c_str(), total_size) ;
2018-09-02 13:49:23 +00:00
2018-09-23 14:18:35 +00:00
return NULL;
2018-09-02 13:49:23 +00:00
}
void* dc_loadstate_thread(void* p)
{
2018-09-20 20:41:10 +00:00
string filename;
2018-09-02 13:49:23 +00:00
unsigned int total_size = 0 ;
void *data = NULL ;
void *data_ptr = NULL ;
FILE *f ;
mtx_serialization.Lock() ;
if ( !wait_until_dc_running()) {
printf("Failed to load state - dc loop kept running\n") ;
mtx_serialization.Unlock() ;
return NULL;
}
dc_stop() ;
if ( !acquire_mainloop_lock() )
{
printf("Failed to load state - could not acquire main loop lock\n") ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
return NULL;
}
if ( ! dc_serialize(&data, &total_size) )
{
printf("Failed to load state - could not initialize total size\n") ;
cleanup_serialize(data) ;
return NULL;
}
data = malloc(total_size) ;
if ( data == NULL )
{
printf("Failed to load state - could not malloc %d bytes", total_size) ;
cleanup_serialize(data) ;
return NULL;
}
2018-09-20 20:41:10 +00:00
filename = get_savestate_file_path();
f = fopen(filename.c_str(), "rb") ;
2018-09-02 13:49:23 +00:00
if ( f == NULL )
{
2018-09-20 20:41:10 +00:00
printf("Failed to load state - could not open %s for reading\n", filename.c_str()) ;
2018-09-02 13:49:23 +00:00
cleanup_serialize(data) ;
return NULL;
}
fread(data, 1, total_size, f) ;
fclose(f);
data_ptr = data ;
bm_Reset() ;
if ( ! dc_unserialize(&data_ptr, &total_size) )
{
printf("Failed to load state - could not unserialize data\n") ;
cleanup_serialize(data) ;
return NULL;
}
cleanup_serialize(data) ;
2018-09-20 20:41:10 +00:00
printf("Loaded state from %s size %d\n", filename.c_str(), total_size) ;
2018-09-23 14:18:35 +00:00
return NULL;
2018-09-02 13:49:23 +00:00
}
void dc_savestate()
{
cThread thd(dc_savestate_thread,0);
thd.Start() ;
}
void dc_loadstate()
{
cThread thd(dc_loadstate_thread,0);
thd.Start() ;
}