static void init_video_input(const input_driver_t *tmp) { driver_t *driver = driver_get_ptr(); /* Video driver didn't provide an input driver, * so we use configured one. */ RARCH_LOG("Graphics driver did not initialize an input driver. Attempting to pick a suitable driver.\n"); if (tmp) driver->input = tmp; else find_input_driver(); if (!driver->input) { /* This should never really happen as tmp (driver.input) is always * found before this in find_driver_input(), or we have aborted * in a similar fashion anyways. */ rarch_fail(1, "init_video_input()"); } driver->input_data = input_driver_init(); if (driver->input_data) return; RARCH_ERR("Cannot initialize input driver. Exiting ...\n"); rarch_fail(1, "init_video_input()"); }
void init_menu(void) { const char *video_driver; driver_t *driver = driver_get_ptr(); if (driver->menu) return; find_menu_driver(); video_driver = menu_video_get_ident(); switch (driver->menu_ctx->type) { case MENU_VIDEO_DRIVER_GENERIC: break; case MENU_VIDEO_DRIVER_DIRECT3D: if (video_driver && (strcmp(video_driver, "d3d") != 0)) init_menu_fallback(); break; case MENU_VIDEO_DRIVER_OPENGL: if (video_driver && (strcmp(video_driver, "gl") != 0)) init_menu_fallback(); break; } if (!(driver->menu = (menu_handle_t*)menu_init(driver->menu_ctx))) rarch_fail(1, "init_menu()"); if (driver->menu_ctx->lists_init) if (!driver->menu_ctx->lists_init(driver->menu)) rarch_fail(1, "init_menu()"); }
void init_libretro_sym(bool 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 (!dummy) { #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()"); } 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(dummy); pretro_set_environment(environment_cb); }
static void find_video_driver(void) { #if defined(HAVE_OPENGL) && defined(HAVE_FBO) if (g_extern.system.hw_render_callback.context_type) { RARCH_LOG("Using HW render, OpenGL driver forced.\n"); driver.video = &video_gl; return; } #endif int i = find_video_driver_index(g_settings.video.driver); if (i >= 0) driver.video = video_drivers[i]; else { unsigned d; RARCH_ERR("Couldn't find any video driver named \"%s\"\n", g_settings.video.driver); RARCH_LOG_OUTPUT("Available video drivers are:\n"); for (d = 0; video_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", video_drivers[d]->ident); RARCH_WARN("Going to default to first video driver...\n"); driver.video = video_drivers[0]; if (!driver.video) rarch_fail(1, "find_video_driver()"); } }
void find_audio_driver(void) { driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); int i = find_driver_index("audio_driver", settings->audio.driver); if (i >= 0) driver->audio = (const audio_driver_t*)audio_driver_find_handle(i); else { unsigned d; RARCH_ERR("Couldn't find any audio driver named \"%s\"\n", settings->audio.driver); RARCH_LOG_OUTPUT("Available audio drivers are:\n"); for (d = 0; audio_driver_find_handle(d); d++) RARCH_LOG_OUTPUT("\t%s\n", audio_driver_find_ident(d)); RARCH_WARN("Going to default to first audio driver...\n"); driver->audio = (const audio_driver_t*)audio_driver_find_handle(0); if (!driver->audio) rarch_fail(1, "find_audio_driver()"); } }
void init_menu(void) { driver_t *driver = driver_get_ptr(); if (driver->menu) return; find_menu_driver(); if (!(driver->menu = (menu_handle_t*)menu_init(driver->menu_ctx))) { RARCH_ERR("Cannot initialize menu.\n"); rarch_fail(1, "init_menu()"); } if (!(menu_entries_init(driver->menu))) { RARCH_ERR("Cannot initialize menu lists.\n"); rarch_fail(1, "init_menu()"); } }
static void init_menu(void) { if (driver.menu) return; find_menu_driver(); if (!(driver.menu = (menu_handle_t*)menu_init(driver.menu_ctx))) { RARCH_ERR("Cannot initialize menu.\n"); rarch_fail(1, "init_menu()"); } }
static void find_location_driver(void) { int i = find_location_driver_index(g_settings.location.driver); if (i >= 0) driver.location = location_drivers[i]; else { unsigned d; RARCH_ERR("Couldn't find any location driver named \"%s\"\n", g_settings.location.driver); RARCH_LOG_OUTPUT("Available location drivers are:\n"); for (d = 0; location_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", location_drivers[d]->ident); rarch_fail(1, "find_location_driver()"); } }
static void find_input_driver(void) { int i = find_input_driver_index(g_settings.input.driver); if (i >= 0) driver.input = input_drivers[i]; else { unsigned d; RARCH_ERR("Couldn't find any input driver named \"%s\"\n", g_settings.input.driver); RARCH_LOG_OUTPUT("Available input drivers are:\n"); for (d = 0; input_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", input_drivers[d]->ident); rarch_fail(1, "find_input_driver()"); } }
static void load_symbols(void) { #ifdef HAVE_DYNAMIC RARCH_LOG("Loading dynamic libretro from: \"%s\"\n", g_settings.libretro); lib_handle = dylib_load(g_settings.libretro); if (!lib_handle) { RARCH_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libretro); rarch_fail(1, "load_dynamic()"); } #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); }
static void event_init_movie(void) { settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (global->bsv.movie_start_playback) { if (!(global->bsv.movie = bsv_movie_init(global->bsv.movie_start_path, RARCH_MOVIE_PLAYBACK))) { RARCH_ERR("%s: \"%s\".\n", msg_hash_to_str(MSG_FAILED_TO_LOAD_MOVIE_FILE), global->bsv.movie_start_path); rarch_fail(1, "event_init_movie()"); } global->bsv.movie_playback = true; rarch_main_msg_queue_push_new(MSG_STARTING_MOVIE_PLAYBACK, 2, 180, false); RARCH_LOG("%s.\n", msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK)); settings->rewind_granularity = 1; } else if (global->bsv.movie_start_recording) { char msg[PATH_MAX_LENGTH] = {0}; snprintf(msg, sizeof(msg), "%s \"%s\".", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), global->bsv.movie_start_path); if (!(global->bsv.movie = bsv_movie_init(global->bsv.movie_start_path, RARCH_MOVIE_RECORD))) { rarch_main_msg_queue_push_new(MSG_FAILED_TO_START_MOVIE_RECORD, 1, 180, true); RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); return; } rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), global->bsv.movie_start_path); settings->rewind_granularity = 1; } }
void find_video_driver(void) { int i; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); #if defined(HAVE_OPENGL) && defined(HAVE_FBO) if (video_state.hw_render_callback.context_type) { RARCH_LOG("Using HW render, OpenGL driver forced.\n"); driver->video = &video_gl; return; } #endif if (driver->frontend_ctx && driver->frontend_ctx->get_video_driver) { driver->video = driver->frontend_ctx->get_video_driver(); if (driver->video) return; RARCH_WARN("Frontend supports get_video_driver() but did not specify one.\n"); } i = find_driver_index("video_driver", settings->video.driver); if (i >= 0) driver->video = (const video_driver_t*)video_driver_find_handle(i); else { unsigned d; RARCH_ERR("Couldn't find any video driver named \"%s\"\n", settings->video.driver); RARCH_LOG_OUTPUT("Available video drivers are:\n"); for (d = 0; video_driver_find_handle(d); d++) RARCH_LOG_OUTPUT("\t%s\n", video_driver_find_ident(d)); RARCH_WARN("Going to default to first video driver...\n"); driver->video = (const video_driver_t*)video_driver_find_handle(0); if (!driver->video) rarch_fail(1, "find_video_driver()"); } }
void find_menu_driver(void) { int i = find_menu_driver_index(g_settings.menu.driver); if (i >= 0) driver.menu_ctx = menu_ctx_drivers[i]; else { unsigned d; RARCH_WARN("Couldn't find any menu driver named \"%s\"\n", g_settings.menu.driver); RARCH_LOG_OUTPUT("Available menu drivers are:\n"); for (d = 0; menu_ctx_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", menu_ctx_drivers[d]->ident); RARCH_WARN("Going to default to first menu driver...\n"); driver.menu_ctx = menu_ctx_drivers[0]; if (!driver.menu_ctx) rarch_fail(1, "find_menu_driver()"); } }
static void find_audio_driver(void) { int i = find_audio_driver_index(g_settings.audio.driver); if (i >= 0) driver.audio = audio_drivers[i]; else { unsigned d; RARCH_ERR("Couldn't find any audio driver named \"%s\"\n", g_settings.audio.driver); RARCH_LOG_OUTPUT("Available audio drivers are:\n"); for (d = 0; audio_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", audio_drivers[d]->ident); RARCH_WARN("Going to default to first audio driver...\n"); driver.audio = audio_drivers[0]; if (!driver.audio) rarch_fail(1, "find_audio_driver()"); } }
void find_image_driver(void) { int i; if (driver.image) return; i = find_image_driver_index(g_settings.image.driver); if (i >= 0) driver.image = image_ctx_drivers[i]; else { unsigned d; RARCH_ERR("Couldn't find any image driver named \"%s\"\n", g_settings.image.driver); RARCH_LOG_OUTPUT("Available image drivers are:\n"); for (d = 0; image_ctx_drivers[d]; d++) RARCH_LOG_OUTPUT("\t%s\n", image_ctx_drivers[d]->ident); rarch_fail(1, "find_image_driver()"); } }
static void event_init_movie(void) { settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (global->bsv.movie_start_playback) { if (!(global->bsv.movie = bsv_movie_init(global->bsv.movie_start_path, RARCH_MOVIE_PLAYBACK))) { RARCH_ERR("Failed to load movie file: \"%s\".\n", global->bsv.movie_start_path); rarch_fail(1, "event_init_movie()"); } global->bsv.movie_playback = true; rarch_main_msg_queue_push("Starting movie playback.", 2, 180, false); RARCH_LOG("Starting movie playback.\n"); settings->rewind_granularity = 1; } else if (global->bsv.movie_start_recording) { char msg[PATH_MAX_LENGTH] = {0}; snprintf(msg, sizeof(msg), "Starting movie record to \"%s\".", global->bsv.movie_start_path); if (!(global->bsv.movie = bsv_movie_init(global->bsv.movie_start_path, RARCH_MOVIE_RECORD))) { rarch_main_msg_queue_push("Failed to start movie record.", 1, 180, true); RARCH_ERR("Failed to start movie record.\n"); return; } rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("Starting movie record to \"%s\".\n", global->bsv.movie_start_path); settings->rewind_granularity = 1; } }
static void parse_config_file(void) { bool ret; if (*g_extern.config_path) { RARCH_LOG("Loading config from: %s.\n", g_extern.config_path); ret = config_load_file(g_extern.config_path); } else { RARCH_LOG("Loading default config.\n"); ret = config_load_file(NULL); } if (!ret) { RARCH_ERR("Couldn't find config at path: \"%s\"\n", g_extern.config_path); #ifndef RARCH_CONSOLE rarch_fail(1, "parse_config_file()"); #endif } }
void find_menu_driver(void) { driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); int i = find_driver_index("menu_driver", settings->menu.driver); if (i >= 0) driver->menu_ctx = (const menu_ctx_driver_t*)menu_driver_find_handle(i); else { unsigned d; RARCH_WARN("Couldn't find any menu driver named \"%s\"\n", settings->menu.driver); RARCH_LOG_OUTPUT("Available menu drivers are:\n"); for (d = 0; menu_driver_find_handle(d); d++) RARCH_LOG_OUTPUT("\t%s\n", menu_driver_find_ident(d)); RARCH_WARN("Going to default to first menu driver...\n"); driver->menu_ctx = (const menu_ctx_driver_t*)menu_driver_find_handle(0); if (!driver->menu_ctx) rarch_fail(1, "find_menu_driver()"); } }
void init_video(void) { unsigned max_dim, scale, width, height; video_viewport_t *custom_vp = NULL; const input_driver_t *tmp = NULL; const struct retro_game_geometry *geom = NULL; video_info_t video = {0}; static uint16_t dummy_pixels[32] = {0}; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); init_video_filter(video_state.pix_fmt); event_command(EVENT_CMD_SHADER_DIR_INIT); if (av_info) geom = (const struct retro_game_geometry*)&av_info->geometry; max_dim = max(geom->max_width, geom->max_height); scale = next_pow2(max_dim) / RARCH_SCALE_BASE; scale = max(scale, 1); if (video_state.filter.filter) scale = video_state.filter.scale; /* Update core-dependent aspect ratio values. */ video_viewport_set_square_pixel(geom->base_width, geom->base_height); video_viewport_set_core(); video_viewport_set_config(); /* Update CUSTOM viewport. */ custom_vp = video_viewport_get_custom(); if (settings->video.aspect_ratio_idx == ASPECT_RATIO_CUSTOM) { float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (custom_vp->width && custom_vp->height) ? (float)custom_vp->width / custom_vp->height : default_aspect; } video_driver_set_aspect_ratio_value( aspectratio_lut[settings->video.aspect_ratio_idx].value); if (settings->video.fullscreen) { width = settings->video.fullscreen_x; height = settings->video.fullscreen_y; } else { if (settings->video.force_aspect) { /* Do rounding here to simplify integer scale correctness. */ unsigned base_width = roundf(geom->base_height * video_driver_get_aspect_ratio()); width = roundf(base_width * settings->video.scale); } else width = roundf(geom->base_width * settings->video.scale); height = roundf(geom->base_height * settings->video.scale); } if (width && height) RARCH_LOG("Video @ %ux%u\n", width, height); else RARCH_LOG("Video @ fullscreen\n"); driver->display_type = RARCH_DISPLAY_NONE; driver->video_display = 0; driver->video_window = 0; if (!init_video_pixel_converter(RARCH_SCALE_BASE * scale)) { RARCH_ERR("Failed to initialize pixel converter.\n"); rarch_fail(1, "init_video()"); } video.width = width; video.height = height; video.fullscreen = settings->video.fullscreen; video.vsync = settings->video.vsync && !global->system.force_nonblock; video.force_aspect = settings->video.force_aspect; #ifdef GEKKO video.viwidth = settings->video.viwidth; video.vfilter = settings->video.vfilter; #endif video.smooth = settings->video.smooth; video.input_scale = scale; video.rgb32 = video_state.filter.filter ? video_state.filter.out_rgb32 : (video_state.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); tmp = (const input_driver_t*)driver->input; /* Need to grab the "real" video driver interface on a reinit. */ find_video_driver(); #ifdef HAVE_THREADS if (settings->video.threaded && !video_state.hw_render_callback.context_type) { /* Can't do hardware rendering with threaded driver currently. */ RARCH_LOG("Starting threaded video driver ...\n"); if (!rarch_threaded_video_init(&driver->video, &driver->video_data, &driver->input, &driver->input_data, driver->video, &video)) { RARCH_ERR("Cannot open threaded video driver ... Exiting ...\n"); rarch_fail(1, "init_video()"); } } else #endif driver->video_data = driver->video->init(&video, &driver->input, &driver->input_data); if (!driver->video_data) { RARCH_ERR("Cannot open video driver ... Exiting ...\n"); rarch_fail(1, "init_video()"); } driver->video_poke = NULL; if (driver->video->poke_interface) driver->video->poke_interface(driver->video_data, &driver->video_poke); if (driver->video->viewport_info && (!custom_vp->width || !custom_vp->height)) { /* Force custom viewport to have sane parameters. */ custom_vp->width = width; custom_vp->height = height; video_driver_viewport_info(custom_vp); } video_driver_set_rotation( (settings->video.rotation + global->system.rotation) % 4); video_driver_suppress_screensaver(settings->ui.suspend_screensaver_enable); if (!driver->input) init_video_input(tmp); event_command(EVENT_CMD_OVERLAY_DEINIT); event_command(EVENT_CMD_OVERLAY_INIT); video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); #if defined(PSP) video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); #endif }
/** * parse_input: * @argc : Count of (commandline) arguments. * @argv : (Commandline) arguments. * * Parses (commandline) arguments passed to RetroArch. * **/ static void parse_input(int argc, char *argv[]) { runloop_t *runloop = rarch_main_get_ptr(); global_t *global = global_get_ptr(); global->libretro_no_content = false; global->libretro_dummy = false; global->has_set_save_path = false; global->has_set_state_path = false; global->has_set_libretro = false; global->has_set_libretro_directory = false; global->has_set_verbosity = false; global->has_set_netplay_mode = false; global->has_set_username = false; global->has_set_netplay_ip_address = false; global->has_set_netplay_delay_frames = false; global->has_set_netplay_ip_port = false; global->has_set_ups_pref = false; global->has_set_bps_pref = false; global->has_set_ips_pref = false; global->ups_pref = false; global->bps_pref = false; global->ips_pref = false; *global->ups_name = '\0'; *global->bps_name = '\0'; *global->ips_name = '\0'; *global->subsystem = '\0'; global->overrides_active = false; if (argc < 2) { global->libretro_dummy = true; return; } /* Make sure we can call parse_input several times ... */ optind = 0; int val = 0; const struct option opts[] = { #ifdef HAVE_DYNAMIC { "libretro", 1, NULL, 'L' }, #endif { "menu", 0, &val, 'M' }, { "help", 0, NULL, 'h' }, { "save", 1, NULL, 's' }, { "fullscreen", 0, NULL, 'f' }, { "record", 1, NULL, 'r' }, { "recordconfig", 1, &val, 'R' }, { "size", 1, &val, 's' }, { "verbose", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "appendconfig", 1, &val, 'C' }, { "nodevice", 1, NULL, 'N' }, { "dualanalog", 1, NULL, 'A' }, { "device", 1, NULL, 'd' }, { "savestate", 1, NULL, 'S' }, { "bsvplay", 1, NULL, 'P' }, { "bsvrecord", 1, NULL, 'R' }, { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETPLAY { "host", 0, NULL, 'H' }, { "connect", 1, NULL, 'C' }, { "frames", 1, NULL, 'F' }, { "port", 1, &val, 'p' }, { "spectate", 0, &val, 'S' }, #endif { "nick", 1, &val, 'N' }, #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) { "command", 1, &val, 'c' }, #endif { "ups", 1, NULL, 'U' }, { "bps", 1, &val, 'B' }, { "ips", 1, &val, 'I' }, { "no-patch", 0, &val, 'n' }, { "detach", 0, NULL, 'D' }, { "features", 0, &val, 'f' }, { "subsystem", 1, NULL, 'Z' }, { "max-frames", 1, NULL, 'm' }, { "eof-exit", 0, &val, 'e' }, { NULL, 0, NULL, 0 } }; #define FFMPEG_RECORD_ARG "r:" #ifdef HAVE_DYNAMIC #define DYNAMIC_ARG "L:" #else #define DYNAMIC_ARG #endif #ifdef HAVE_NETPLAY #define NETPLAY_ARG "HC:F:" #else #define NETPLAY_ARG #endif #define BSV_MOVIE_ARG "P:R:M:" const char *optstring = "hs:fvS:A:c:U:DN:d:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG; settings_t *settings = config_get_ptr(); for (;;) { int port; val = 0; int c = getopt_long(argc, argv, optstring, opts, NULL); if (c == -1) break; switch (c) { case 'h': print_help(); exit(0); case 'Z': strlcpy(global->subsystem, optarg, sizeof(global->subsystem)); break; case 'd': { unsigned id = 0; struct string_list *list = string_split(optarg, ":"); port = 0; if (list && list->size == 2) { port = strtol(list->elems[0].data, NULL, 0); id = strtoul(list->elems[1].data, NULL, 0); } string_list_free(list); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect device to a valid port.\n"); print_help(); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = id; global->has_set_libretro_device[port - 1] = true; break; } case 'A': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect dualanalog to a valid port.\n"); print_help(); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_ANALOG; global->has_set_libretro_device[port - 1] = true; break; case 's': strlcpy(global->savefile_name, optarg, sizeof(global->savefile_name)); global->has_set_save_path = true; break; case 'f': global->force_fullscreen = true; break; case 'S': strlcpy(global->savestate_name, optarg, sizeof(global->savestate_name)); global->has_set_state_path = true; break; case 'v': global->verbosity = true; global->has_set_verbosity = true; break; case 'N': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Disconnect device from a valid port.\n"); print_help(); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_NONE; global->has_set_libretro_device[port - 1] = true; break; case 'c': strlcpy(global->config_path, optarg, sizeof(global->config_path)); break; case 'r': strlcpy(global->record.path, optarg, sizeof(global->record.path)); global->record.enable = true; break; #ifdef HAVE_DYNAMIC case 'L': if (path_is_directory(optarg)) { *settings->libretro = '\0'; strlcpy(settings->libretro_directory, optarg, sizeof(settings->libretro_directory)); global->has_set_libretro = true; global->has_set_libretro_directory = true; RARCH_WARN("Using old --libretro behavior. Setting libretro_directory to \"%s\" instead.\n", optarg); } else { strlcpy(settings->libretro, optarg, sizeof(settings->libretro)); global->has_set_libretro = true; } break; #endif case 'P': case 'R': strlcpy(global->bsv.movie_start_path, optarg, sizeof(global->bsv.movie_start_path)); global->bsv.movie_start_playback = (c == 'P'); global->bsv.movie_start_recording = (c == 'R'); break; case 'M': if (strcmp(optarg, "noload-nosave") == 0) { global->sram_load_disable = true; global->sram_save_disable = true; } else if (strcmp(optarg, "noload-save") == 0) global->sram_load_disable = true; else if (strcmp(optarg, "load-nosave") == 0) global->sram_save_disable = true; else if (strcmp(optarg, "load-save") != 0) { RARCH_ERR("Invalid argument in --sram-mode.\n"); print_help(); rarch_fail(1, "parse_input()"); } break; #ifdef HAVE_NETPLAY case 'H': global->has_set_netplay_ip_address = true; global->netplay_enable = true; *global->netplay_server = '\0'; break; case 'C': global->has_set_netplay_ip_address = true; global->netplay_enable = true; strlcpy(global->netplay_server, optarg, sizeof(global->netplay_server)); break; case 'F': global->netplay_sync_frames = strtol(optarg, NULL, 0); global->has_set_netplay_delay_frames = true; break; #endif case 'U': strlcpy(global->ups_name, optarg, sizeof(global->ups_name)); global->ups_pref = true; global->has_set_ups_pref = true; break; case 'D': #if defined(_WIN32) && !defined(_XBOX) FreeConsole(); #endif break; case 'm': runloop->frames.video.max = strtoul(optarg, NULL, 10); break; case 0: switch (val) { case 'M': global->libretro_dummy = true; break; #ifdef HAVE_NETPLAY case 'p': global->has_set_netplay_ip_port = true; global->netplay_port = strtoul(optarg, NULL, 0); break; case 'S': global->has_set_netplay_mode = true; global->netplay_is_spectate = true; break; #endif case 'N': global->has_set_username = true; strlcpy(settings->username, optarg, sizeof(settings->username)); break; #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) case 'c': if (network_cmd_send(optarg)) exit(0); else rarch_fail(1, "network_cmd_send()"); break; #endif case 'C': strlcpy(global->append_config_path, optarg, sizeof(global->append_config_path)); break; case 'B': strlcpy(global->bps_name, optarg, sizeof(global->bps_name)); global->bps_pref = true; global->has_set_bps_pref = true; break; case 'I': strlcpy(global->ips_name, optarg, sizeof(global->ips_name)); global->ips_pref = true; global->has_set_ips_pref = true; break; case 'n': global->block_patch = true; break; case 's': { if (sscanf(optarg, "%ux%u", &global->record.width, &global->record.height) != 2) { RARCH_ERR("Wrong format for --size.\n"); print_help(); rarch_fail(1, "parse_input()"); } break; } case 'R': strlcpy(global->record.config, optarg, sizeof(global->record.config)); break; case 'f': print_features(); exit(0); case 'e': global->bsv.eof_exit = true; break; default: break; } break; case '?': print_help(); rarch_fail(1, "parse_input()"); default: RARCH_ERR("Error parsing arguments.\n"); rarch_fail(1, "parse_input()"); } } if (global->libretro_dummy) { if (optind < argc) { RARCH_ERR("--menu was used, but content file was passed as well.\n"); rarch_fail(1, "parse_input()"); } } else if (!*global->subsystem && optind < argc) rarch_set_paths(argv[optind]); else if (*global->subsystem && optind < argc) set_special_paths(argv + optind, argc - optind); else global->libretro_no_content = true; /* Copy SRM/state dirs used, so they can be reused on reentrancy. */ if (global->has_set_save_path && path_is_directory(global->savefile_name)) strlcpy(global->savefile_dir, global->savefile_name, sizeof(global->savefile_dir)); if (global->has_set_state_path && path_is_directory(global->savestate_name)) strlcpy(global->savestate_dir, global->savestate_name, sizeof(global->savestate_dir)); }
static void load_symbols(void) { #ifdef HAVE_DYNAMIC const char *libretro_path = g_settings.libretro; char libretro_core_buffer[PATH_MAX]; if (path_is_directory(g_settings.libretro)) { if (!find_first_libretro(libretro_core_buffer, sizeof(libretro_core_buffer), g_settings.libretro, g_extern.fullpath)) { RARCH_ERR("libretro_path is a directory, but no valid libretro implementation was found.\n"); rarch_fail(1, "load_dynamic()"); } libretro_path = libretro_core_buffer; } RARCH_LOG("Loading dynamic libretro from: \"%s\"\n", libretro_path); lib_handle = dylib_load(libretro_path); if (!lib_handle) { RARCH_ERR("Failed to open dynamic library: \"%s\"\n", libretro_path); rarch_fail(1, "load_dynamic()"); } #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 menu_init(void) { rgui = rgui_init(); if (rgui == NULL) { RARCH_ERR("Could not initialize menu.\n"); rarch_fail(1, "menu_init()"); } rgui->trigger_state = 0; rgui->old_input_state = 0; rgui->do_held = false; rgui->frame_buf_show = true; rgui->current_pad = 0; #ifdef HAVE_DYNAMIC if (path_is_directory(g_settings.libretro)) strlcpy(rgui->libretro_dir, g_settings.libretro, sizeof(rgui->libretro_dir)); else if (*g_settings.libretro) { fill_pathname_basedir(rgui->libretro_dir, g_settings.libretro, sizeof(rgui->libretro_dir)); libretro_get_system_info(g_settings.libretro, &rgui->info, NULL); } #else retro_get_system_info(&rgui->info); #endif #ifdef HAVE_FILEBROWSER if (!(strlen(g_settings.rgui_browser_directory) > 0)) strlcpy(g_settings.rgui_browser_directory, default_paths.filebrowser_startup_dir, sizeof(g_settings.rgui_browser_directory)); rgui->browser = (filebrowser_t*)calloc(1, sizeof(*(rgui->browser))); if (rgui->browser == NULL) { RARCH_ERR("Could not initialize filebrowser.\n"); rarch_fail(1, "menu_init()"); } strlcpy(rgui->browser->current_dir.extensions, rgui->info.valid_extensions, sizeof(rgui->browser->current_dir.extensions)); // Look for zips to extract as well. if (*rgui->info.valid_extensions) { strlcat(rgui->browser->current_dir.extensions, "|zip", sizeof(rgui->browser->current_dir.extensions)); } strlcpy(rgui->browser->current_dir.root_dir, g_settings.rgui_browser_directory, sizeof(rgui->browser->current_dir.root_dir)); filebrowser_iterate(rgui->browser, FILEBROWSER_ACTION_RESET); #endif #ifdef HAVE_SHADER_MANAGER shader_manager_init(rgui); #endif if (*g_extern.config_path) { char history_path[PATH_MAX]; if (*g_settings.game_history_path) strlcpy(history_path, g_settings.game_history_path, sizeof(history_path)); else { fill_pathname_resolve_relative(history_path, g_extern.config_path, ".retroarch-game-history.txt", sizeof(history_path)); } RARCH_LOG("[RGUI]: Opening history: %s.\n", history_path); rgui->history = rom_history_init(history_path, g_settings.game_history_size); } rgui->last_time = rarch_get_time_usec(); }
/** * load_symbols: * @type : Type of core to be loaded. * If CORE_TYPE_DUMMY, will * load dummy symbols. * * Setup libretro callback symbols. **/ static void load_symbols(enum rarch_core_type type) { switch (type) { case CORE_TYPE_PLAIN: { #ifdef HAVE_DYNAMIC settings_t *settings = config_get_ptr(); function_t sym = dylib_proc(NULL, "retro_init"); if (sym) { /* Try to verify that -lretro was not linked in from other modules * since loading it dynamically and with -l will fail hard. */ RARCH_ERR("Serious problem. RetroArch wants to load libretro cores 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 (!*settings->libretro) { RARCH_ERR("RetroArch is built for dynamic libretro cores, but libretro_path is not set. Cannot continue.\n"); rarch_fail(1, "init_libretro_sym()"); } /* Need to use absolute path for this setting. It can be * saved to content history, and a relative path would * break in that scenario. */ path_resolve_realpath(settings->libretro, sizeof(settings->libretro)); RARCH_LOG("Loading dynamic libretro core from: \"%s\"\n", settings->libretro); lib_handle = dylib_load(settings->libretro); if (!lib_handle) { RARCH_ERR("Failed to open libretro core: \"%s\"\n", settings->libretro); rarch_fail(1, "load_dynamic()"); } #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); break; case CORE_TYPE_DUMMY: 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); break; #ifdef HAVE_FFMPEG case CORE_TYPE_FFMPEG: SYM_FFMPEG(retro_init); SYM_FFMPEG(retro_deinit); SYM_FFMPEG(retro_api_version); SYM_FFMPEG(retro_get_system_info); SYM_FFMPEG(retro_get_system_av_info); SYM_FFMPEG(retro_set_environment); SYM_FFMPEG(retro_set_video_refresh); SYM_FFMPEG(retro_set_audio_sample); SYM_FFMPEG(retro_set_audio_sample_batch); SYM_FFMPEG(retro_set_input_poll); SYM_FFMPEG(retro_set_input_state); SYM_FFMPEG(retro_set_controller_port_device); SYM_FFMPEG(retro_reset); SYM_FFMPEG(retro_run); SYM_FFMPEG(retro_serialize_size); SYM_FFMPEG(retro_serialize); SYM_FFMPEG(retro_unserialize); SYM_FFMPEG(retro_cheat_reset); SYM_FFMPEG(retro_cheat_set); SYM_FFMPEG(retro_load_game); SYM_FFMPEG(retro_load_game_special); SYM_FFMPEG(retro_unload_game); SYM_FFMPEG(retro_get_region); SYM_FFMPEG(retro_get_memory_data); SYM_FFMPEG(retro_get_memory_size); break; #endif case CORE_TYPE_IMAGEVIEWER: #ifdef HAVE_IMAGEVIEWER SYM_IMAGEVIEWER(retro_init); SYM_IMAGEVIEWER(retro_deinit); SYM_IMAGEVIEWER(retro_api_version); SYM_IMAGEVIEWER(retro_get_system_info); SYM_IMAGEVIEWER(retro_get_system_av_info); SYM_IMAGEVIEWER(retro_set_environment); SYM_IMAGEVIEWER(retro_set_video_refresh); SYM_IMAGEVIEWER(retro_set_audio_sample); SYM_IMAGEVIEWER(retro_set_audio_sample_batch); SYM_IMAGEVIEWER(retro_set_input_poll); SYM_IMAGEVIEWER(retro_set_input_state); SYM_IMAGEVIEWER(retro_set_controller_port_device); SYM_IMAGEVIEWER(retro_reset); SYM_IMAGEVIEWER(retro_run); SYM_IMAGEVIEWER(retro_serialize_size); SYM_IMAGEVIEWER(retro_serialize); SYM_IMAGEVIEWER(retro_unserialize); SYM_IMAGEVIEWER(retro_cheat_reset); SYM_IMAGEVIEWER(retro_cheat_set); SYM_IMAGEVIEWER(retro_load_game); SYM_IMAGEVIEWER(retro_load_game_special); SYM_IMAGEVIEWER(retro_unload_game); SYM_IMAGEVIEWER(retro_get_region); SYM_IMAGEVIEWER(retro_get_memory_data); SYM_IMAGEVIEWER(retro_get_memory_size); #endif break; } }
void init_video_input(void) { unsigned max_dim, scale, width, height; const input_driver_t *tmp = NULL; const struct retro_game_geometry *geom = NULL; rarch_init_filter(g_extern.system.pix_fmt); init_shader_dir(); geom = (const struct retro_game_geometry*)&g_extern.system.av_info.geometry; max_dim = max(geom->max_width, geom->max_height); scale = next_pow2(max_dim) / RARCH_SCALE_BASE; scale = max(scale, 1); if (g_extern.filter.filter) scale = g_extern.filter.scale; // Update core-dependent aspect ratio values. gfx_set_square_pixel_viewport(geom->base_width, geom->base_height); gfx_set_core_viewport(); gfx_set_config_viewport(); // Update CUSTOM viewport. rarch_viewport_t *custom_vp = &g_extern.console.screen.viewports.custom_vp; if (g_settings.video.aspect_ratio_idx == ASPECT_RATIO_CUSTOM) { float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (custom_vp->width && custom_vp->height) ? (float)custom_vp->width / custom_vp->height : default_aspect; } g_extern.system.aspect_ratio = aspectratio_lut[g_settings.video.aspect_ratio_idx].value; if (g_settings.video.fullscreen) { width = g_settings.video.fullscreen_x; height = g_settings.video.fullscreen_y; } else { if (g_settings.video.force_aspect) { // Do rounding here to simplify integer scale correctness. unsigned base_width = roundf(geom->base_height * g_extern.system.aspect_ratio); width = roundf(base_width * g_settings.video.scale); height = roundf(geom->base_height * g_settings.video.scale); } else { width = roundf(geom->base_width * g_settings.video.scale); height = roundf(geom->base_height * g_settings.video.scale); } } if (width && height) RARCH_LOG("Video @ %ux%u\n", width, height); else RARCH_LOG("Video @ fullscreen\n"); driver.display_type = RARCH_DISPLAY_NONE; driver.video_display = 0; driver.video_window = 0; if (!init_video_pixel_converter(RARCH_SCALE_BASE * scale)) { RARCH_ERR("Failed to initialize pixel converter.\n"); rarch_fail(1, "init_video_input()"); } video_info_t video = {0}; video.width = width; video.height = height; video.fullscreen = g_settings.video.fullscreen; video.vsync = g_settings.video.vsync && !g_extern.system.force_nonblock; video.force_aspect = g_settings.video.force_aspect; #ifdef GEKKO video.viwidth = g_settings.video.viwidth; #endif video.smooth = g_settings.video.smooth; video.input_scale = scale; video.rgb32 = g_extern.filter.filter ? g_extern.filter.out_rgb32 : (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); tmp = (const input_driver_t*)driver.input; find_video_driver(); // Need to grab the "real" video driver interface on a reinit. #ifdef HAVE_THREADS if (g_settings.video.threaded && !g_extern.system.hw_render_callback.context_type) // Can't do hardware rendering with threaded driver currently. { RARCH_LOG("Starting threaded video driver ...\n"); if (!rarch_threaded_video_init(&driver.video, &driver.video_data, &driver.input, &driver.input_data, driver.video, &video)) { RARCH_ERR("Cannot open threaded video driver ... Exiting ...\n"); rarch_fail(1, "init_video_input()"); } } else #endif driver.video_data = driver.video->init(&video, &driver.input, &driver.input_data); if (!driver.video_data) { RARCH_ERR("Cannot open video driver ... Exiting ...\n"); rarch_fail(1, "init_video_input()"); } driver.video_poke = NULL; if (driver.video->poke_interface) driver.video->poke_interface(driver.video_data, &driver.video_poke); // Force custom viewport to have sane parameters. if (driver.video->viewport_info && (!custom_vp->width || !custom_vp->height)) { custom_vp->width = width; custom_vp->height = height; driver.video->viewport_info(driver.video_data, custom_vp); } if (driver.video->set_rotation) driver.video->set_rotation(driver.video_data, (g_settings.video.rotation + g_extern.system.rotation) % 4); #ifdef HAVE_X11 if (driver.display_type == RARCH_DISPLAY_X11) { RARCH_LOG("Suspending screensaver (X11).\n"); x11_suspend_screensaver(driver.video_window); } #endif // Video driver didn't provide an input driver so we use configured one. if (!driver.input) { RARCH_LOG("Graphics driver did not initialize an input driver. Attempting to pick a suitable driver.\n"); if (tmp) driver.input = tmp; else find_input_driver(); if (driver.input) { driver.input_data = driver.input->init(); if (!driver.input_data) { RARCH_ERR("Cannot initialize input driver. Exiting ...\n"); rarch_fail(1, "init_video_input()"); } } else { // This should never really happen as tmp (driver.input) is always found before this in find_driver_input(), // or we have aborted in a similar fashion anyways. rarch_fail(1, "init_video_input()"); } } rarch_main_command(RARCH_CMD_OVERLAY_DEINIT); rarch_main_command(RARCH_CMD_OVERLAY_INIT); g_extern.measure_data.frame_time_samples_count = 0; }
void init_audio(void) { audio_convert_init_simd(); // Resource leaks will follow if audio is initialized twice. if (driver.audio_data) return; // Accomodate rewind since at some point we might have two full buffers. size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; size_t outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * g_settings.slowmotion_ratio; // Used for recording even if audio isn't enabled. rarch_assert(g_extern.audio_data.conv_outsamples = (int16_t*)malloc(outsamples_max * sizeof(int16_t))); g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size; // Needs to be able to hold full content of a full max_bufsamples in addition to its own. rarch_assert(g_extern.audio_data.rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t))); g_extern.audio_data.rewind_size = max_bufsamples; if (!g_settings.audio.enable) { g_extern.audio_active = false; return; } find_audio_driver(); #ifdef HAVE_THREADS if (g_extern.system.audio_callback.callback) { RARCH_LOG("Starting threaded audio driver ...\n"); if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data, *g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency, driver.audio)) { RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); rarch_fail(1, "init_audio()"); } } else #endif { driver.audio_data = driver.audio->init(*g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency); } if (!driver.audio_data) { RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); g_extern.audio_active = false; } g_extern.audio_data.use_float = false; if (g_extern.audio_active && driver.audio->use_float && driver.audio->use_float(driver.audio_data)) g_extern.audio_data.use_float = true; if (!g_settings.audio.sync && g_extern.audio_active) { rarch_main_command(RARCH_CMD_AUDIO_SET_NONBLOCKING_STATE); g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size; } // Should never happen. if (g_extern.audio_data.in_rate <= 0.0f) { RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", g_extern.audio_data.in_rate, g_settings.audio.out_rate); g_extern.audio_data.in_rate = g_settings.audio.out_rate; } g_extern.audio_data.orig_src_ratio = g_extern.audio_data.src_ratio = (double)g_settings.audio.out_rate / g_extern.audio_data.in_rate; if (!rarch_resampler_realloc(&g_extern.audio_data.resampler_data, &g_extern.audio_data.resampler, g_settings.audio.resampler, g_extern.audio_data.orig_src_ratio)) { RARCH_ERR("Failed to initialize resampler \"%s\".\n", g_settings.audio.resampler); g_extern.audio_active = false; } rarch_assert(g_extern.audio_data.data = (float*)malloc(max_bufsamples * sizeof(float))); g_extern.audio_data.data_ptr = 0; rarch_assert(g_settings.audio.out_rate < g_extern.audio_data.in_rate * AUDIO_MAX_RATIO); rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float))); g_extern.audio_data.rate_control = false; if (!g_extern.system.audio_callback.callback && g_extern.audio_active && g_settings.audio.rate_control) { if (driver.audio->buffer_size && driver.audio->write_avail) { g_extern.audio_data.driver_buffer_size = driver.audio->buffer_size(driver.audio_data); g_extern.audio_data.rate_control = true; } else RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); } rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); g_extern.measure_data.buffer_free_samples_count = 0; if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback.callback) // Threaded driver is initially stopped. driver.audio->start(driver.audio_data); }
static void load_symbols(bool is_dummy) { if (is_dummy) { 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); } else { #ifdef HAVE_DYNAMIC if (path_is_directory(g_settings.libretro)) { char libretro_core_buffer[PATH_MAX]; if (!find_first_libretro(libretro_core_buffer, sizeof(libretro_core_buffer), g_settings.libretro, g_extern.fullpath)) { RARCH_ERR("libretro_path is a directory, but no valid libretro implementation was found.\n"); rarch_fail(1, "load_dynamic()"); } strlcpy(g_settings.libretro, libretro_core_buffer, sizeof(g_settings.libretro)); } // Need to use absolute path for this setting. It can be saved to ROM history, // and a relative path would break in that scenario. path_resolve_realpath(g_settings.libretro, sizeof(g_settings.libretro)); RARCH_LOG("Loading dynamic libretro from: \"%s\"\n", g_settings.libretro); lib_handle = dylib_load(g_settings.libretro); if (!lib_handle) { RARCH_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libretro); rarch_fail(1, "load_dynamic()"); } #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_audio(void) { size_t outsamples_max, max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; runloop_t *runloop = rarch_main_get_ptr(); driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); audio_convert_init_simd(); /* Resource leaks will follow if audio is initialized twice. */ if (driver->audio_data) return; /* Accomodate rewind since at some point we might have two full buffers. */ outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * settings->slowmotion_ratio; /* Used for recording even if audio isn't enabled. */ rarch_assert(global->audio_data.conv_outsamples = (int16_t*)malloc(outsamples_max * sizeof(int16_t))); if (!global->audio_data.conv_outsamples) goto error; global->audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; global->audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; global->audio_data.chunk_size = global->audio_data.block_chunk_size; /* Needs to be able to hold full content of a full max_bufsamples * in addition to its own. */ rarch_assert(global->audio_data.rewind_buf = (int16_t*) malloc(max_bufsamples * sizeof(int16_t))); if (!global->audio_data.rewind_buf) goto error; global->audio_data.rewind_size = max_bufsamples; if (!settings->audio.enable) { driver->audio_active = false; return; } find_audio_driver(); #ifdef HAVE_THREADS if (global->system.audio_callback.callback) { RARCH_LOG("Starting threaded audio driver ...\n"); if (!rarch_threaded_audio_init(&driver->audio, &driver->audio_data, *settings->audio.device ? settings->audio.device : NULL, settings->audio.out_rate, settings->audio.latency, driver->audio)) { RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); rarch_fail(1, "init_audio()"); } } else #endif { driver->audio_data = driver->audio->init(*settings->audio.device ? settings->audio.device : NULL, settings->audio.out_rate, settings->audio.latency); } if (!driver->audio_data) { RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); driver->audio_active = false; } global->audio_data.use_float = false; if (driver->audio_active && driver->audio->use_float(driver->audio_data)) global->audio_data.use_float = true; if (!settings->audio.sync && driver->audio_active) { rarch_main_command(RARCH_CMD_AUDIO_SET_NONBLOCKING_STATE); global->audio_data.chunk_size = global->audio_data.nonblock_chunk_size; } if (global->audio_data.in_rate <= 0.0f) { /* Should never happen. */ RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", global->audio_data.in_rate, settings->audio.out_rate); global->audio_data.in_rate = settings->audio.out_rate; } global->audio_data.orig_src_ratio = global->audio_data.src_ratio = (double)settings->audio.out_rate / global->audio_data.in_rate; if (!rarch_resampler_realloc(&driver->resampler_data, &driver->resampler, settings->audio.resampler, global->audio_data.orig_src_ratio)) { RARCH_ERR("Failed to initialize resampler \"%s\".\n", settings->audio.resampler); driver->audio_active = false; } rarch_assert(global->audio_data.data = (float*) malloc(max_bufsamples * sizeof(float))); if (!global->audio_data.data) goto error; global->audio_data.data_ptr = 0; rarch_assert(settings->audio.out_rate < global->audio_data.in_rate * AUDIO_MAX_RATIO); rarch_assert(global->audio_data.outsamples = (float*) malloc(outsamples_max * sizeof(float))); if (!global->audio_data.outsamples) goto error; global->audio_data.rate_control = false; if (!global->system.audio_callback.callback && driver->audio_active && settings->audio.rate_control) { if (driver->audio->buffer_size && driver->audio->write_avail) { global->audio_data.driver_buffer_size = driver->audio->buffer_size(driver->audio_data); global->audio_data.rate_control = true; } else RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); } rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); runloop->measure_data.buffer_free_samples_count = 0; if (driver->audio_active && !settings->audio.mute_enable && global->system.audio_callback.callback) { /* Threaded driver is initially stopped. */ driver->audio->start(driver->audio_data); } return; error: if (global->audio_data.conv_outsamples) free(global->audio_data.conv_outsamples); global->audio_data.conv_outsamples = NULL; if (global->audio_data.data) free(global->audio_data.data); global->audio_data.data = NULL; if (global->audio_data.rewind_buf) free(global->audio_data.rewind_buf); global->audio_data.rewind_buf = NULL; if (global->audio_data.outsamples) free(global->audio_data.outsamples); global->audio_data.outsamples = NULL; }
/** * parse_input: * @argc : Count of (commandline) arguments. * @argv : (Commandline) arguments. * * Parses (commandline) arguments passed to program. * **/ static void parse_input(int argc, char *argv[]) { const char *optstring = NULL; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); const struct option opts[] = { #ifdef HAVE_DYNAMIC { "libretro", 1, NULL, 'L' }, #endif { "menu", 0, NULL, RA_OPT_MENU }, { "help", 0, NULL, 'h' }, { "save", 1, NULL, 's' }, { "fullscreen", 0, NULL, 'f' }, { "record", 1, NULL, 'r' }, { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, { "size", 1, NULL, RA_OPT_SIZE }, { "verbose", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, { "nodevice", 1, NULL, 'N' }, { "dualanalog", 1, NULL, 'A' }, { "device", 1, NULL, 'd' }, { "savestate", 1, NULL, 'S' }, { "bsvplay", 1, NULL, 'P' }, { "bsvrecord", 1, NULL, 'R' }, { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETPLAY { "host", 0, NULL, 'H' }, { "connect", 1, NULL, 'C' }, { "frames", 1, NULL, 'F' }, { "port", 1, NULL, RA_OPT_PORT }, { "spectate", 0, NULL, RA_OPT_SPECTATE }, #endif { "nick", 1, NULL, RA_OPT_NICK }, #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) { "command", 1, NULL, RA_OPT_COMMAND }, #endif { "ups", 1, NULL, 'U' }, { "bps", 1, NULL, RA_OPT_BPS }, { "ips", 1, NULL, RA_OPT_IPS }, { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, { "detach", 0, NULL, 'D' }, { "features", 0, NULL, RA_OPT_FEATURES }, { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, { "version", 0, NULL, RA_OPT_VERSION }, #ifdef HAVE_FILE_LOGGER { "log-file", 1, NULL, RA_OPT_LOG_FILE }, #endif { NULL, 0, NULL, 0 } }; global->inited.core.no_content = false; global->inited.core.type = CORE_TYPE_PLAIN; *global->subsystem = '\0'; global->has_set.save_path = false; global->has_set.state_path = false; global->has_set.libretro = false; global->has_set.libretro_directory = false; global->has_set.verbosity = false; global->has_set.netplay_mode = false; global->has_set.username = false; global->has_set.netplay_ip_address = false; global->has_set.netplay_delay_frames = false; global->has_set.netplay_ip_port = false; global->has_set.ups_pref = false; global->has_set.bps_pref = false; global->has_set.ips_pref = false; global->patch.ups_pref = false; global->patch.bps_pref = false; global->patch.ips_pref = false; *global->name.ups = '\0'; *global->name.bps = '\0'; *global->name.ips = '\0'; global->overrides_active = false; if (argc < 2) { global->inited.core.type = CORE_TYPE_DUMMY; return; } /* Make sure we can call parse_input several times ... */ optind = 0; optstring = "hs:fvS:A:c:U:DN:d:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG; for (;;) { int port; int c = getopt_long(argc, argv, optstring, opts, NULL); if (c == -1) break; switch (c) { case 'h': print_help(argv[0]); exit(0); case 'd': { unsigned id = 0; struct string_list *list = string_split(optarg, ":"); port = 0; if (list && list->size == 2) { port = strtol(list->elems[0].data, NULL, 0); id = strtoul(list->elems[1].data, NULL, 0); } string_list_free(list); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect device to a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = id; global->has_set.libretro_device[port - 1] = true; break; } case 'A': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect dualanalog to a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_ANALOG; global->has_set.libretro_device[port - 1] = true; break; case 's': strlcpy(global->name.savefile, optarg, sizeof(global->name.savefile)); global->has_set.save_path = true; break; case 'f': global->force_fullscreen = true; break; case 'S': strlcpy(global->name.savestate, optarg, sizeof(global->name.savestate)); global->has_set.state_path = true; break; case 'v': global->verbosity = true; global->has_set.verbosity = true; break; case 'N': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Disconnect device from a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_NONE; global->has_set.libretro_device[port - 1] = true; break; case 'c': strlcpy(global->path.config, optarg, sizeof(global->path.config)); break; case 'r': strlcpy(global->record.path, optarg, sizeof(global->record.path)); global->record.enable = true; break; #ifdef HAVE_DYNAMIC case 'L': if (path_is_directory(optarg)) { *settings->libretro = '\0'; strlcpy(settings->libretro_directory, optarg, sizeof(settings->libretro_directory)); global->has_set.libretro = true; global->has_set.libretro_directory = true; RARCH_WARN("Using old --libretro behavior. Setting libretro_directory to \"%s\" instead.\n", optarg); } else { strlcpy(settings->libretro, optarg, sizeof(settings->libretro)); global->has_set.libretro = true; } break; #endif case 'P': case 'R': strlcpy(global->bsv.movie_start_path, optarg, sizeof(global->bsv.movie_start_path)); global->bsv.movie_start_playback = (c == 'P'); global->bsv.movie_start_recording = (c == 'R'); break; case 'M': if (!strcmp(optarg, "noload-nosave")) { global->sram.load_disable = true; global->sram.save_disable = true; } else if (!strcmp(optarg, "noload-save")) global->sram.load_disable = true; else if (!strcmp(optarg, "load-nosave")) global->sram.save_disable = true; else if (strcmp(optarg, "load-save") != 0) { RARCH_ERR("Invalid argument in --sram-mode.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } break; #ifdef HAVE_NETPLAY case 'H': global->has_set.netplay_ip_address = true; global->netplay.enable = true; *global->netplay.server = '\0'; break; case 'C': global->has_set.netplay_ip_address = true; global->netplay.enable = true; strlcpy(global->netplay.server, optarg, sizeof(global->netplay.server)); break; case 'F': global->netplay.sync_frames = strtol(optarg, NULL, 0); global->has_set.netplay_delay_frames = true; break; #endif case RA_OPT_BPS: strlcpy(global->name.bps, optarg, sizeof(global->name.bps)); global->patch.bps_pref = true; global->has_set.bps_pref = true; break; case 'U': strlcpy(global->name.ups, optarg, sizeof(global->name.ups)); global->patch.ups_pref = true; global->has_set.ups_pref = true; break; case RA_OPT_IPS: strlcpy(global->name.ips, optarg, sizeof(global->name.ips)); global->patch.ips_pref = true; global->has_set.ips_pref = true; break; case RA_OPT_NO_PATCH: global->patch.block_patch = true; break; case 'D': #if defined(_WIN32) && !defined(_XBOX) FreeConsole(); #endif break; case RA_OPT_MENU: global->inited.core.type = CORE_TYPE_DUMMY; break; #ifdef HAVE_NETPLAY case RA_OPT_PORT: global->has_set.netplay_ip_port = true; global->netplay.port = strtoul(optarg, NULL, 0); break; case RA_OPT_SPECTATE: global->has_set.netplay_mode = true; global->netplay.is_spectate = true; break; #endif case RA_OPT_NICK: global->has_set.username = true; strlcpy(settings->username, optarg, sizeof(settings->username)); break; #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) case RA_OPT_COMMAND: if (network_cmd_send(optarg)) exit(0); else rarch_fail(1, "network_cmd_send()"); break; #endif case RA_OPT_APPENDCONFIG: strlcpy(global->path.append_config, optarg, sizeof(global->path.append_config)); break; case RA_OPT_SIZE: { if (sscanf(optarg, "%ux%u", &global->record.width, &global->record.height) != 2) { RARCH_ERR("Wrong format for --size.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } break; } case RA_OPT_RECORDCONFIG: strlcpy(global->record.config, optarg, sizeof(global->record.config)); break; case RA_OPT_MAX_FRAMES: { unsigned max_frames = strtoul(optarg, NULL, 10); rarch_main_ctl(RARCH_MAIN_CTL_SET_MAX_FRAMES, &max_frames); } break; case RA_OPT_SUBSYSTEM: strlcpy(global->subsystem, optarg, sizeof(global->subsystem)); break; case RA_OPT_FEATURES: print_features(); exit(0); case RA_OPT_EOF_EXIT: global->bsv.eof_exit = true; break; case RA_OPT_VERSION: print_version(); exit(0); #ifdef HAVE_FILE_LOGGER case RA_OPT_LOG_FILE: global->log_file = fopen(optarg, "wb"); break; #endif case '?': print_help(argv[0]); rarch_fail(1, "parse_input()"); default: RARCH_ERR("Error parsing arguments.\n"); rarch_fail(1, "parse_input()"); } } if (global->inited.core.type == CORE_TYPE_DUMMY) { if (optind < argc) { RARCH_ERR("--menu was used, but content file was passed as well.\n"); rarch_fail(1, "parse_input()"); } } else if (!*global->subsystem && optind < argc) rarch_set_paths(argv[optind]); else if (*global->subsystem && optind < argc) set_special_paths(argv + optind, argc - optind); else global->inited.core.no_content = true; /* Copy SRM/state dirs used, so they can be reused on reentrancy. */ if (global->has_set.save_path && path_is_directory(global->name.savefile)) strlcpy(global->dir.savefile, global->name.savefile, sizeof(global->dir.savefile)); if (global->has_set.state_path && path_is_directory(global->name.savestate)) strlcpy(global->dir.savestate, global->name.savestate, sizeof(global->dir.savestate)); }