flycast/core/nullDC.cpp

882 lines
23 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-10-29 14:11:34 +00:00
#include "hw/sh4/sh4_sched.h"
2018-09-23 14:18:35 +00:00
#include "hw/pvr/Renderer_if.h"
2018-10-29 14:11:34 +00:00
#include "hw/pvr/spg.h"
2019-02-06 18:57:13 +00:00
#include "hw/aica/dsp.h"
2018-10-29 15:53:26 +00:00
void FlushCache();
2019-02-06 18:57:13 +00:00
static void LoadCustom();
2018-10-29 15:53:26 +00:00
2013-12-19 17:10:14 +00:00
settings_t settings;
static bool continue_running = false;
2018-09-02 13:49:23 +00:00
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 || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
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()
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
printf("Game ID is [%s]\n", reios_product_number);
// 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)
// Skies of Arcadia
|| !strncmp("MK-51052", reios_product_number, 8))
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;
}
// NHL 2K2
if (!strncmp("MK-51182", reios_product_number, 8))
{
printf("Enabling Extra depth scaling for game %s\n", reios_product_number);
2018-12-11 22:20:30 +00:00
settings.rend.ExtraDepthScale = 10000;
}
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Game ID is [%s]\n", naomi_game_id);
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
{
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
settings.dynarec.safemode = 1;
}
if (!strcmp("SAMURAI SPIRITS 6", naomi_game_id))
{
printf("Enabling Extra depth scaling for game %s\n", naomi_game_id);
settings.rend.ExtraDepthScale = 1e26;
}
if (!strcmp("DYNAMIC GOLF", naomi_game_id)
|| !strcmp("SHOOTOUT POOL", naomi_game_id)
|| !strcmp("OUTTRIGGER JAPAN", naomi_game_id)
|| !strcmp("CRACKIN'DJ ver JAPAN", naomi_game_id)
|| !strcmp("CRACKIN'DJ PART2 ver JAPAN", naomi_game_id)
|| !strcmp("KICK '4' CASH", naomi_game_id))
{
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
settings.input.JammaSetup = 2;
}
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
{
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 1;
}
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 3;
}
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id))
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 4;
}
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 5;
}
2018-12-11 22:20:30 +00:00
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 7;
}
2018-10-21 00:48:24 +00:00
if (!strcmp("COSMIC SMASH IN JAPAN", naomi_game_id))
{
printf("Enabling translucent depth multipass for game %s\n", naomi_game_id);
settings.rend.TranslucentPolygonDepthMask = true;
}
#endif
}
void dc_reset()
{
plugins_Reset(false);
mem_Reset(false);
sh4_cpu.Reset(false);
}
#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
}
if (plugins_Init())
{
#if defined(_ANDROID)
reios_init_value = -4;
return;
#else
return -3;
#endif
}
#if defined(_ANDROID)
}
int dc_init()
{
int rv = 0;
if (reios_init_value != 0)
return reios_init_value;
LoadSpecialSettings();
#else
LoadCustom();
#endif
2015-07-25 06:39:35 +00:00
#if FEAT_SHREC != DYNAREC_NONE
Get_Sh4Recompiler(&sh4_cpu);
sh4_cpu.Init(); // Also initialize the interpreter
2013-12-19 17:10:14 +00:00
if(settings.dynarec.Enable)
{
printf("Using Recompiler\n");
}
else
#endif
{
Get_Sh4Interpreter(&sh4_cpu);
#if FEAT_SHREC == DYNAREC_NONE
sh4_cpu.Init();
#endif
2013-12-19 17:10:14 +00:00
printf("Using Interpreter\n");
}
InitAudio();
2013-12-19 17:10:14 +00:00
mem_Init();
mem_map_default();
os_SetupInput();
#if DC_PLATFORM == DC_PLATFORM_NAOMI
mcfg_CreateNAOMIJamma();
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
mcfg_CreateAtomisWaveControllers();
#endif
2013-12-19 17:10:14 +00:00
dc_reset();
2013-12-19 17:10:14 +00:00
return rv;
}
2018-09-02 13:49:23 +00:00
bool dc_is_running()
{
return sh4_cpu.IsCpuRunning();
}
2018-10-02 16:29:29 +00:00
#ifndef TARGET_DISPFRAME
2013-12-19 17:10:14 +00:00
void dc_run()
{
2018-09-02 13:49:23 +00:00
while ( true )
{
2019-02-06 18:57:13 +00:00
bool dynarec_enabled = settings.dynarec.Enable;
continue_running = false ;
2018-09-02 13:49:23 +00:00
mtx_mainloop.Lock() ;
sh4_cpu.Run();
mtx_mainloop.Unlock() ;
mtx_serialization.Lock() ;
mtx_serialization.Unlock() ;
2019-02-06 18:57:13 +00:00
if (dynarec_enabled != settings.dynarec.Enable)
{
if (settings.dynarec.Enable)
{
Get_Sh4Recompiler(&sh4_cpu);
printf("Using Recompiler\n");
}
else
{
Get_Sh4Interpreter(&sh4_cpu);
printf("Using Interpreter\n");
}
sh4_cpu.ResetCache();
}
if (!continue_running)
2018-09-02 13:49:23 +00:00
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();
mcfg_DestroyDevices();
2013-12-19 17:10:14 +00:00
SaveSettings();
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()
{
settings.dreamcast.RTC = GetRTC_now();
#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.region = cfgLoadInt("config","Dreamcast.Region",3);
settings.dreamcast.broadcast = cfgLoadInt("config","Dreamcast.Broadcast",4);
settings.dreamcast.language = cfgLoadInt("config","Dreamcast.Language", 6);
2013-12-19 17:10:14 +00:00
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-12-30 17:42:55 +00:00
settings.rend.CustomTextures = cfgLoadInt("config", "rend.CustomTextures", 0);
settings.rend.DumpTextures = cfgLoadInt("config", "rend.DumpTextures", 0);
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);
settings.input.JammaSetup = cfgLoadInt("input", "JammaSetup", 0);
#else
// TODO Expose this with JNI
settings.rend.Clipping = 1;
settings.rend.RenderToTextureUpscale = 1;
settings.rend.TextureUpscale = 1;
// Configured on a per-game basis
settings.rend.ExtraDepthScale = 1.f;
settings.dynarec.safemode = 0;
settings.input.JammaSetup = 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);
*/
}
2019-02-06 18:57:13 +00:00
static void LoadCustom()
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
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;
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
char *reios_id = naomi_game_id;
char *reios_software_name = naomi_game_id;
#endif
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);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
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);
#endif
}
2019-02-06 18:57:13 +00:00
#ifndef _ANDROID
2013-12-19 17:10:14 +00:00
void SaveSettings()
{
2019-02-06 18:57:13 +00:00
cfgSaveInt("config", "Dynarec.Enabled", settings.dynarec.Enable);
cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable);
cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region);
cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast);
cfgSaveInt("config", "Dynarec.idleskip", settings.dynarec.idleskip);
cfgSaveInt("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
cfgSaveInt("config", "Dynarec.safe-mode", settings.dynarec.safemode);
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
cfgSaveInt("config", "aica.LimitFPS", settings.aica.LimitFPS);
cfgSaveInt("config", "aica.NoBatch", settings.aica.NoBatch);
cfgSaveInt("config", "rend.WideScreen", settings.rend.WideScreen);
cfgSaveInt("config", "rend.ShowFPS", settings.rend.ShowFPS);
cfgSaveInt("config", "rend.RenderToTextureBuffer", settings.rend.RenderToTextureBuffer);
cfgSaveInt("config", "rend.RenderToTextureUpscale", settings.rend.RenderToTextureUpscale);
cfgSaveInt("config", "rend.ModifierVolumes", settings.rend.ModifierVolumes);
cfgSaveInt("config", "rend.Clipping", settings.rend.Clipping);
cfgSaveInt("config", "rend.TextureUpscale", settings.rend.TextureUpscale);
cfgSaveInt("config", "rend.MaxFilteredTextureSize", settings.rend.MaxFilteredTextureSize);
cfgSaveInt("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveInt("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);
cfgSaveInt("config", "pvr.MaxThreads", settings.pvr.MaxThreads);
cfgSaveInt("config", "pvr.SynchronousRendering", settings.pvr.SynchronousRender);
cfgSaveInt("config", "Debug.SerialConsoleEnabled", settings.debug.SerialConsole);
cfgSaveInt("input", "DCKeyboard", settings.input.DCKeyboard);
cfgSaveInt("input", "DCMouse", settings.input.DCMouse);
cfgSaveInt("input", "MouseSensitivity", settings.input.MouseSensitivity);
2013-12-19 17:10:14 +00:00
}
2019-02-06 18:57:13 +00:00
#endif
2018-09-02 13:49:23 +00:00
2019-02-06 18:57:13 +00:00
static bool wait_until_dc_running()
2018-09-02 13:49:23 +00:00
{
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 ;
}
2019-02-06 18:57:13 +00:00
static bool acquire_mainloop_lock()
2018-09-02 13:49:23 +00:00
{
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
}
2019-02-06 18:57:13 +00:00
bool dc_pause_emu()
{
2019-02-06 18:57:13 +00:00
if (sh4_cpu.IsCpuRunning())
{
#ifndef TARGET_NO_THREADS
mtx_serialization.Lock();
if (!wait_until_dc_running()) {
printf("Can't open settings - dc loop kept running\n");
mtx_serialization.Unlock();
return false;
}
dc_stop();
if (!acquire_mainloop_lock())
{
printf("Can't open settings - could not acquire main loop lock\n");
continue_running = true;
mtx_serialization.Unlock();
return false;
}
#else
dc_stop();
#endif
2019-02-06 18:57:13 +00:00
}
return true;
}
void dc_resume_emu(bool continue_running)
{
if (!sh4_cpu.IsCpuRunning())
{
::continue_running = continue_running;
rend_cancel_emu_wait();
mtx_serialization.Unlock();
mtx_mainloop.Unlock();
}
}
2019-02-06 18:57:13 +00:00
static void cleanup_serialize(void *data)
2018-09-02 13:49:23 +00:00
{
if ( data != NULL )
free(data) ;
2019-02-06 18:57:13 +00:00
dc_resume_emu(true);
2018-09-02 13:49:23 +00:00
}
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;
}
2019-02-06 18:57:13 +00:00
static void* dc_savestate_thread(void* p)
2018-09-02 13:49:23 +00:00
{
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 ;
2019-02-06 18:57:13 +00:00
if (!dc_pause_emu())
return NULL;
2018-09-02 13:49:23 +00:00
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
}
2019-02-06 18:57:13 +00:00
static void* dc_loadstate_thread(void* p)
2018-09-02 13:49:23 +00:00
{
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 ;
2019-02-06 18:57:13 +00:00
if (!dc_pause_emu())
return NULL;
2018-09-02 13:49:23 +00:00
filename = get_savestate_file_path();
f = fopen(filename.c_str(), "rb") ;
if ( f == NULL )
2018-09-02 13:49:23 +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;
}
fseek(f, 0, SEEK_END);
total_size = ftell(f);
fseek(f, 0, SEEK_SET);
2018-09-02 13:49:23 +00:00
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-02 13:49:23 +00:00
}
fread(data, 1, total_size, f) ;
fclose(f);
data_ptr = data ;
2018-10-29 14:11:34 +00:00
sh4_cpu.ResetCache();
#if FEAT_AREC == DYNAREC_JIT
FlushCache();
#endif
2018-09-02 13:49:23 +00:00
if ( ! dc_unserialize(&data_ptr, &total_size) )
{
printf("Failed to load state - could not unserialize data\n") ;
cleanup_serialize(data) ;
return NULL;
}
2019-02-06 18:57:13 +00:00
dsp.dyndirty = true;
2018-10-29 14:11:34 +00:00
sh4_sched_ffts();
CalculateSync();
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() ;
}