Begin fixing up SSNES for libretro.
This commit is contained in:
parent
9b57081097
commit
cd3c9a548c
294
dynamic.c
294
dynamic.c
|
@ -39,80 +39,61 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NEED_DYNAMIC
|
||||
#define DLSYM(lib, x) dylib_proc(lib, #x)
|
||||
|
||||
#define SYM(type, x) do { \
|
||||
p##x = (type)DLSYM(lib_handle, x); \
|
||||
#ifdef HAVE_DYNAMIC
|
||||
#define SYM(x) do { \
|
||||
function_t func = dylib_proc(lib, #x); \
|
||||
memcpy(&p##x, &func, sizeof(func)); \
|
||||
if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); ssnes_fail(1, "init_libsnes_sym()"); } \
|
||||
} while (0)
|
||||
|
||||
#define OPT_SYM(type, x) do { \
|
||||
p##x = (type)DLSYM(lib_handle, x); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DYNAMIC
|
||||
static dylib_t lib_handle = NULL;
|
||||
#else
|
||||
#define SYM(x) p##x = x
|
||||
#endif
|
||||
|
||||
void (*psnes_init)(void);
|
||||
void (*pretro_init)(void);
|
||||
void (*pretro_deinit)(void);
|
||||
|
||||
void (*psnes_set_video_refresh)(snes_video_refresh_t);
|
||||
void (*psnes_set_audio_sample)(snes_audio_sample_t);
|
||||
void (*psnes_set_input_poll)(snes_input_poll_t);
|
||||
void (*psnes_set_input_state)(snes_input_state_t);
|
||||
unsigned (*pretro_api_version)(void);
|
||||
|
||||
void (*psnes_reset)(void);
|
||||
void (*psnes_run)(void);
|
||||
void (*pretro_get_system_info)(struct retro_system_info*);
|
||||
void (*pretro_get_system_av_info)(struct retro_system_av_info*);
|
||||
|
||||
void (*psnes_cheat_reset)(void);
|
||||
void (*psnes_cheat_set)(unsigned, bool, const char*);
|
||||
void (*pretro_set_environment)(retro_environment_t);
|
||||
void (*pretro_set_video_refresh)(retro_video_refresh_t);
|
||||
void (*pretro_set_audio_sample)(retro_audio_sample_t);
|
||||
void (*pretro_set_audio_sample_batch)(retro_audio_sample_batch_t);
|
||||
void (*pretro_set_input_poll)(retro_input_poll_t);
|
||||
void (*pretro_set_input_state)(retro_input_state_t);
|
||||
|
||||
const char *(*psnes_library_id)(void) = NULL;
|
||||
unsigned (*psnes_library_revision_minor)(void);
|
||||
unsigned (*psnes_library_revision_major)(void);
|
||||
void (*pretro_set_controller_port_device)(bool, unsigned);
|
||||
|
||||
bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned);
|
||||
bool (*psnes_load_cartridge_super_game_boy)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
bool (*psnes_load_cartridge_bsx)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
bool (*psnes_load_cartridge_bsx_slotted)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
bool (*psnes_load_cartridge_sufami_turbo)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
void (*pretro_reset)(void);
|
||||
void (*pretro_run)(void);
|
||||
|
||||
void (*psnes_set_controller_port_device)(bool, unsigned);
|
||||
size_t (*pretro_serialize_size)(void);
|
||||
bool (*pretro_serialize)(void*, size_t);
|
||||
bool (*pretro_unserialize)(const void*, size_t);
|
||||
|
||||
bool (*psnes_get_region)(void);
|
||||
void (*pretro_cheat_reset)(void);
|
||||
void (*pretro_cheat_set)(unsigned, bool, const char*);
|
||||
|
||||
unsigned (*psnes_serialize_size)(void);
|
||||
bool (*psnes_serialize)(uint8_t*, unsigned);
|
||||
bool (*psnes_unserialize)(const uint8_t*, unsigned);
|
||||
bool (*pretro_load_game)(const retro_game_info*);
|
||||
bool (*pretro_load_game_special)(unsigned, const retro_game_info*, size_t);
|
||||
|
||||
void (*psnes_set_cartridge_basename)(const char*);
|
||||
void (*pretro_unload_game)(void);
|
||||
|
||||
uint8_t* (*psnes_get_memory_data)(unsigned);
|
||||
unsigned (*psnes_get_memory_size)(unsigned);
|
||||
unsigned (*pretro_get_region)(void);
|
||||
|
||||
void (*psnes_unload_cartridge)(void);
|
||||
void (*psnes_term)(void);
|
||||
void *(*pretro_get_memory_data)(unsigned);
|
||||
size_t (*pretro_get_memory_size)(unsigned);
|
||||
|
||||
#if defined(NEED_DYNAMIC) || defined(SSNES_CONSOLE)
|
||||
static void set_environment(void);
|
||||
#endif
|
||||
static void set_environment_defaults(void);
|
||||
|
||||
#ifdef HAVE_DYNAMIC
|
||||
static void load_dynamic(void)
|
||||
static void load_symbols(void)
|
||||
{
|
||||
#ifdef HAVE_DYNAMIC
|
||||
SSNES_LOG("Loading dynamic libsnes from: \"%s\"\n", g_settings.libsnes);
|
||||
lib_handle = dylib_load(g_settings.libsnes);
|
||||
if (!lib_handle)
|
||||
|
@ -120,77 +101,43 @@ static void load_dynamic(void)
|
|||
SSNES_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libsnes);
|
||||
ssnes_fail(1, "load_dynamic()");
|
||||
}
|
||||
|
||||
SYM(void (*)(void), snes_init);
|
||||
SYM(void (*)(snes_video_refresh_t), snes_set_video_refresh);
|
||||
SYM(void (*)(snes_audio_sample_t), snes_set_audio_sample);
|
||||
SYM(void (*)(snes_input_poll_t), snes_set_input_poll);
|
||||
SYM(void (*)(snes_input_state_t), snes_set_input_state);
|
||||
SYM(const char *(*)(void), snes_library_id);
|
||||
SYM(unsigned (*)(void), snes_library_revision_minor);
|
||||
SYM(unsigned (*)(void), snes_library_revision_major);
|
||||
SYM(void (*)(void), snes_cheat_reset);
|
||||
SYM(void (*)(unsigned, bool, const char*), snes_cheat_set);
|
||||
SYM(void (*)(void), snes_reset);
|
||||
SYM(void (*)(void), snes_run);
|
||||
SYM(bool (*)(void), snes_get_region);
|
||||
SYM(bool (*)(const char*, const uint8_t*, unsigned), snes_load_cartridge_normal);
|
||||
SYM(bool (*)(const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned), snes_load_cartridge_super_game_boy);
|
||||
SYM(bool (*)(const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned), snes_load_cartridge_bsx);
|
||||
SYM(bool (*)(const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned), snes_load_cartridge_bsx_slotted);
|
||||
SYM(bool (*)(const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned), snes_load_cartridge_sufami_turbo);
|
||||
SYM(void (*)(bool, unsigned), snes_set_controller_port_device);
|
||||
SYM(unsigned (*)(void), snes_serialize_size);
|
||||
SYM(bool (*)(uint8_t*, unsigned), snes_serialize);
|
||||
SYM(bool (*)(const uint8_t*, unsigned), snes_unserialize);
|
||||
SYM(void (*)(const char*), snes_set_cartridge_basename);
|
||||
SYM(uint8_t *(*)(unsigned), snes_get_memory_data);
|
||||
SYM(unsigned (*)(unsigned), snes_get_memory_size);
|
||||
SYM(void (*)(void), snes_unload_cartridge);
|
||||
SYM(void (*)(void), snes_term);
|
||||
}
|
||||
#else
|
||||
#define SSYM(x) do { \
|
||||
p##x = x; \
|
||||
} while (0)
|
||||
|
||||
static void set_statics(void)
|
||||
{
|
||||
SSYM(snes_init);
|
||||
SSYM(snes_set_video_refresh);
|
||||
SSYM(snes_set_audio_sample);
|
||||
SSYM(snes_set_input_poll);
|
||||
SSYM(snes_set_input_state);
|
||||
SSYM(snes_library_revision_minor);
|
||||
SSYM(snes_library_revision_major);
|
||||
SSYM(snes_library_id);
|
||||
SSYM(snes_cheat_reset);
|
||||
SSYM(snes_cheat_set);
|
||||
SSYM(snes_reset);
|
||||
SSYM(snes_run);
|
||||
SSYM(snes_get_region);
|
||||
SSYM(snes_load_cartridge_normal);
|
||||
SSYM(snes_load_cartridge_super_game_boy);
|
||||
SSYM(snes_load_cartridge_bsx);
|
||||
SSYM(snes_load_cartridge_bsx_slotted);
|
||||
SSYM(snes_load_cartridge_sufami_turbo);
|
||||
SSYM(snes_set_controller_port_device);
|
||||
SSYM(snes_serialize_size);
|
||||
SSYM(snes_serialize);
|
||||
SSYM(snes_unserialize);
|
||||
SSYM(snes_set_cartridge_basename);
|
||||
SSYM(snes_get_memory_data);
|
||||
SSYM(snes_get_memory_size);
|
||||
SSYM(snes_unload_cartridge);
|
||||
SSYM(snes_term);
|
||||
}
|
||||
#endif
|
||||
|
||||
SYM(retro_init);
|
||||
SYM(retro_deinit);
|
||||
|
||||
SYM(retro_api_version);
|
||||
SYM(retro_get_system_info);
|
||||
SYM(retro_get_system_av_info);
|
||||
|
||||
SYM(retro_set_environment);
|
||||
SYM(retro_set_video_refresh);
|
||||
SYM(retro_set_audio_sample);
|
||||
SYM(retro_set_audio_sample_batch);
|
||||
SYM(retro_set_input_poll);
|
||||
SYM(retro_set_input_state);
|
||||
|
||||
SYM(retro_set_controller_port_device);
|
||||
|
||||
SYM(retro_reset);
|
||||
SYM(retro_run);
|
||||
|
||||
SYM(retro_serialize_size);
|
||||
SYM(retro_serialize);
|
||||
SYM(retro_unserialize);
|
||||
|
||||
SYM(retro_cheat_reset);
|
||||
SYM(retro_cheat_set);
|
||||
|
||||
SYM(retro_load_game);
|
||||
SYM(retro_load_game_special);
|
||||
|
||||
SYM(retro_unload_game);
|
||||
SYM(retro_get_region);
|
||||
SYM(retro_get_memory_data);
|
||||
SYM(retro_get_memory_size);
|
||||
}
|
||||
|
||||
void init_libsnes_sym(void)
|
||||
{
|
||||
// Guarantee that we can do "dirty" casting.
|
||||
|
@ -200,7 +147,7 @@ void init_libsnes_sym(void)
|
|||
#ifdef HAVE_DYNAMIC
|
||||
// Try to verify that -lsnes was not linked in from other modules
|
||||
// since loading it dynamically and with -l will fail hard.
|
||||
function_t sym = dylib_proc(NULL, "snes_init");
|
||||
function_t sym = dylib_proc(NULL, "retro_init");
|
||||
if (sym)
|
||||
{
|
||||
SSNES_ERR("Serious problem. SSNES wants to load libsnes dyamically, but it is already linked.\n");
|
||||
|
@ -212,23 +159,19 @@ void init_libsnes_sym(void)
|
|||
if (!*g_settings.libsnes)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
strlcpy(g_settings.libsnes, "snes.dll", sizeof(g_settings.libsnes));
|
||||
strlcpy(g_settings.libsnes, "retro.dll", sizeof(g_settings.libsnes));
|
||||
#elif defined(__APPLE__)
|
||||
strlcpy(g_settings.libsnes, "libsnes.dylib", sizeof(g_settings.libsnes));
|
||||
strlcpy(g_settings.libsnes, "libretro.dylib", sizeof(g_settings.libsnes));
|
||||
#else
|
||||
strlcpy(g_settings.libsnes, "libsnes.so", sizeof(g_settings.libsnes));
|
||||
strlcpy(g_settings.libsnes, "libretro.so", sizeof(g_settings.libsnes));
|
||||
#endif
|
||||
}
|
||||
|
||||
load_dynamic();
|
||||
#else
|
||||
set_statics();
|
||||
#endif
|
||||
|
||||
load_symbols();
|
||||
|
||||
set_environment_defaults();
|
||||
#if defined(NEED_DYNAMIC) || defined(SSNES_CONSOLE)
|
||||
set_environment();
|
||||
#endif
|
||||
}
|
||||
|
||||
void uninit_libsnes_sym(void)
|
||||
|
@ -289,46 +232,15 @@ void dylib_close(dylib_t lib)
|
|||
}
|
||||
#endif
|
||||
|
||||
unsigned audio_sample_batch(const int16_t *, unsigned);
|
||||
|
||||
#if defined(NEED_DYNAMIC) || defined(SSNES_CONSOLE)
|
||||
static bool environment_cb(unsigned cmd, void *data)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNES_ENVIRONMENT_GET_FULLPATH:
|
||||
*(const char**)data = g_extern.system.fullpath;
|
||||
SSNES_LOG("Environ FULLPATH: \"%s\"\n", g_extern.system.fullpath);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_GEOMETRY:
|
||||
g_extern.system.geom = *(const struct snes_geometry*)data;
|
||||
g_extern.system.geom.max_width = next_pow2(g_extern.system.geom.max_width);
|
||||
g_extern.system.geom.max_height = next_pow2(g_extern.system.geom.max_height);
|
||||
SSNES_LOG("Environ SET_GEOMETRY: (%ux%u) / (%ux%u)\n",
|
||||
g_extern.system.geom.base_width,
|
||||
g_extern.system.geom.base_height,
|
||||
g_extern.system.geom.max_width,
|
||||
g_extern.system.geom.max_height);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_PITCH:
|
||||
g_extern.system.pitch = *(const unsigned*)data;
|
||||
SSNES_LOG("Environ SET_PITCH: %u\n", g_extern.system.pitch);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_OVERSCAN:
|
||||
*(bool*)data = !g_settings.video.crop_overscan;
|
||||
SSNES_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!g_settings.video.crop_overscan);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_TIMING:
|
||||
g_extern.system.timing = *(const struct snes_system_timing*)data;
|
||||
g_extern.system.timing_set = true;
|
||||
SSNES_LOG("Environ SET_TIMING: %.3f Hz/ %.3f Hz\n",
|
||||
(float)g_extern.system.timing.fps, (float)g_extern.system.timing.sample_rate);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_CAN_DUPE:
|
||||
#ifdef HAVE_FFMPEG
|
||||
*(bool*)data = true;
|
||||
|
@ -339,16 +251,6 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
#endif
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_NEED_FULLPATH:
|
||||
g_extern.system.need_fullpath = *(const bool*)data;
|
||||
SSNES_LOG("Environ SET_NEED_FULLPATH: %s\n", g_extern.system.need_fullpath ? "true" : "false");
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_CAN_REWIND:
|
||||
*(bool*)data = g_settings.rewind_enable;
|
||||
SSNES_LOG("Environ GET_CAN_REWIND: %s\n", g_settings.rewind_enable ? "true" : "false");
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_VARIABLE:
|
||||
{
|
||||
struct snes_variable *var = (struct snes_variable*)data;
|
||||
|
@ -393,16 +295,6 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef SSNES_CONSOLE
|
||||
case SNES_ENVIRONMENT_SET_BATCH_LOAD:
|
||||
g_console.block_zip_extract = *(const bool*)data;
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_ROM_FORMATS:
|
||||
ssnes_console_set_rom_ext((const char*)data);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SNES_ENVIRONMENT_SET_MESSAGE:
|
||||
{
|
||||
const struct snes_message *msg = (const struct snes_message*)data;
|
||||
|
@ -412,11 +304,6 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
case SNES_ENVIRONMENT_GET_AUDIO_BATCH_CB:
|
||||
SSNES_LOG("Environ GET_AUDIO_BATCH_CB\n");
|
||||
*(snes_audio_sample_batch_t*)data = audio_sample_batch;
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_SET_ROTATION:
|
||||
{
|
||||
unsigned rotation = *(const unsigned*)data;
|
||||
|
@ -436,11 +323,6 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
case SNES_ENVIRONMENT_SET_CORE_VERSION:
|
||||
strlcpy(g_extern.system.version, (const char*)data, sizeof(g_extern.system.version));
|
||||
SSNES_LOG("Environ SET_CORE_VERSION: %s\n", g_extern.system.version);
|
||||
break;
|
||||
|
||||
default:
|
||||
SSNES_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
|
||||
return false;
|
||||
|
@ -450,40 +332,14 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef NEED_DYNAMIC
|
||||
// SSNES extension hooks. Totally optional 'n shizz :)
|
||||
static void set_environment(void)
|
||||
{
|
||||
#ifdef HAVE_DYNAMIC
|
||||
dylib_t lib = lib_handle;
|
||||
#else
|
||||
dylib_t lib = NULL;
|
||||
#endif
|
||||
|
||||
void (*psnes_set_environment)(snes_environment_t) =
|
||||
(void (*)(snes_environment_t))dylib_proc(lib, "snes_set_environment");
|
||||
|
||||
if (psnes_set_environment)
|
||||
psnes_set_environment(environment_cb);
|
||||
pretro_set_environment(environment_cb);
|
||||
}
|
||||
#elif defined(SSNES_CONSOLE)
|
||||
// Not very optional when we're running on a console without dynamic loading support.
|
||||
static void set_environment(void)
|
||||
{
|
||||
snes_set_environment(environment_cb);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume SNES as defaults.
|
||||
static void set_environment_defaults(void)
|
||||
{
|
||||
SSNES_LOG("Setting environment defaults (SNES)\n");
|
||||
g_extern.system.pitch = 0; // 0 is classic libsnes semantics.
|
||||
g_extern.system.geom.base_width = 256;
|
||||
g_extern.system.geom.base_height = 224;
|
||||
g_extern.system.geom.max_width = 512;
|
||||
g_extern.system.geom.max_height = 512;
|
||||
|
||||
// Split up environment variables beforehand.
|
||||
if (g_extern.system.environment_split && strtok(g_extern.system.environment_split, ";"))
|
||||
while (strtok(NULL, ";"));
|
||||
|
|
67
dynamic.h
67
dynamic.h
|
@ -19,7 +19,7 @@
|
|||
#define __DYNAMIC_H
|
||||
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
|
@ -31,8 +31,8 @@
|
|||
#undef NEED_DYNAMIC
|
||||
#endif
|
||||
|
||||
void init_libsnes_sym(void);
|
||||
void uninit_libsnes_sym(void);
|
||||
void init_libretro_sym(void);
|
||||
void uninit_libretro_sym(void);
|
||||
|
||||
typedef void *dylib_t;
|
||||
#ifdef NEED_DYNAMIC
|
||||
|
@ -43,53 +43,42 @@ void dylib_close(dylib_t lib);
|
|||
function_t dylib_proc(dylib_t lib, const char *proc);
|
||||
#endif
|
||||
|
||||
extern void (*psnes_init)(void);
|
||||
extern void (*pretro_init)(void);
|
||||
extern void (*pretro_deinit)(void);
|
||||
|
||||
extern void (*psnes_set_video_refresh)(snes_video_refresh_t);
|
||||
extern void (*psnes_set_audio_sample)(snes_audio_sample_t);
|
||||
extern void (*psnes_set_input_poll)(snes_input_poll_t);
|
||||
extern void (*psnes_set_input_state)(snes_input_state_t);
|
||||
extern unsigned (*pretro_api_version)(void);
|
||||
|
||||
extern void (*psnes_cheat_reset)(void);
|
||||
extern void (*psnes_cheat_set)(unsigned, bool, const char*);
|
||||
extern void (*pretro_get_system_info)(struct retro_system_info*);
|
||||
extern void (*pretro_get_system_av_info)(struct retro_system_av_info*);
|
||||
|
||||
extern const char *(*psnes_library_id)(void);
|
||||
extern unsigned (*psnes_library_revision_minor)(void);
|
||||
extern unsigned (*psnes_library_revision_major)(void);
|
||||
extern void (*pretro_set_environment)(retro_environment_t);
|
||||
extern void (*pretro_set_video_refresh)(retro_video_refresh_t);
|
||||
extern void (*pretro_set_audio_sample)(retro_audio_sample_t);
|
||||
extern void (*pretro_set_audio_sample_batch)(retro_audio_sample_batch_t);
|
||||
extern void (*pretro_set_input_poll)(retro_input_poll_t);
|
||||
extern void (*pretro_set_input_state)(retro_input_state_t);
|
||||
|
||||
extern bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned);
|
||||
extern bool (*psnes_load_cartridge_super_game_boy)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
extern bool (*psnes_load_cartridge_bsx)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
extern bool (*psnes_load_cartridge_bsx_slotted)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
extern bool (*psnes_load_cartridge_sufami_turbo)(
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned,
|
||||
const char*, const uint8_t*, unsigned);
|
||||
extern void (*pretro_set_controller_port_device)(bool, unsigned);
|
||||
|
||||
extern void (*psnes_set_controller_port_device)(bool, unsigned);
|
||||
extern void (*pretro_reset)(void);
|
||||
extern void (*pretro_run)(void);
|
||||
|
||||
extern bool (*psnes_get_region)(void);
|
||||
extern size_t (*pretro_serialize_size)(void);
|
||||
extern bool (*pretro_serialize)(void*, size_t);
|
||||
extern bool (*pretro_unserialize)(const void*, size_t);
|
||||
|
||||
extern unsigned (*psnes_serialize_size)(void);
|
||||
extern bool (*psnes_serialize)(uint8_t*, unsigned);
|
||||
extern bool (*psnes_unserialize)(const uint8_t*, unsigned);
|
||||
extern void (*pretro_cheat_reset)(void);
|
||||
extern void (*pretro_cheat_set)(unsigned, bool, const char*);
|
||||
|
||||
extern void (*psnes_reset)(void);
|
||||
extern void (*psnes_run)(void);
|
||||
extern bool (*pretro_load_game)(const struct retro_game_info*);
|
||||
extern bool (*pretro_load_game_special)(unsigned, const struct retro_game_info*, size_t);
|
||||
|
||||
extern void (*psnes_set_cartridge_basename)(const char*);
|
||||
extern void (*pretro_unload_game)(void);
|
||||
|
||||
extern uint8_t* (*psnes_get_memory_data)(unsigned);
|
||||
extern unsigned (*psnes_get_memory_size)(unsigned);
|
||||
extern unsigned (*pretro_get_region)(void);
|
||||
|
||||
extern void (*psnes_unload_cartridge)(void);
|
||||
extern void (*psnes_term)(void);
|
||||
extern void *(*pretro_get_memory_data)(unsigned);
|
||||
extern size_t (*pretro_get_memory_size)(unsigned);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
13
general.h
13
general.h
|
@ -298,18 +298,16 @@ struct global
|
|||
|
||||
struct
|
||||
{
|
||||
struct snes_geometry geom;
|
||||
unsigned pitch; // If 0, has classic libsnes semantics.
|
||||
struct retro_game_geometry geom;
|
||||
struct retro_system_timing timing;
|
||||
struct retro_system_info info;
|
||||
|
||||
char fullpath[PATH_MAX];
|
||||
struct snes_system_timing timing;
|
||||
bool timing_set;
|
||||
bool need_fullpath;
|
||||
|
||||
char *environment;
|
||||
char *environment_split;
|
||||
|
||||
unsigned rotation;
|
||||
char version[64];
|
||||
} system;
|
||||
|
||||
struct
|
||||
|
@ -416,9 +414,10 @@ struct global
|
|||
|
||||
struct
|
||||
{
|
||||
const uint16_t *data;
|
||||
const void *data;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
size_t pitch;
|
||||
} frame_cache;
|
||||
|
||||
char title_buf[64];
|
||||
|
|
95
libretro.h
95
libretro.h
|
@ -19,6 +19,7 @@ extern "C" {
|
|||
#define RETRO_DEVICE_KEYBOARD 3
|
||||
#define RETRO_DEVICE_LIGHTGUN 4
|
||||
|
||||
#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD)
|
||||
#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
|
@ -51,9 +52,9 @@ extern "C" {
|
|||
#define RETRO_REGION_NTSC 0
|
||||
#define RETRO_REGION_PAL 1
|
||||
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
#define RETRO_MEMORY_RTC 1
|
||||
#define RETRO_MEMORY_SYSTEM_RAM 2
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
#define RETRO_MEMORY_RTC 1
|
||||
#define RETRO_MEMORY_SYSTEM_RAM 2
|
||||
|
||||
#define RETRO_MEMORY_SNES_BSX_RAM 0x100
|
||||
#define RETRO_MEMORY_SNES_BSX_PRAM 0x101
|
||||
|
@ -62,52 +63,45 @@ extern "C" {
|
|||
#define RETRO_MEMORY_SNES_GAME_BOY_RAM 0x104
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RTC 0x105
|
||||
|
||||
#define RETRO_GAME_TYPE_BSX 0x100
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x101
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x102
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x103
|
||||
#define RETRO_GAME_TYPE_BSX 0x100
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x101
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x102
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x103
|
||||
|
||||
|
||||
// Environment commands.
|
||||
#define RETRO_ENVIRONMENT_SET_GEOMETRY 1 // const struct retro_geometry * --
|
||||
// Window geometry information for the system/game.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_TIMING 2 // const struct retro_system_timing * --
|
||||
// Set exact timings of the system. Used primarily for video recording.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_ROTATION 3 // const unsigned * --
|
||||
#define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * --
|
||||
// Sets screen rotation of graphics.
|
||||
// Is only implemented if rotation can be accelerated by hardware.
|
||||
// Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, 270 degrees
|
||||
// counter-clockwise respectively.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_OVERSCAN 4 // bool * --
|
||||
// Boolean value whether or not the implementation should use overscan.
|
||||
#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 // bool * --
|
||||
// Boolean value whether or not the implementation should use overscan, or crop away overscan.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_CAN_DUPE 5 // bool * --
|
||||
#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 // bool * --
|
||||
// Boolean value whether or not SSNES supports frame duping,
|
||||
// passing NULL to video frame callback.
|
||||
//
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_VARIABLE 6 // struct retro_variable * --
|
||||
#define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * --
|
||||
// Interface to aquire user-defined information from environment
|
||||
// that cannot feasibly be supported in a multi-system way.
|
||||
// Mostly used for obscure,
|
||||
// specific features that the user can tap into when neseccary.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_VARIABLES 7 // const struct retro_variable * --
|
||||
#define RETRO_ENVIRONMENT_SET_VARIABLES 5 // const struct retro_variable * --
|
||||
// Allows an implementation to signal the environment
|
||||
// which variables it might want to check for later using GET_VARIABLE.
|
||||
// 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element.
|
||||
// retro_variable::value should contain a human readable description of the key.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_MESSAGE 8 // const struct retro_message * --
|
||||
#define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * --
|
||||
// Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'.
|
||||
|
||||
struct retro_message
|
||||
{
|
||||
const char *msg;
|
||||
unsigned frames;
|
||||
unsigned frames;
|
||||
};
|
||||
|
||||
struct retro_system_info
|
||||
|
@ -115,7 +109,27 @@ struct retro_system_info
|
|||
const char *library_name;
|
||||
const char *library_version;
|
||||
const char *valid_extensions;
|
||||
bool need_fullpath;
|
||||
bool need_fullpath;
|
||||
};
|
||||
|
||||
struct retro_game_geometry
|
||||
{
|
||||
unsigned base_width; // Nominal video width of game.
|
||||
unsigned base_height; // Nominal video height of game.
|
||||
unsigned max_width; // Maximum possible width of game.
|
||||
unsigned max_height; // Maximum possible height of game.
|
||||
};
|
||||
|
||||
struct retro_system_timing
|
||||
{
|
||||
double fps; // FPS of video content.
|
||||
double sample_rate; // Sampling rate of audio.
|
||||
};
|
||||
|
||||
struct retro_system_av_info
|
||||
{
|
||||
struct retro_game_geometry geometry;
|
||||
struct retro_system_timing timing;
|
||||
};
|
||||
|
||||
struct retro_variable
|
||||
|
@ -127,26 +141,13 @@ struct retro_variable
|
|||
const char *value; // Value to be obtained. If key does not exist, it is set to NULL.
|
||||
};
|
||||
|
||||
struct retro_game_geometry
|
||||
{
|
||||
unsigned base_width; // Nominal video width of system.
|
||||
unsigned base_height; // Nominal video height of system.
|
||||
unsigned max_width; // Maximum possible width of system.
|
||||
unsigned max_height; // Maximum possible height of system.
|
||||
};
|
||||
|
||||
struct retro_game_info
|
||||
{
|
||||
const char *path;
|
||||
const void *game_data;
|
||||
size_t game_size;
|
||||
const char *game_meta;
|
||||
};
|
||||
|
||||
struct retro_system_timing
|
||||
{
|
||||
double fps;
|
||||
double sample_rate;
|
||||
const char *path; // Path to game. Usually used as a reference.
|
||||
const void *data; // Memory buffer of loaded game. If the game is too big to load in one go. SET_NEED_FULLPATH should be used.
|
||||
// In this case, data and size will be 0, and game can be loaded from path.
|
||||
size_t size; // Size of memory buffer.
|
||||
const char *meta; // String of implementation specific meta-data.
|
||||
};
|
||||
|
||||
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
|
||||
|
@ -157,9 +158,13 @@ typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames)
|
|||
typedef void (*retro_input_poll_t)(void);
|
||||
typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
||||
void retro_init(void);
|
||||
void retro_deinit(void);
|
||||
|
||||
unsigned retro_api_version(void);
|
||||
|
||||
void retro_get_system_info(struct retro_system_info *info);
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
|
||||
void retro_set_environment(retro_environment_t);
|
||||
void retro_set_video_refresh(retro_video_refresh_t);
|
||||
|
@ -170,9 +175,6 @@ void retro_set_input_state(retro_input_state_t);
|
|||
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
void retro_init(void);
|
||||
void retro_deinit(void);
|
||||
|
||||
void retro_reset(void);
|
||||
void retro_run(void);
|
||||
|
||||
|
@ -183,10 +185,7 @@ bool retro_unserialize(const void *data, size_t size);
|
|||
void retro_cheat_reset(void);
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code);
|
||||
|
||||
bool retro_load_game(const char *game_path,
|
||||
const void *game_data, size_t game_size,
|
||||
const char *game_meta
|
||||
);
|
||||
bool retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
bool retro_load_game_special(
|
||||
unsigned game_type,
|
||||
|
|
25
netplay.h
25
netplay.h
|
@ -20,30 +20,33 @@
|
|||
#define __SSNES_NETPLAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
|
||||
void input_poll_net(void);
|
||||
int16_t input_state_net(bool port, unsigned device, unsigned index, unsigned id);
|
||||
void video_frame_net(const uint16_t *data, unsigned width, unsigned height);
|
||||
void audio_sample_net(uint16_t left, uint16_t right);
|
||||
int16_t input_state_net(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
void video_frame_net(const uint16_t *data, unsigned width, unsigned height, size_t pitch);
|
||||
void audio_sample_net(int16_t left, int16_t right);
|
||||
void audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||
|
||||
int16_t input_state_spectate(bool port, unsigned device, unsigned index, unsigned id);
|
||||
int16_t input_state_spectate_client(bool port, unsigned device, unsigned index, unsigned id);
|
||||
int16_t input_state_spectate(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
int16_t input_state_spectate_client(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
||||
typedef struct netplay netplay_t;
|
||||
|
||||
struct snes_callbacks
|
||||
struct retro_callbacks
|
||||
{
|
||||
snes_video_refresh_t frame_cb;
|
||||
snes_audio_sample_t sample_cb;
|
||||
snes_input_state_t state_cb;
|
||||
retro_video_refresh_t frame_cb;
|
||||
retro_audio_sample_t sample_cb;
|
||||
retro_audio_sample_batch_t sample_batch_cb;
|
||||
retro_input_state_t state_cb;
|
||||
};
|
||||
|
||||
// Creates a new netplay handle. A NULL host means we're hosting (player 1). :)
|
||||
netplay_t *netplay_new(const char *server,
|
||||
uint16_t port, unsigned frames,
|
||||
const struct snes_callbacks *cb, bool spectate,
|
||||
const struct retro_callbacks *cb, bool spectate,
|
||||
const char *nick);
|
||||
void netplay_free(netplay_t *handle);
|
||||
|
||||
|
|
65
ssnes.c
65
ssnes.c
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -88,14 +88,6 @@ static void set_fast_forward_button(bool new_button_state, bool new_hold_button_
|
|||
old_hold_button_state = new_hold_button_state;
|
||||
}
|
||||
|
||||
static inline unsigned lines_to_pitch(unsigned height)
|
||||
{
|
||||
if (g_extern.system.pitch == 0) // SNES semantics
|
||||
return ((height == 448) || (height == 478)) ? 1024 : 2048;
|
||||
else
|
||||
return g_extern.system.pitch;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCREENSHOTS
|
||||
static void take_screenshot(void)
|
||||
{
|
||||
|
@ -108,10 +100,10 @@ static void take_screenshot(void)
|
|||
const uint16_t *data = g_extern.frame_cache.data;
|
||||
unsigned width = g_extern.frame_cache.width;
|
||||
unsigned height = g_extern.frame_cache.height;
|
||||
size_t pitch = g_extern.frame_cache.pitch;
|
||||
ret = screenshot_dump(g_settings.screenshot_directory,
|
||||
data,
|
||||
width, height,
|
||||
lines_to_pitch(height));
|
||||
width, height, pitch);
|
||||
}
|
||||
|
||||
const char *msg = NULL;
|
||||
|
@ -138,27 +130,6 @@ static void take_screenshot(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef SSNES_CONSOLE
|
||||
static inline void adjust_crop(const uint16_t **data, unsigned *height)
|
||||
{
|
||||
// Rather SNES specific.
|
||||
unsigned pixel_pitch = lines_to_pitch(*height) >> 1;
|
||||
if (g_settings.video.crop_overscan)
|
||||
{
|
||||
if (*height == 239)
|
||||
{
|
||||
*data += 7 * pixel_pitch; // Skip 7 top scanlines.
|
||||
*height = 224;
|
||||
}
|
||||
else if (*height == 478)
|
||||
{
|
||||
*data += 15 * pixel_pitch; // Skip 15 top scanlines.
|
||||
*height = 448;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void readjust_audio_input_rate(void)
|
||||
{
|
||||
int avail = audio_write_avail_func();
|
||||
|
@ -177,15 +148,11 @@ static void readjust_audio_input_rate(void)
|
|||
// g_extern.audio_data.src_ratio, g_extern.audio_data.orig_src_ratio);
|
||||
}
|
||||
|
||||
// libsnes: 0.065
|
||||
// Format received is 16-bit 0RRRRRGGGGGBBBBB
|
||||
static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
||||
static void video_frame(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
#ifndef SSNES_CONSOLE
|
||||
if (!g_extern.video_active)
|
||||
return;
|
||||
|
||||
adjust_crop(&data, &height);
|
||||
#endif
|
||||
|
||||
// Slightly messy code,
|
||||
|
@ -197,7 +164,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
|||
{
|
||||
struct ffemu_video_data ffemu_data = {0};
|
||||
ffemu_data.data = data;
|
||||
ffemu_data.pitch = lines_to_pitch(height);
|
||||
ffemu_data.pitch = pitch;
|
||||
ffemu_data.width = width;
|
||||
ffemu_data.height = height;
|
||||
ffemu_data.is_dupe = is_dupe;
|
||||
|
@ -217,7 +184,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
|||
unsigned oheight = height;
|
||||
g_extern.filter.psize(&owidth, &oheight);
|
||||
g_extern.filter.prender(g_extern.filter.colormap, g_extern.filter.buffer,
|
||||
g_extern.filter.pitch, data, lines_to_pitch(height), width, height);
|
||||
g_extern.filter.pitch, data, pitch, width, height);
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (g_extern.recording && g_settings.video.post_filter_record)
|
||||
|
@ -234,16 +201,17 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
|||
if (!video_frame_func(g_extern.filter.buffer, owidth, oheight, g_extern.filter.pitch, msg))
|
||||
g_extern.video_active = false;
|
||||
}
|
||||
else if (!video_frame_func(data, width, height, lines_to_pitch(height), msg))
|
||||
else if (!video_frame_func(data, width, height, pitch, msg))
|
||||
g_extern.video_active = false;
|
||||
#else
|
||||
if (!video_frame_func(data, width, height, lines_to_pitch(height), msg))
|
||||
if (!video_frame_func(data, width, height, pitch, msg))
|
||||
g_extern.video_active = false;
|
||||
#endif
|
||||
|
||||
g_extern.frame_cache.data = data;
|
||||
g_extern.frame_cache.width = width;
|
||||
g_extern.frame_cache.height = height;
|
||||
g_extern.frame_cache.pitch = pitch;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GRIFFIN
|
||||
|
@ -266,7 +234,8 @@ void ssnes_render_cached_frame(void)
|
|||
{
|
||||
video_frame(g_extern.frame_cache.data,
|
||||
g_extern.frame_cache.width,
|
||||
g_extern.frame_cache.height);
|
||||
g_extern.frame_cache.height,
|
||||
g_extern.frame_cache.pitch);
|
||||
}
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
|
@ -1018,17 +987,17 @@ static void init_controllers(void)
|
|||
if (g_extern.has_justifier)
|
||||
{
|
||||
SSNES_LOG("Connecting Justifier to port 2.\n");
|
||||
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_JUSTIFIER);
|
||||
pretro_set_controller_port_device(1, RETRO_DEVICE_LIGHTGUN_JUSTIFIER);
|
||||
}
|
||||
else if (g_extern.has_justifiers)
|
||||
{
|
||||
SSNES_LOG("Connecting Justifiers to port 2.\n");
|
||||
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_JUSTIFIERS);
|
||||
pretro_set_controller_port_device(1, RETRO_DEVICE_LIGHTGUN_JUSTIFIERS);
|
||||
}
|
||||
else if (g_extern.has_multitap)
|
||||
{
|
||||
SSNES_LOG("Connecting Multitap to port 2.\n");
|
||||
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_MULTITAP);
|
||||
pretro_set_controller_port_device(1, RETRO_DEVICE_JOYPAD_MULTITAP);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1037,17 +1006,17 @@ static void init_controllers(void)
|
|||
if (g_extern.disconnect_device[i])
|
||||
{
|
||||
SSNES_LOG("Disconnecting device from port %u.\n", i + 1);
|
||||
psnes_set_controller_port_device(i, SNES_DEVICE_NONE);
|
||||
pretro_set_controller_port_device(i, RETRO_DEVICE_NONE);
|
||||
}
|
||||
else if (g_extern.has_mouse[i])
|
||||
{
|
||||
SSNES_LOG("Connecting mouse to port %u.\n", i + 1);
|
||||
psnes_set_controller_port_device(i, SNES_DEVICE_MOUSE);
|
||||
pretro_set_controller_port_device(i, RETRO_DEVICE_MOUSE);
|
||||
}
|
||||
else if (g_extern.has_scope[i])
|
||||
{
|
||||
SSNES_LOG("Connecting scope to port %u.\n", i + 1);
|
||||
psnes_set_controller_port_device(i, SNES_DEVICE_SUPER_SCOPE);
|
||||
pretro_set_controller_port_device(i, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue