Add dummy core loading.

This commit is contained in:
Themaister 2013-04-14 16:24:19 +02:00
parent 6e56c552b4
commit 1395c32937
10 changed files with 367 additions and 45 deletions

View File

@ -10,6 +10,7 @@ OBJ = frontend/frontend.o \
driver.o \
settings.o \
dynamic.o \
dynamic_dummy.o \
message.o \
rewind.o \
gfx/gfx_common.o \

View File

@ -10,6 +10,7 @@ OBJ = frontend/frontend.o \
settings.o \
hash.o \
dynamic.o \
dynamic_dummy.o \
message.o \
rewind.o \
movie.o \

View File

@ -28,6 +28,12 @@ ROM types supported depend on the libretro implementation used.
\fB--help, -h\fR
Prints help text.
.TP
\fB--menu\fR
Starts directly in in-game menu (RGUI) if enabled.
Does not require a ROM or libretro implementation to be set.
These can be loaded afterwards in the menu.
.TP
\fB--features\fR
Prints available features compiled into RetroArch, then exits.

View File

@ -31,6 +31,7 @@
#include "boolean.h"
#include "libretro.h"
#include "dynamic_dummy.h"
#ifdef NEED_DYNAMIC
#ifdef _WIN32
@ -47,11 +48,14 @@
if (p##x == NULL) { RARCH_ERR("Failed to load symbol: \"%s\"\n", #x); rarch_fail(1, "init_libretro_sym()"); } \
} while (0)
static dylib_t lib_handle = NULL;
static dylib_t lib_handle;
static bool lib_dummy;
#else
#define SYM(x) p##x = x
#endif
#define SYM_DUMMY(x) p##x = libretro_dummy_##x
void (*pretro_init)(void);
void (*pretro_deinit)(void);
@ -89,7 +93,7 @@ unsigned (*pretro_get_region)(void);
void *(*pretro_get_memory_data)(unsigned);
size_t (*pretro_get_memory_size)(unsigned);
static void set_environment(void);
static bool environment_cb(unsigned cmd, void *data);
#ifdef HAVE_DYNAMIC
#if defined(__APPLE__)
@ -256,6 +260,43 @@ static void load_symbols(void)
SYM(retro_get_memory_size);
}
static void load_symbols_dummy(void)
{
SYM_DUMMY(retro_init);
SYM_DUMMY(retro_deinit);
SYM_DUMMY(retro_api_version);
SYM_DUMMY(retro_get_system_info);
SYM_DUMMY(retro_get_system_av_info);
SYM_DUMMY(retro_set_environment);
SYM_DUMMY(retro_set_video_refresh);
SYM_DUMMY(retro_set_audio_sample);
SYM_DUMMY(retro_set_audio_sample_batch);
SYM_DUMMY(retro_set_input_poll);
SYM_DUMMY(retro_set_input_state);
SYM_DUMMY(retro_set_controller_port_device);
SYM_DUMMY(retro_reset);
SYM_DUMMY(retro_run);
SYM_DUMMY(retro_serialize_size);
SYM_DUMMY(retro_serialize);
SYM_DUMMY(retro_unserialize);
SYM_DUMMY(retro_cheat_reset);
SYM_DUMMY(retro_cheat_set);
SYM_DUMMY(retro_load_game);
SYM_DUMMY(retro_load_game_special);
SYM_DUMMY(retro_unload_game);
SYM_DUMMY(retro_get_region);
SYM_DUMMY(retro_get_memory_data);
SYM_DUMMY(retro_get_memory_size);
}
void libretro_get_current_core_pathname(char *name, size_t size)
{
if (size == 0)
@ -283,33 +324,40 @@ void libretro_get_current_core_pathname(char *name, size_t size)
}
}
void init_libretro_sym(void)
void init_libretro_sym(bool dummy)
{
lib_dummy = dummy;
// Guarantee that we can do "dirty" casting.
// Every OS that this program supports should pass this ...
rarch_assert(sizeof(void*) == sizeof(void (*)(void)));
if (lib_dummy)
load_symbols_dummy();
else
{
#ifdef HAVE_DYNAMIC
// Try to verify that -lretro was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
function_t sym = dylib_proc(NULL, "retro_init");
if (sym)
{
RARCH_ERR("Serious problem. RetroArch wants to load libretro dyamically, but it is already linked.\n");
RARCH_ERR("This could happen if other modules RetroArch depends on link against libretro directly.\n");
RARCH_ERR("Proceeding could cause a crash. Aborting ...\n");
rarch_fail(1, "init_libretro_sym()");
}
// Try to verify that -lretro was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
function_t sym = dylib_proc(NULL, "retro_init");
if (sym)
{
RARCH_ERR("Serious problem. RetroArch wants to load libretro dyamically, but it is already linked.\n");
RARCH_ERR("This could happen if other modules RetroArch depends on link against libretro directly.\n");
RARCH_ERR("Proceeding could cause a crash. Aborting ...\n");
rarch_fail(1, "init_libretro_sym()");
}
if (!*g_settings.libretro)
{
RARCH_ERR("RetroArch is built for dynamic libretro, but libretro_path is not set. Cannot continue.\n");
rarch_fail(1, "init_libretro_sym()");
}
if (!*g_settings.libretro)
{
RARCH_ERR("RetroArch is built for dynamic libretro, but libretro_path is not set. Cannot continue.\n");
rarch_fail(1, "init_libretro_sym()");
}
#endif
load_symbols();
set_environment();
load_symbols();
}
pretro_set_environment(environment_cb);
}
void uninit_libretro_sym(void)
@ -317,7 +365,9 @@ void uninit_libretro_sym(void)
#ifdef HAVE_DYNAMIC
if (lib_handle)
dylib_close(lib_handle);
lib_handle = NULL;
#endif
lib_dummy = false;
}
#ifdef NEED_DYNAMIC
@ -591,8 +641,3 @@ static bool environment_cb(unsigned cmd, void *data)
return true;
}
static void set_environment(void)
{
pretro_set_environment(environment_cb);
}

