Unverified Commit f19bc118 authored by Libretro-Admin's avatar Libretro-Admin Committed by GitHub
Browse files

Merge pull request #66 from bbbradsmith/memory_savestate

use in-memory savestates instead of intermediate file
parents f605173e 67728dc9
Pipeline #4628 passed with stages
in 6 minutes and 29 seconds
......@@ -34,9 +34,6 @@ extern int Reset_Cold(void);
#include <time.h>
#endif
long frame=0;
static unsigned long Ktime=0, LastFPSTime=0;
//VIDEO
extern SDL_Surface *sdlscrn;
unsigned short int bmp[1024*1024];
......@@ -52,9 +49,10 @@ char RPATH[512];
//EMU FLAGS
int NPAGE=-1, KCOL=1, BKGCOLOR=0, MAXPAS=6;
int SHIFTON=-1,MOUSEMODE=-1,SHOWKEY=-1,PAS=4,STATUTON=-1;
int SND; //SOUND ON/OFF
int SND=1; //SOUND ON/OFF
static int firstps=0;
int pauseg=0; //enter_gui
int slowdown=0;
//JOY
int al[2];//left analog1
......@@ -80,6 +78,69 @@ extern int LEDA,LEDB,LEDC;
int BOXDEC= 32+2;
int STAT_BASEY;
// savestate serialization
static bool serialize_forward;
static char* serialize_data;
#define SERIALIZE_STEP \
if (serialize_forward) memcpy(serialize_data, x, sizeof(*x)); \
else memcpy(x, serialize_data, sizeof(*x)); \
serialize_data += sizeof(*x);
void serialize_char(char *x) { SERIALIZE_STEP }
void serialize_int(int *x) { SERIALIZE_STEP }
int hatari_mapper_serialize_size()
{
return 1023;
}
static bool hatari_mapper_serialize_bidi(char* data, char version)
{
// ignoring version, there is only one version so far
serialize_data = data;
serialize_int(&NPAGE);
serialize_int(&KCOL);
serialize_int(&BKGCOLOR);
serialize_int(&MAXPAS);
serialize_int(&SHIFTON);
serialize_int(&MOUSEMODE);
serialize_int(&SHOWKEY);
serialize_int(&PAS);
serialize_int(&STATUTON);
serialize_int(&SND);
serialize_int(&pauseg);
serialize_int(&slowdown);
serialize_int(&fmousex);
serialize_int(&fmousey);
serialize_int(&gmx);
serialize_int(&gmy);
if ((int)(data - serialize_data) > hatari_mapper_serialize_size())
{
fprintf(stderr, "hatari_mapper_serialize_size()=%d insufficient! (Needs: %d)\n", hatari_mapper_serialize_size(), (int)(data - serialize_data));
return false;
}
return true;
}
bool hatari_mapper_serialize(char* data, char version)
{
serialize_forward = true;
return hatari_mapper_serialize_bidi(data, version);
}
bool hatari_mapper_unserialize(const char* data, char version)
{
serialize_forward = false;
int pauseg_old = pauseg;
bool result = hatari_mapper_serialize_bidi((char*)data, version);
if (pauseg_old) pauseg = pauseg_old; // because of the co-thread implementation there's really no way to save-state out of the GUI, so: stay paused
return result;
}
// input state
static retro_input_state_t input_state_cb;
static retro_input_poll_t input_poll_cb;
......@@ -124,37 +185,11 @@ long GetTicks(void)
}
#ifdef WIIU
#include <features/features_cpu.h>
retro_time_t current_tus=0,last_tus=0;
#endif
int slowdown=0;
//NO SURE FIND BETTER WAY TO COME BACK IN MAIN THREAD IN HATARI GUI
void gui_poll_events(void)
{
#ifdef WIIU
current_tus=cpu_features_get_time_usec();
current_tus/=1000;
if(current_tus - last_tus >= 1000/50)
{
slowdown=0;
frame++;
last_tus = current_tus;
co_switch(mainThread);
}
#else
Ktime = GetTicks();
if(Ktime - LastFPSTime >= 1000/50)
{
slowdown=0;
frame++;
LastFPSTime = Ktime;
co_switch(mainThread);
}
#endif
slowdown=0;
co_switch(mainThread);
}
//save bkg for screenshot
......
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (features_cpu.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_SDK_CPU_INFO_H
#define _LIBRETRO_SDK_CPU_INFO_H
#include <retro_common_api.h>
#include <stdint.h>
#include <libretro.h>
RETRO_BEGIN_DECLS
/**
* cpu_features_get_perf_counter:
*
* Gets performance counter.
*
* Returns: performance counter.
**/
retro_perf_tick_t cpu_features_get_perf_counter(void);
/**
* cpu_features_get_time_usec:
*
* Gets time in microseconds, from an undefined epoch.
* The epoch may change between computers or across reboots.
*
* Returns: time in microseconds
**/
retro_time_t cpu_features_get_time_usec(void);
/**
* cpu_features_get:
*
* Gets CPU features.
*
* Returns: bitmask of all CPU features available.
**/
uint64_t cpu_features_get(void);
/**
* cpu_features_get_core_amount:
*
* Gets the amount of available CPU cores.
*
* Returns: amount of CPU cores available.
**/
unsigned cpu_features_get_core_amount(void);
void cpu_features_get_model_name(char *name, int len);
RETRO_END_DECLS
#endif
......@@ -60,10 +60,10 @@ unsigned int video_config = 0;
int CHANGE_RATE = 0, CHANGEAV_TIMING = 0;
float FRAMERATE = 50.0, SAMPLERATE = 44100.0;
extern bool UseNonPolarizedLowPassFilter;
bool hatari_fastfdc = true;
bool hatari_borders = true;
char hatari_frameskips[2];
int firstpass = 1;
char savestate_fname[RETRO_PATH_MAX];
static struct retro_input_descriptor input_descriptors[] = {
......@@ -115,6 +115,18 @@ void retro_set_environment(retro_environment_t cb)
},
"true"
},
// Audio
{
"hatari_polarized_filter",
"Polarized audio filter",
"Uses hatari's polarized lowpass filters on audio to simulate distortion",
{
{ "false", "disabled" },
{ "true", "enabled" },
{ NULL, NULL },
},
"false"
},
// Video
{
"hatari_video_hires",
......@@ -212,6 +224,16 @@ static void update_variables(void)
ConfigureParams.DiskImage.FastFloppy = hatari_fastfdc;
}
// Audio
var.key = "hatari_polarized_filter";
var.value = NULL;
UseNonPolarizedLowPassFilter = true;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if(strcmp(var.value, "true") == 0)
UseNonPolarizedLowPassFilter = false;
}
// Video
var.key = "hatari_video_hires";
var.value = NULL;
......@@ -661,9 +683,6 @@ void retro_run(void)
if (MidiRetroInterface && MidiRetroInterface->output_enabled())
MidiRetroInterface->flush();
if (firstpass)
firstpass=0;
}
#define M3U_FILE_EXT "m3u"
......@@ -740,64 +759,48 @@ bool retro_load_game_special(unsigned type, const struct retro_game_info *info,
return false;
}
const char RETRO_SAVE_VERSION = 1;
char* retro_save_buffer = NULL;
int retro_save_pos = 0;
int retro_save_size = 0;
int retro_save_head = 1; // bytes reserved for libretro header/state
int retro_save_max = 0;
int retro_save_error = 0;
extern int hatari_mapper_serialize_size();
extern bool hatari_mapper_serialize(char* data, char version);
extern bool hatari_mapper_unserialize(const char* data, char version);
size_t retro_serialize_size(void)
{
if (firstpass != 1)
{
snprintf(savestate_fname, sizeof(savestate_fname), "%s%shatari_tempsave.uss", retro_save_directory, RETRO_PATH_SEPARATOR);
MemorySnapShot_Capture(savestate_fname, false);
FILE *file = fopen(savestate_fname, "rb");
if (file)
{
size_t size = 0;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fclose(file);
return size;
}
}
return 0;
return 10 * 1024 * 1024; // Hatari uncompressed savestates seem to be about 6MB
}
bool retro_serialize(void *data_, size_t size)
{
if (firstpass != 1)
{
snprintf(savestate_fname, sizeof(savestate_fname), "%s%shatari_tempsave.uss", retro_save_directory, RETRO_PATH_SEPARATOR);
MemorySnapShot_Capture(savestate_fname, false);
FILE *file = fopen(savestate_fname, "rb");
if (file)
{
if (fread(data_, size, 1, file) == 1)
{
fclose(file);
return true;
}
fclose(file);
}
}
return false;
retro_save_max = size;
retro_save_head = hatari_mapper_serialize_size() + 1;
if (size < retro_save_head) return false;
retro_save_buffer = data_;
memset(retro_save_buffer, 0, size);
retro_save_buffer[0] = RETRO_SAVE_VERSION;
retro_save_error = hatari_mapper_serialize(data_+1, retro_save_buffer[0]) ? 0 : 1;
retro_save_size = retro_save_head;
MemorySnapShot_Capture("", false);
return retro_save_error == 0;
}
bool retro_unserialize(const void *data_, size_t size)
{
if (firstpass != 1)
{
snprintf(savestate_fname, sizeof(savestate_fname), "%s%shatari_tempsave.uss", retro_save_directory, RETRO_PATH_SEPARATOR);
FILE *file = fopen(savestate_fname, "wb");
if (file)
{
if (fwrite(data_, size, 1, file) == 1)
{
fclose(file);
MemorySnapShot_Restore(savestate_fname, false);
return true;
}
else
fclose(file);
}
}
return false;
retro_save_max = size;
retro_save_head = hatari_mapper_serialize_size() + 1;
if (size < retro_save_head) return false;
retro_save_buffer = (void*)data_; // discarding const
if (retro_save_buffer[0] != RETRO_SAVE_VERSION) return false; // unknown version
retro_save_error = hatari_mapper_unserialize(data_+1, retro_save_buffer[0]) ? 0 : 1;
retro_save_size = size;
MemorySnapShot_Restore("", false);
return retro_save_error == 0;
}
void *retro_get_memory_data(unsigned id)
......
......@@ -330,7 +330,9 @@ return;
// FrameDuration_micro = (Sint64) ( 1000000.0 / nScreenRefreshRate + 0.5 ); /* round to closest integer */
FrameDuration_micro = ClocksTimings_GetVBLDuration_micro ( ConfigureParams.System.nMachineType , nScreenRefreshRate );
FrameDuration_micro *= nVBLSlowdown;
#ifndef __LIBRETRO__
CurrentTicks = Time_GetTicks();
#endif
if (DestTicks == 0) /* on first call, init DestTicks */
{
......@@ -339,6 +341,12 @@ return;
DestTicks += pulse_swallowing_count; /* audio.c - Audio_CallBack() */
#ifdef __LIBRETRO__
/* Libretro is responsible for synchronizing the timing, allowing it to drive fast-forward, etc. Every time this point
is reached, we must assume we're ready for exactly the next frame. */
CurrentTicks = DestTicks;
#endif
nDelay = DestTicks - CurrentTicks;
/* Do not wait if we are in fast forward mode or if we are totally out of sync */
......
......@@ -58,9 +58,11 @@ const char MemorySnapShot_fileid[] = "Hatari memorySnapShot.c : " __DATE__ " " _
#define VERSION_STRING "1.8.1" /* Version number of compatible memory snapshots - Always 6 bytes (inc' NULL) */
#define SNAPSHOT_MAGIC 0xDeadBeef
#ifndef __LIBRETRO__ /* snapshot sizes are not allowed to increase over time in libretro, so compression should not be used */
#if HAVE_LIBZ
#define COMPRESS_MEMORYSNAPSHOT /* Compress snapshots to reduce disk space used */
#endif
#endif
#ifdef COMPRESS_MEMORYSNAPSHOT
......@@ -69,6 +71,17 @@ const char MemorySnapShot_fileid[] = "Hatari memorySnapShot.c : " __DATE__ " " _
#include <zlib.h>
typedef gzFile MSS_File;
#elif defined(__LIBRETRO__)
/* Libretro will write to a memory buffer rather than a file. */
typedef void* MSS_File;
extern char* retro_save_buffer; /* allocated and managed by libretro */
extern int retro_save_pos; /* current read/write position */
extern int retro_save_size; /* highest used file position */
extern int retro_save_head; /* reserved space for libretro header */
extern int retro_save_max; /* maximum size of retro_save_buffer */
extern int retro_save_error; /* 0 if no error */
#else
typedef FILE* MSS_File;
......@@ -88,6 +101,15 @@ static MSS_File MemorySnapShot_fopen(const char *pszFileName, const char *pszMod
{
#ifdef COMPRESS_MEMORYSNAPSHOT
return gzopen(pszFileName, pszMode);
#elif defined(__LIBRETRO__)
retro_save_pos = retro_save_head;
if (retro_save_pos > retro_save_size) retro_save_size = retro_save_pos;
if (retro_save_buffer == NULL)
{
retro_save_error = 1;
return NULL;
}
return (void*)-1;
#else
return fopen(pszFileName, pszMode);
#endif
......@@ -102,6 +124,8 @@ static void MemorySnapShot_fclose(MSS_File fhndl)
{
#ifdef COMPRESS_MEMORYSNAPSHOT
gzclose(fhndl);
#elif defined(__LIBRETRO__)
/* Nothing to do. */
#else
fclose(fhndl);
#endif
......@@ -116,6 +140,18 @@ static int MemorySnapShot_fread(MSS_File fhndl, char *buf, int len)
{
#ifdef COMPRESS_MEMORYSNAPSHOT
return gzread(fhndl, buf, len);
#elif defined(__LIBRETRO__)
if (retro_save_pos + len <= retro_save_size)
{
memcpy(buf, retro_save_buffer + retro_save_pos, len);
retro_save_pos += len;
return len;
}
else
{
retro_save_error = 1;
return 0;
}
#else
return fread(buf, 1, len, fhndl);
#endif
......@@ -130,6 +166,19 @@ static int MemorySnapShot_fwrite(MSS_File fhndl, const char *buf, int len)
{
#ifdef COMPRESS_MEMORYSNAPSHOT
return gzwrite(fhndl, buf, len);
#elif defined(__LIBRETRO__)
if (retro_save_pos + len <= retro_save_max)
{
memcpy(retro_save_buffer + retro_save_pos, buf, len);
retro_save_pos += len;
if (retro_save_pos > retro_save_size) retro_save_size = retro_save_pos;
return len;
}
else
{
retro_save_error = 1;
return 0;
}
#else
return fwrite(buf, 1, len, fhndl);
#endif
......@@ -144,6 +193,9 @@ static int MemorySnapShot_fseek(MSS_File fhndl, int pos)
{
#ifdef COMPRESS_MEMORYSNAPSHOT
return (int)gzseek(fhndl, pos, SEEK_CUR); /* return -1 if error, new position >=0 if OK */
#elif defined(__LIBRETRO__)
retro_save_pos = retro_save_head + pos;
return 0;
#else
return fseek(fhndl, pos, SEEK_CUR); /* return -1 if error, 0 if OK */
#endif
......
......@@ -221,6 +221,9 @@ Uint8 SoundRegs[ 14 ];
int YmVolumeMixing = YM_TABLE_MIXING;
bool UseLowPassFilter = false;
#ifdef __LIBRETRO__
bool UseNonPolarizedLowPassFilter = true;
#endif
bool bEnvelopeFreqFlag; /* Cleared each frame for YM saving */
......@@ -381,7 +384,18 @@ static ymsample PWMaliasFilter(ymsample x0)
return y0;
}
#ifdef __LIBRETRO__
// A more "normal" alternative to the lowpass filters above,
// which affects rising and falling waves the same way rather than unequally.
// Removes a lot of unpleasant distortion.
static ymsample NonPolarizedLowPassFilter(ymsample x0)
{
static yms32 y0 = 0, x1 = 0;
y0 = (3*(x0 + x1) + (y0<<1)) >> 3;
x1 = x0;
return y0;
}
#endif
/*--------------------------------------------------------------*/
/* Build the volume conversion table used to simulate the */
......@@ -972,6 +986,11 @@ static ymsample YM2149_NextSample(void)
if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
#ifdef __LIBRETRO__
if ( UseNonPolarizedLowPassFilter )
return NonPolarizedLowPassFilter(sample);
#endif
/* Apply low pass filter ? */
if ( UseLowPassFilter )
return LowPassFilter(sample);
......@@ -1041,6 +1060,11 @@ static ymsample YM2149_NextSample(void)
if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
#ifdef __LIBRETRO__
if ( UseNonPolarizedLowPassFilter )
return NonPolarizedLowPassFilter(sample);
#endif
/* Apply low pass filter ? */
if ( UseLowPassFilter )
return LowPassFilter(sample);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment