Begin fixing up SSNES for libretro.

This commit is contained in:
Themaister 2012-04-05 11:47:43 +02:00
parent 9b57081097
commit cd3c9a548c
6 changed files with 187 additions and 372 deletions

294
dynamic.c
View File

@ -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, ";"));

View File

@ -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

View File

@ -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];

View File

@ -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,

View File

@ -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
View File

@ -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);
}
}
}