View File

@ -33,7 +33,7 @@
extern "C" {
#endif
void init_libretro_sym(void);
void init_libretro_sym(bool dummy);
void uninit_libretro_sym(void);
typedef void *dylib_t;

185
dynamic_dummy.c Normal file
View File

@ -0,0 +1,185 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
* Copyright (C) 2011-2013 - Daniel De Matteis
* Copyright (C) 2012-2013 - Michael Lelli
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "libretro.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static uint16_t *frame_buf;
void libretro_dummy_retro_init(void)
{
frame_buf = (uint16_t*)calloc(320 * 240, sizeof(uint16_t));
}
void libretro_dummy_retro_deinit(void)
{
free(frame_buf);
frame_buf = NULL;
}
unsigned libretro_dummy_retro_api_version(void)
{
return RETRO_API_VERSION;
}
void libretro_dummy_retro_set_controller_port_device(unsigned port, unsigned device)
{
(void)port;
(void)device;
}
void libretro_dummy_retro_get_system_info(struct retro_system_info *info)
{
memset(info, 0, sizeof(*info));
info->library_name = "N/A";
info->library_version = "";
info->need_fullpath = false;
info->valid_extensions = ""; // Nothing.
}
// Doesn't really matter, but need something sane.
void libretro_dummy_retro_get_system_av_info(struct retro_system_av_info *info)
{
info->timing.fps = 60.0;
info->timing.sample_rate = 30000.0;
info->geometry.base_width = 320;
info->geometry.base_height = 240;
info->geometry.max_width = 320;
info->geometry.max_height = 240;
info->geometry.aspect_ratio = 4.0 / 3.0;
}
static retro_video_refresh_t video_cb;
static retro_audio_sample_t audio_cb;
static retro_audio_sample_batch_t audio_batch_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
void libretro_dummy_retro_set_environment(retro_environment_t cb)
{
environ_cb = cb;
// We know it's supported, it's internal to RetroArch.
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt);
}
void libretro_dummy_retro_set_audio_sample(retro_audio_sample_t cb)
{
audio_cb = cb;
}
void libretro_dummy_retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
audio_batch_cb = cb;
}
void libretro_dummy_retro_set_input_poll(retro_input_poll_t cb)
{
input_poll_cb = cb;
}
void libretro_dummy_retro_set_input_state(retro_input_state_t cb)
{
input_state_cb = cb;
}
void libretro_dummy_retro_set_video_refresh(retro_video_refresh_t cb)
{
video_cb = cb;
}
void libretro_dummy_retro_reset(void)
{}
void libretro_dummy_retro_run(void)
{
input_poll_cb();
for (unsigned i = 0; i < 320 * 240; i++)
frame_buf[i] = 4 << 5;
video_cb(frame_buf, 320, 240, 640);
}
// This should never be called, it's only used as a placeholder.
bool libretro_dummy_retro_load_game(const struct retro_game_info *info)
{
(void)info;
return false;
}
void libretro_dummy_retro_unload_game(void)
{}
unsigned libretro_dummy_retro_get_region(void)
{
return RETRO_REGION_NTSC;
}
bool libretro_dummy_retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
{
(void)type;
(void)info;
(void)num;
return false;
}
size_t libretro_dummy_retro_serialize_size(void)
{
return 0;
}
bool libretro_dummy_retro_serialize(void *data, size_t size)
{
(void)data;
(void)size;
return false;
}
bool libretro_dummy_retro_unserialize(const void *data, size_t size)
{
(void)data;
(void)size;
return false;
}
void *libretro_dummy_retro_get_memory_data(unsigned id)
{
(void)id;
return NULL;
}
size_t libretro_dummy_retro_get_memory_size(unsigned id)
{
(void)id;
return 0;
}
void libretro_dummy_retro_cheat_reset(void)
{}
void libretro_dummy_retro_cheat_set(unsigned index, bool enabled, const char *code)
{
(void)index;
(void)enabled;
(void)code;
}

59
dynamic_dummy.h Normal file
View File

@ -0,0 +1,59 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
* Copyright (C) 2011-2013 - Daniel De Matteis
* Copyright (C) 2012-2013 - Michael Lelli
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DYNAMIC_DUMMY_H__
#define DYNAMIC_DUMMY_H__
#include "boolean.h"
#include "libretro.h"
void libretro_dummy_retro_init(void);
void libretro_dummy_retro_deinit(void);
unsigned libretro_dummy_retro_api_version(void);
void libretro_dummy_retro_get_system_info(struct retro_system_info *info);
void libretro_dummy_retro_get_system_av_info(struct retro_system_av_info *info);
void libretro_dummy_retro_set_environment(retro_environment_t cb);
void libretro_dummy_retro_set_video_refresh(retro_video_refresh_t cb);
void libretro_dummy_retro_set_audio_sample(retro_audio_sample_t cb);
void libretro_dummy_retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);
void libretro_dummy_retro_set_input_poll(retro_input_poll_t cb);
void libretro_dummy_retro_set_input_state(retro_input_state_t cb);
void libretro_dummy_retro_set_controller_port_device(unsigned port, unsigned device);
void libretro_dummy_retro_reset(void);
void libretro_dummy_retro_run(void);
size_t libretro_dummy_retro_serialize_size(void);
bool libretro_dummy_retro_serialize(void *data, size_t size);
bool libretro_dummy_retro_unserialize(const void *data, size_t size);
void libretro_dummy_retro_cheat_reset(void);
void libretro_dummy_retro_cheat_set(unsigned index, bool enabled, const char *code);
bool libretro_dummy_retro_load_game(const struct retro_game_info *game);
bool libretro_dummy_retro_load_game_special(unsigned game_type,
const struct retro_game_info *info, size_t num_info);
void libretro_dummy_retro_unload_game(void);
unsigned libretro_dummy_retro_get_region(void);
void *libretro_dummy_retro_get_memory_data(unsigned id);
size_t libretro_dummy_retro_get_memory_size(unsigned id);
#endif

View File

@ -601,6 +601,8 @@ struct global
char error_string[1024];
jmp_buf error_sjlj_context;
unsigned menu_toggle_behavior;
bool libretro_dummy;
};
struct rarch_main_wrap

View File

