Implement persistent buffer API support

This commit is contained in:
twinaphex 2021-06-07 02:49:46 +02:00
parent 40077aee14
commit 6fd2acba28
2 changed files with 505 additions and 107 deletions

View File

@ -282,6 +282,7 @@ enum retro_language
RETRO_LANGUAGE_PERSIAN = 20,
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_FINNISH = 23,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
@ -712,6 +713,9 @@ enum retro_mod
* state of rumble motors in controllers.
* A strong and weak motor is supported, and they can be
* controlled indepedently.
* Should be called from either retro_init() or retro_load_game().
* Should not be called from retro_set_environment().
* Returns false if rumble functionality is unavailable.
*/
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
/* uint64_t * --
@ -1374,6 +1378,121 @@ enum retro_mod
* call will target the newly initialized driver.
*/
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64
/* const struct retro_fastforwarding_override * --
* Used by a libretro core to override the current
* fastforwarding mode of the frontend.
* If NULL is passed to this function, the frontend
* will return true if fastforwarding override
* functionality is supported (no change in
* fastforwarding state will occur in this case).
*/
#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
/* const struct retro_system_content_info_override * --
* Allows an implementation to override 'global' content
* info parameters reported by retro_get_system_info().
* Overrides also affect subsystem content info parameters
* set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
* This function must be called inside retro_set_environment().
* If callback returns false, content info overrides
* are unsupported by the frontend, and will be ignored.
* If callback returns true, extended game info may be
* retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
* in retro_load_game() or retro_load_game_special().
*
* 'data' points to an array of retro_system_content_info_override
* structs terminated by a { NULL, false, false } element.
* If 'data' is NULL, no changes will be made to the frontend;
* a core may therefore pass NULL in order to test whether
* the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
* by the frontend.
*
* For struct member descriptions, see the definition of
* struct retro_system_content_info_override.
*
* Example:
*
* - struct retro_system_info:
* {
* "My Core", // library_name
* "v1.0", // library_version
* "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
* true, // need_fullpath
* false // block_extract
* }
*
* - Array of struct retro_system_content_info_override:
* {
* {
* "md|sms|gg", // extensions
* false, // need_fullpath
* true // persistent_data
* },
* {
* "sg", // extensions
* false, // need_fullpath
* false // persistent_data
* },
* { NULL, false, false }
* }
*
* Result:
* - Files of type m3u, cue, iso, chd will not be
* loaded by the frontend. Frontend will pass a
* valid path to the core, and core will handle
* loading internally
* - Files of type md, sms, gg will be loaded by
* the frontend. A valid memory buffer will be
* passed to the core. This memory buffer will
* remain valid until retro_deinit() returns
* - Files of type sg will be loaded by the frontend.
* A valid memory buffer will be passed to the core.
* This memory buffer will remain valid until
* retro_load_game() (or retro_load_game_special())
* returns
*
* NOTE: If an extension is listed multiple times in
* an array of retro_system_content_info_override
* structs, only the first instance will be registered
*/
#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
/* const struct retro_game_info_ext ** --
* Allows an implementation to fetch extended game
* information, providing additional content path
* and memory buffer status details.
* This function may only be called inside
* retro_load_game() or retro_load_game_special().
* If callback returns false, extended game information
* is unsupported by the frontend. In this case, only
* regular retro_game_info will be available.
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
* to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
* returns true.
*
* 'data' points to an array of retro_game_info_ext structs.
*
* For struct member descriptions, see the definition of
* struct retro_game_info_ext.
*
* - If function is called inside retro_load_game(),
* the retro_game_info_ext array is guaranteed to
* have a size of 1 - i.e. the returned pointer may
* be used to access directly the members of the
* first retro_game_info_ext struct, for example:
*
* struct retro_game_info_ext *game_info_ext;
* if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
* printf("Content Directory: %s\n", game_info_ext->dir);
*
* - If the function is called inside retro_load_game_special(),
* the retro_game_info_ext array is guaranteed to have a
* size equal to the num_info argument passed to
* retro_load_game_special()
*/
/* VFS functionality */
/* File paths:
@ -2777,6 +2896,213 @@ struct retro_system_info
bool block_extract;
};
/* Defines overrides which modify frontend handling of
* specific content file types.
* An array of retro_system_content_info_override is
* passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
* NOTE: In the following descriptions, references to
* retro_load_game() may be replaced with
* retro_load_game_special() */
struct retro_system_content_info_override
{
/* A list of file extensions for which the override
* should apply, delimited by a 'pipe' character
* (e.g. "md|sms|gg")
* Permitted file extensions are limited to those
* included in retro_system_info::valid_extensions
* and/or retro_subsystem_rom_info::valid_extensions */
const char *extensions;
/* Overrides the need_fullpath value set in
* retro_system_info and/or retro_subsystem_rom_info.
* To reiterate:
*
* If need_fullpath is true and retro_load_game() is called:
* - retro_game_info::path is guaranteed to contain a valid
* path to an existent file
* - retro_game_info::data and retro_game_info::size are invalid
*
* If need_fullpath is false and retro_load_game() is called:
* - retro_game_info::path may be NULL
* - retro_game_info::data and retro_game_info::size are guaranteed
* to be valid
*
* In addition:
*
* If need_fullpath is true and retro_load_game() is called:
* - retro_game_info_ext::full_path is guaranteed to contain a valid
* path to an existent file
* - retro_game_info_ext::archive_path may be NULL
* - retro_game_info_ext::archive_file may be NULL
* - retro_game_info_ext::dir is guaranteed to contain a valid path
* to the directory in which the content file exists
* - retro_game_info_ext::name is guaranteed to contain the
* basename of the content file, without extension
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file in lower case format
* - retro_game_info_ext::data and retro_game_info_ext::size
* are invalid
*
* If need_fullpath is false and retro_load_game() is called:
* - If retro_game_info_ext::file_in_archive is false:
* - retro_game_info_ext::full_path is guaranteed to contain
* a valid path to an existent file
* - retro_game_info_ext::archive_path may be NULL
* - retro_game_info_ext::archive_file may be NULL
* - retro_game_info_ext::dir is guaranteed to contain a
* valid path to the directory in which the content file exists
* - retro_game_info_ext::name is guaranteed to contain the
* basename of the content file, without extension
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file in lower case format
* - If retro_game_info_ext::file_in_archive is true:
* - retro_game_info_ext::full_path may be NULL
* - retro_game_info_ext::archive_path is guaranteed to
* contain a valid path to an existent compressed file
* inside which the content file is located
* - retro_game_info_ext::archive_file is guaranteed to
* contain a valid path to an existent content file
* inside the compressed file referred to by
* retro_game_info_ext::archive_path
* e.g. for a compressed file '/path/to/foo.zip'
* containing 'bar.sfc'
* > retro_game_info_ext::archive_path will be '/path/to/foo.zip'
* > retro_game_info_ext::archive_file will be 'bar.sfc'
* - retro_game_info_ext::dir is guaranteed to contain a
* valid path to the directory in which the compressed file
* (containing the content file) exists
* - retro_game_info_ext::name is guaranteed to contain
* EITHER
* 1) the basename of the compressed file (containing
* the content file), without extension
* OR
* 2) the basename of the content file inside the
* compressed file, without extension
* In either case, a core should consider 'name' to
* be the canonical name/ID of the the content file
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file inside the compressed file,
* in lower case format
* - retro_game_info_ext::data and retro_game_info_ext::size are
* guaranteed to be valid */
bool need_fullpath;
/* If need_fullpath is false, specifies whether the content
* data buffer available in retro_load_game() is 'persistent'
*
* If persistent_data is false and retro_load_game() is called:
* - retro_game_info::data and retro_game_info::size
* are valid only until retro_load_game() returns
* - retro_game_info_ext::data and retro_game_info_ext::size
* are valid only until retro_load_game() returns
*
* If persistent_data is true and retro_load_game() is called:
* - retro_game_info::data and retro_game_info::size
* are valid until retro_deinit() returns
* - retro_game_info_ext::data and retro_game_info_ext::size
* are valid until retro_deinit() returns */
bool persistent_data;
};
/* Similar to retro_game_info, but provides extended
* information about the source content file and
* game memory buffer status.
* And array of retro_game_info_ext is returned by
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
* NOTE: In the following descriptions, references to
* retro_load_game() may be replaced with
* retro_load_game_special() */
struct retro_game_info_ext
{
/* - If file_in_archive is false, contains a valid
* path to an existent content file (UTF-8 encoded)
* - If file_in_archive is true, may be NULL */
const char *full_path;
/* - If file_in_archive is false, may be NULL
* - If file_in_archive is true, contains a valid path
* to an existent compressed file inside which the
* content file is located (UTF-8 encoded) */
const char *archive_path;
/* - If file_in_archive is false, may be NULL
* - If file_in_archive is true, contain a valid path
* to an existent content file inside the compressed
* file referred to by archive_path (UTF-8 encoded)
* e.g. for a compressed file '/path/to/foo.zip'
* containing 'bar.sfc'
* > archive_path will be '/path/to/foo.zip'
* > archive_file will be 'bar.sfc' */
const char *archive_file;
/* - If file_in_archive is false, contains a valid path
* to the directory in which the content file exists
* (UTF-8 encoded)
* - If file_in_archive is true, contains a valid path
* to the directory in which the compressed file
* (containing the content file) exists (UTF-8 encoded) */
const char *dir;
/* Contains the canonical name/ID of the content file
* (UTF-8 encoded). Intended for use when identifying
* 'complementary' content named after the loaded file -
* i.e. companion data of a different format (a CD image
* required by a ROM), texture packs, internally handled
* save files, etc.
* - If file_in_archive is false, contains the basename
* of the content file, without extension
* - If file_in_archive is true, then string is
* implementation specific. A frontend may choose to
* set a name value of:
* EITHER
* 1) the basename of the compressed file (containing
* the content file), without extension
* OR
* 2) the basename of the content file inside the
* compressed file, without extension
* RetroArch sets the 'name' value according to (1).
* A frontend that supports routine loading of
* content from archives containing multiple unrelated
* content files may set the 'name' value according
* to (2). */
const char *name;
/* - If file_in_archive is false, contains the extension
* of the content file in lower case format
* - If file_in_archive is true, contains the extension
* of the content file inside the compressed file,
* in lower case format */
const char *ext;
/* String of implementation specific meta-data. */
const char *meta;
/* Memory buffer of loaded game content. Will be NULL:
* IF
* - retro_system_info::need_fullpath is true and
* retro_system_content_info_override::need_fullpath
* is unset
* OR
* - retro_system_content_info_override::need_fullpath
* is true */
const void *data;
/* Size of game content memory buffer, in bytes */
size_t size;
/* True if loaded content file is inside a compressed
* archive */
bool file_in_archive;
/* - If data is NULL, value is unset/ignored
* - If data is non-NULL:
* - If persistent_data is false, data and size are
* valid only until retro_load_game() returns
* - If persistent_data is true, data and size are
* are valid until retro_deinit() returns */
bool persistent_data;
};
struct retro_game_geometry
{
unsigned base_width; /* Nominal video width of game. */
@ -2934,6 +3260,47 @@ struct retro_framebuffer
Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
};
/* Used by a libretro core to override the current
* fastforwarding mode of the frontend */
struct retro_fastforwarding_override
{
/* Specifies the runtime speed multiplier that
* will be applied when 'fastforward' is true.
* For example, a value of 5.0 when running 60 FPS
* content will cap the fast-forward rate at 300 FPS.
* Note that the target multiplier may not be achieved
* if the host hardware has insufficient processing
* power.
* Setting a value of 0.0 (or greater than 0.0 but
* less than 1.0) will result in an uncapped
* fast-forward rate (limited only by hardware
* capacity).
* If the value is negative, it will be ignored
* (i.e. the frontend will use a runtime speed
* multiplier of its own choosing) */
float ratio;
/* If true, fastforwarding mode will be enabled.
* If false, fastforwarding mode will be disabled. */
bool fastforward;
/* If true, and if supported by the frontend, an
* on-screen notification will be displayed while
* 'fastforward' is true.
* If false, and if supported by the frontend, any
* on-screen fast-forward notifications will be
* suppressed */
bool notification;
/* If true, the core will have sole control over
* when fastforwarding mode is enabled/disabled;
* the frontend will not be able to change the
* state set by 'fastforward' until either
* 'inhibit_toggle' is set to false, or the core
* is unloaded */
bool inhibit_toggle;
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing

View File

@ -52,7 +52,8 @@ static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
static bool libretro_supports_bitmasks = false;
static bool libretro_supports_persistent_buffer = false;
static bool libretro_supports_bitmasks = false;
static bool overscan;
static double last_sound_rate;
@ -67,13 +68,13 @@ static unsigned rotate_joymap = 0;
static MDFN_Surface *surf = NULL;
static uint16_t *rotate_buf = NULL;
#define ROTATE_PIXEL_BUF(typename_t, src, width, height, dst) \
{ \
typename_t *in_ptr = (typename_t*)src; \
typename_t *out_ptr = (typename_t*)dst; \
size_t x, y; \
for (x = 0; x < width; x++) \
for (y = 0; y < height; y++) \
#define ROTATE_PIXEL_BUF(typename_t, src, width, height, dst) \
{ \
typename_t *in_ptr = (typename_t*)src; \
typename_t *out_ptr = (typename_t*)dst; \
size_t x, y; \
for (x = 0; x < width; x++) \
for (y = 0; y < height; y++) \
*(out_ptr + y + (((width - 1) - x) * height)) = *(in_ptr + x + (y * width)); \
}
@ -240,7 +241,7 @@ static void init_frameskip(void)
*/
int wsc = 1; /*color/mono*/
uint32 rom_size;
uint32 rom_size;
uint16 WSButtonStatus;
@ -248,21 +249,20 @@ static uint8 WSRCurrentSong;
MDFNGI EmulatedWSwan =
{
MDFN_MASTERCLOCK_FIXED(3072000),
0,
224, /* lcm_width */
144, /* lcm_height */
MDFN_MASTERCLOCK_FIXED(3072000),
0,
224, /* lcm_width */
144, /* lcm_height */
224, /* Nominal width */
144, /* Nominal height */
224, /* Nominal width */
144, /* Nominal height */
224, /* Framebuffer width */
144, /* Framebuffer height */
224, /* Framebuffer width */
144, /* Framebuffer height */
2, /* Number of output sound channels */
2, /* Number of output sound channels */
};
static void Reset(void)
{
int u0;
@ -289,8 +289,6 @@ static uint8 *chee;
static void Emulate(EmulateSpecStruct *espec, int16_t *sndbuf)
{
uint16 butt_data;
espec->DisplayRect.x = 0;
espec->DisplayRect.y = 0;
espec->DisplayRect.w = 224;
@ -303,9 +301,7 @@ static void Emulate(EmulateSpecStruct *espec, int16_t *sndbuf)
if(espec->SoundFormatChanged)
WSwan_SetSoundRate(RETRO_SAMPLE_RATE);
butt_data = chee[0] | (chee[1] << 8);
WSButtonStatus = butt_data;
WSButtonStatus = chee[0] | (chee[1] << 8);
MDFNMP_ApplyPeriodicCheats();
@ -371,11 +367,12 @@ static const DLEntry Developers[] =
static uint32 SRAMSize;
static int Load(const uint8_t *data, size_t size)
static int Load(bool persistent_data, const uint8_t *data, size_t size)
{
uint32 pow_size = 0;
uint32 real_rom_size = 0;
uint8 header[10];
uint32 pow_size = 0;
uint32 real_rom_size = 0;
bool is_detective_conan = false;
if(size < 65536)
return(0);
@ -384,37 +381,70 @@ static int Load(const uint8_t *data, size_t size)
pow_size = next_pow2(real_rom_size);
rom_size = pow_size + (pow_size == 0);
wsCartROM = (uint8 *)calloc(1, rom_size);
memcpy(header, data + rom_size - 10, 10);
/* This real_rom_size vs rom_size funny business
* is intended primarily for handling
* WSR files. */
if(real_rom_size < rom_size)
memset(wsCartROM, 0xFF, rom_size - real_rom_size);
/* Detective Conan */
is_detective_conan = ((header[8] | (header[9] << 8)) == 0x8de1 && (header[0]==0x01)&&(header[2]==0x27));
memcpy(wsCartROM + (rom_size - real_rom_size), data, size);
/* Detective Conan needs to manipulate wsCartROM,
* have to forcibly disable persistent buffer
* support unfortunately because of this */
if (is_detective_conan)
{
libretro_supports_persistent_buffer = false;
persistent_data = false;
}
memcpy(header, wsCartROM + rom_size - 10, 10);
if (persistent_data)
wsCartROM = (uint8 *)data;
else
{
wsCartROM = (uint8 *)calloc(1, rom_size);
SRAMSize = 0;
/* This real_rom_size vs rom_size funny business
* is intended primarily for handling
* WSR files. */
if (real_rom_size < rom_size)
memset(wsCartROM, 0xFF, rom_size - real_rom_size);
memcpy(wsCartROM + (rom_size - real_rom_size), data, size);
}
SRAMSize = 0;
eeprom_size = 0;
switch(header[5])
{
case 0x01: SRAMSize = 8 * 1024; break;
case 0x02: SRAMSize = 32 * 1024; break;
case 0x03: SRAMSize = 128 * 1024; break;
case 0x04: SRAMSize = 256 * 1024; break; /* Dicing Knight!, Judgement Silver */
case 0x05: SRAMSize = 512 * 1024; break; /* Wonder Gate */
case 0x10: eeprom_size = 128; break;
case 0x20: eeprom_size = 2 *1024; break;
case 0x50: eeprom_size = 1024; break;
case 0x01:
SRAMSize = 8 * 1024;
break;
case 0x02:
SRAMSize = 32 * 1024;
break;
case 0x03:
SRAMSize = 128 * 1024;
break;
case 0x04:
SRAMSize = 256 * 1024;
break; /* Dicing Knight!, Judgement Silver */
case 0x05:
SRAMSize = 512 * 1024;
break; /* Wonder Gate */
case 0x10:
eeprom_size = 128;
break;
case 0x20:
eeprom_size = 2 *1024;
break;
case 0x50:
eeprom_size = 1024;
break;
}
if((header[8] | (header[9] << 8)) == 0x8de1 && (header[0]==0x01)&&(header[2]==0x27)) /* Detective Conan */
if (is_detective_conan)
{
/* WS cpu is using cache/pipeline or there's protected ROM bank where pointing CS */
/* WS cpu is using cache/pipeline or
* there's protected ROM bank where pointing CS */
wsCartROM[0xfffe8]=0xea;
wsCartROM[0xfffe9]=0x00;
wsCartROM[0xfffea]=0x00;
@ -441,22 +471,10 @@ static int Load(const uint8_t *data, size_t size)
return(1);
}
static void CloseGame(void)
{
WSwan_MemoryKill();
WSwan_SoundKill();
if(wsCartROM)
{
free(wsCartROM);
wsCartROM = NULL;
}
}
static void SetInput(int port, const char *type, void *ptr)
{
if(!port) chee = (uint8 *)ptr;
if (!port)
chee = (uint8 *)ptr;
}
int StateAction(StateMem *sm, int load, int data_only)
@ -539,28 +557,6 @@ static InputInfoStruct InputInfo =
static bool update_video, update_audio;
static bool MDFNI_LoadGame(
const char *force_module, const uint8_t *data,
size_t size)
{
if(Load(data, size) <= 0)
return false;
MDFN_LoadGameCheats(NULL);
MDFNMP_InstallReadPatches();
return true;
}
static void MDFNI_CloseGame(void)
{
MDFN_FlushGameCheats(0);
CloseGame();
MDFNMP_Kill();
}
static void check_system_specs(void)
{
/* TODO - should theoretically be level 4, but apparently
@ -776,30 +772,23 @@ void retro_reset(void)
DoSimpleCommand(MDFN_MSC_RESET);
}
bool retro_load_game_special(unsigned a, const struct retro_game_info *b, size_t c)
bool retro_load_game_special(unsigned a,
const struct retro_game_info *b, size_t c)
{
return false;
}
static void set_volume (uint32_t *ptr, unsigned number)
{
switch(number)
{
default:
*ptr = number;
break;
}
}
#define MAX_PLAYERS 1
#define MAX_BUTTONS 11
static uint16_t input_buf;
bool retro_load_game(const struct retro_game_info *info)
{
const uint8_t *rom_data = NULL;
size_t rom_size = 0;
const unsigned rot_angle = 0;
struct retro_input_descriptor desc[] = {
const struct retro_game_info_ext *info_ext = NULL;
struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "X Cursor Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "X Cursor Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "X Cursor Down" },
@ -824,10 +813,25 @@ bool retro_load_game(const struct retro_game_info *info)
overscan = false;
environ_cb(RETRO_ENVIRONMENT_GET_OVERSCAN, &overscan);
if (!MDFNI_LoadGame(MEDNAFEN_CORE_NAME_MODULE,
(const uint8_t*)info->data, info->size))
if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext) &&
info_ext->persistent_data)
{
libretro_supports_persistent_buffer = true;
rom_data = (const uint8_t*)info_ext->data;
rom_size = info_ext->size;
}
else
{
libretro_supports_persistent_buffer = false;
rom_data = (const uint8_t*)info->data;
rom_size = info->size;
}
if (Load(libretro_supports_persistent_buffer, rom_data, rom_size) <= 0)
return false;
MDFN_LoadGameCheats(NULL);
MDFNMP_InstallReadPatches();
SetInput(0, "gamepad", &input_buf);
surf = (MDFN_Surface*)calloc(1, sizeof(*surf));
@ -865,24 +869,34 @@ bool retro_load_game(const struct retro_game_info *info)
}
}
rotate_tall = false;
rotate_tall = false;
select_pressed_last_frame = false;
rotate_joymap = 0;
rotate_joymap = 0;
check_variables(false);
WSwan_SetPixelFormat(RETRO_PIX_DEPTH,
mono_pal_start, mono_pal_end);
update_video = false;
update_audio = true;
update_video = false;
update_audio = true;
return true;
}
void retro_unload_game(void)
{
MDFNI_CloseGame();
MDFN_FlushGameCheats(0);
WSwan_MemoryKill();
WSwan_SoundKill();
if(wsCartROM)
{
if (!libretro_supports_persistent_buffer)
free(wsCartROM);
wsCartROM = NULL;
}
MDFNMP_Kill();
if (surf)
{
@ -895,6 +909,8 @@ void retro_unload_game(void)
if (rotate_buf)
free(rotate_buf);
rotate_buf = NULL;
libretro_supports_persistent_buffer = false;
}
static void update_input(void)
@ -969,7 +985,9 @@ static void update_input(void)
#endif
}
#ifdef DEBUG
static uint64_t video_frames, audio_frames;
#endif
void retro_run(void)
{
@ -1097,8 +1115,10 @@ void retro_run(void)
video_cb(NULL, height, width, FB_HEIGHT * RETRO_PIX_BYTES);
}
#ifdef DEBUG
video_frames++;
audio_frames += spec.SoundBufSize;
#endif
for (total = 0; total < spec.SoundBufSize; )
total += audio_batch_cb(sound_buf + total*2,
@ -1164,6 +1184,7 @@ void retro_deinit(void)
free(rotate_buf);
rotate_buf = NULL;
#ifdef DEBUG
if (log_cb)
{
log_cb(RETRO_LOG_INFO, "[%s]: Samples / Frame: %.5f\n",
@ -1171,6 +1192,7 @@ void retro_deinit(void)
log_cb(RETRO_LOG_INFO, "[%s]: Estimated FPS: %.5f\n",
MEDNAFEN_CORE_NAME, (double)video_frames * 44100 / audio_frames);
}
#endif
libretro_supports_bitmasks = false;
}
@ -1189,14 +1211,23 @@ void retro_set_controller_port_device(unsigned in_port, unsigned device) { }
void retro_set_environment(retro_environment_t cb)
{
static const struct retro_system_content_info_override content_overrides[] = {
{
MEDNAFEN_CORE_EXTENSIONS, /* extensions */
false, /* need_fullpath */
true /* persistent_data */
},
{ NULL, false, false }
};
environ_cb = cb;
libretro_set_core_options(environ_cb);
/* Request a persistent content data buffer */
environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE,
(void*)content_overrides);
}
void retro_set_audio_sample(retro_audio_sample_t cb)
{
}
void retro_set_audio_sample(retro_audio_sample_t cb) { }
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
@ -1252,7 +1283,7 @@ bool retro_serialize(void *data, size_t size)
st.malloced = size;
st.initial_malloc = 0;
ret = MDFNSS_SaveSM(&st, 0, 0, NULL, NULL, NULL);
ret = MDFNSS_SaveSM(&st, 0, 0, NULL, NULL, NULL);
memcpy(data, st.data, size);
free(st.data);