@ -354,6 +354,7 @@ SCALERS
DYNAMIC
============================================================ */
#include "../dynamic.c"
#include "../dynamic_dummy.c"
/*============================================================
FILE

View File

@ -643,6 +643,7 @@ static void print_help(void)
puts("===================================================================");
puts("Usage: retroarch [rom file] [options...]");
puts("\t-h/--help: Show this help message.");
puts("\t--menu: Do not require ROM or libretro core to be loaded, starts directly in menu.");
puts("\t--features: Prints available features compiled into RetroArch.");
puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin.");
puts("\t-f/--fullscreen: Start RetroArch in fullscreen regardless of config settings.");
@ -796,6 +797,8 @@ static void parse_input(int argc, char *argv[])
rarch_fail(1, "parse_input()");
}
g_extern.libretro_dummy = false;
// Make sure we can call parse_input several times ...
optind = 1;
@ -805,6 +808,7 @@ static void parse_input(int argc, char *argv[])
#ifdef HAVE_DYNAMIC
{ "libretro", 1, NULL, 'L' },
#endif
{ "menu", 0, &val, 'M' },
{ "help", 0, NULL, 'h' },
{ "save", 1, NULL, 's' },
{ "fullscreen", 0, NULL, 'f' },
@ -1072,6 +1076,10 @@ static void parse_input(int argc, char *argv[])
case 0:
switch (val)
{
case 'M':
g_extern.libretro_dummy = true;
break;
#ifdef HAVE_NETPLAY
case 'p':
g_extern.netplay_port = strtoul(optarg, NULL, 0);
@ -1160,7 +1168,15 @@ static void parse_input(int argc, char *argv[])
}
}
if (optind < argc)
if (g_extern.libretro_dummy)
{
if (optind < argc)
{
RARCH_ERR("--menu was used, but ROM file was passed as well.\n");
rarch_fail(1, "parse_input()");
}
}
else if (optind < argc)
set_paths(argv[optind]);
else
verify_stdin_paths();
@ -2785,7 +2801,7 @@ int rarch_main_init(int argc, char *argv[])
validate_cpu_features();
config_load();
init_libretro_sym();
init_libretro_sym(g_extern.libretro_dummy);
rarch_init_system_info();
init_drivers_pre();
@ -2793,33 +2809,36 @@ int rarch_main_init(int argc, char *argv[])
verify_api_version();
pretro_init();
g_extern.use_sram = true;
g_extern.use_sram = !g_extern.libretro_dummy;
bool allow_cheats = true;
fill_pathnames();
if (!g_extern.libretro_dummy)
{
fill_pathnames();
if (!init_rom_file(g_extern.game_type))
goto error;
if (!init_rom_file(g_extern.game_type))
goto error;
set_savestate_auto_index();
set_savestate_auto_index();
init_system_av_info();
if (!g_extern.sram_load_disable)
load_save_files();
else
RARCH_LOG("Skipping SRAM load.\n");
if (!g_extern.sram_load_disable)
load_save_files();
else
RARCH_LOG("Skipping SRAM load.\n");
load_auto_state();
load_auto_state();
#ifdef HAVE_BSV_MOVIE
init_movie();
init_movie();
#endif
#ifdef HAVE_NETPLAY
init_netplay();
init_netplay();
#endif
}
init_system_av_info();
init_drivers();
#ifdef HAVE_COMMAND
@ -2839,9 +2858,9 @@ int rarch_main_init(int argc, char *argv[])
#endif
#ifdef HAVE_NETPLAY
g_extern.use_sram = !g_extern.sram_save_disable && !g_extern.netplay_is_client;
g_extern.use_sram = g_extern.use_sram && !g_extern.sram_save_disable && !g_extern.netplay_is_client;
#else
g_extern.use_sram = !g_extern.sram_save_disable;
g_extern.use_sram = g_extern.use_sram && !g_extern.sram_save_disable;
#endif
if (!g_extern.use_sram)
@ -2878,7 +2897,9 @@ error:
static inline bool check_enter_rgui(void)
{
static bool old_rmenu_toggle = true;
bool rmenu_toggle = input_key_pressed_func(RARCH_MENU_TOGGLE);
// Always go into menu if dummy core is loaded.
bool rmenu_toggle = input_key_pressed_func(RARCH_MENU_TOGGLE) || (g_extern.libretro_dummy && !old_rmenu_toggle);
if (rmenu_toggle && !old_rmenu_toggle)
{
if (g_extern.menu_toggle_behavior == 0)
@ -3005,7 +3026,8 @@ void rarch_main_deinit(void)
deinit_movie();
#endif
save_auto_state();
if (!g_extern.libretro_dummy)
save_auto_state();
pretro_unload_game();
pretro_deinit();