From 99632f66e74fc57c463072be312d634aeb67bc61 Mon Sep 17 00:00:00 2001 From: neonloop Date: Wed, 4 Aug 2021 15:09:12 +0000 Subject: Initial commit --- patches/snes9x2002/0001-trimui-support.patch | 50 ++ patches/snes9x2002/0002-core-options.patch | 13 + patches/snes9x2002/1000-update-libretro-h.patch | 876 ++++++++++++++++++++++++ patches/snes9x2002/1001-audio-frameskip.patch | 247 +++++++ 4 files changed, 1186 insertions(+) create mode 100644 patches/snes9x2002/0001-trimui-support.patch create mode 100644 patches/snes9x2002/0002-core-options.patch create mode 100644 patches/snes9x2002/1000-update-libretro-h.patch create mode 100644 patches/snes9x2002/1001-audio-frameskip.patch (limited to 'patches/snes9x2002') diff --git a/patches/snes9x2002/0001-trimui-support.patch b/patches/snes9x2002/0001-trimui-support.patch new file mode 100644 index 0000000..eadb54c --- /dev/null +++ b/patches/snes9x2002/0001-trimui-support.patch @@ -0,0 +1,50 @@ +diff --git a/Makefile b/Makefile +index e42d169..a1f8794 100644 +--- a/Makefile ++++ b/Makefile +@@ -244,6 +244,23 @@ else ifeq ($(platform), gcw0) + CFLAGS += -fno-builtin -fno-exceptions + CFLAGS += -DPATH_MAX=256 -DFAST_LSB_WORD_ACCESS + ++else ifeq ($(platform), trimui) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,--no-undefined ++ CFLAGS += -fsingle-precision-constant -fno-PIC -flto ++ CFLAGS += -DLSB_FIRST -DFAST_ALIGNED_LSB_WORD_ACCESS -DRIGHTSHIFT_IS_SAR ++ CFLAGS += -std=c99 -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s -mtune=arm926ej-s ++ LDFLAGS += -flto ++ OFLAGS += -Ofast -DNDEBUG=1 ++ ARM_ASM = 1 ++ ASM_CPU = 0 ++ ASM_SPC700 = 0 ++ ifeq (,$(DEBUG)) ++ LDFLAGS += -s ++ endif ++ + # Windows MSVC 2010 x64 + else ifeq ($(platform), windows_msvc2010_x64) + CC = cl.exe +@@ -381,12 +398,21 @@ LIBRETRO_DIR := ./libretro + + ifeq ($(DEBUG), 1) + DEFINES += -O0 -g ++else ifneq (,$(OFLAGS)) ++DEFINES += $(OFLAGS) + else ifneq (,$(findstring msvc,$(platform))) + DEFINES += -O2 -DNDEBUG=1 + else + DEFINES += -O3 -DNDEBUG=1 + endif + ++ifeq ($(PROFILE), GENERATE) ++ CFLAGS += -fprofile-generate=./profile/snes9x2002 ++ LDFLAGS += -lgcov ++else ifeq ($(PROFILE), APPLY) ++ CFLAGS += -fprofile-use -fprofile-dir=../profile/snes9x2002 -fbranch-probabilities ++endif ++ + ifneq (,$(findstring msvc,$(platform))) + ifeq ($(DEBUG),1) + DEFINES += -MTd diff --git a/patches/snes9x2002/0002-core-options.patch b/patches/snes9x2002/0002-core-options.patch new file mode 100644 index 0000000..a908343 --- /dev/null +++ b/patches/snes9x2002/0002-core-options.patch @@ -0,0 +1,13 @@ +diff --git a/libretro/libretro.c b/libretro/libretro.c +index 81ce4aa..bc64376 100644 +--- a/libretro/libretro.c ++++ b/libretro/libretro.c +@@ -339,7 +339,7 @@ void retro_init (void) + { + static const struct retro_variable vars[] = + { +- { "snes9x2002_overclock_cycles", "Reduce Slowdown (Hack, Unsafe, Restart); disabled|compatible|max" }, ++ { "snes9x2002_overclock_cycles", "Overclock (Restart); disabled|compatible|max" }, + { NULL, NULL }, + }; + diff --git a/patches/snes9x2002/1000-update-libretro-h.patch b/patches/snes9x2002/1000-update-libretro-h.patch new file mode 100644 index 0000000..b5984f2 --- /dev/null +++ b/patches/snes9x2002/1000-update-libretro-h.patch @@ -0,0 +1,876 @@ +diff --git a/libretro/libretro-common/include/libretro.h b/libretro/libretro-common/include/libretro.h +index f97a969..32aa15f 100644 +--- a/libretro/libretro-common/include/libretro.h ++++ b/libretro/libretro-common/include/libretro.h +@@ -1,4 +1,4 @@ +-/* Copyright (C) 2010-2018 The RetroArch team ++/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro.h). +@@ -278,6 +278,11 @@ enum retro_language + RETRO_LANGUAGE_ARABIC = 16, + RETRO_LANGUAGE_GREEK = 17, + RETRO_LANGUAGE_TURKISH = 18, ++ RETRO_LANGUAGE_SLOVAK = 19, ++ RETRO_LANGUAGE_PERSIAN = 20, ++ RETRO_LANGUAGE_HEBREW = 21, ++ RETRO_LANGUAGE_ASTURIAN = 22, ++ RETRO_LANGUAGE_FINNISH = 23, + RETRO_LANGUAGE_LAST, + + /* Ensure sizeof(enum) == sizeof(int) */ +@@ -708,6 +713,9 @@ enum retro_mod + * state of rumble motors in controllers. + * A strong and weak motor is supported, and they can be + * controlled indepedently. ++ * Should be called from either retro_init() or retro_load_game(). ++ * Should not be called from retro_set_environment(). ++ * Returns false if rumble functionality is unavailable. + */ + #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 + /* uint64_t * -- +@@ -1087,10 +1095,10 @@ enum retro_mod + + #define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* float * -- +- * Float value that lets us know what target refresh rate ++ * Float value that lets us know what target refresh rate + * is curently in use by the frontend. + * +- * The core can use the returned value to set an ideal ++ * The core can use the returned value to set an ideal + * refresh rate/framerate. + */ + +@@ -1098,7 +1106,7 @@ enum retro_mod + /* bool * -- + * Boolean value that indicates whether or not the frontend supports + * input bitmasks being returned by retro_input_state_t. The advantage +- * of this is that retro_input_state_t has to be only called once to ++ * of this is that retro_input_state_t has to be only called once to + * grab all button states instead of multiple times. + * + * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' +@@ -1174,7 +1182,7 @@ enum retro_mod + * "foo_option", + * "Speed hack coprocessor X", + * "Provides increased performance at the expense of reduced accuracy", +- * { ++ * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, +@@ -1246,6 +1254,245 @@ enum retro_mod + * default when calling SET_VARIABLES/SET_CORE_OPTIONS. + */ + ++#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56 ++ /* unsigned * -- ++ * ++ * Allows an implementation to ask frontend preferred hardware ++ * context to use. Core should use this information to deal ++ * with what specific context to request with SET_HW_RENDER. ++ * ++ * 'data' points to an unsigned variable ++ */ ++ ++#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57 ++ /* unsigned * -- ++ * Unsigned value is the API version number of the disk control ++ * interface supported by the frontend. If callback return false, ++ * API version is assumed to be 0. ++ * ++ * In legacy code, the disk control interface is defined by passing ++ * a struct of type retro_disk_control_callback to ++ * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. ++ * This may be still be done regardless of the disk control ++ * interface version. ++ * ++ * If version is >= 1 however, the disk control interface may ++ * instead be defined by passing a struct of type ++ * retro_disk_control_ext_callback to ++ * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. ++ * This allows the core to provide additional information about ++ * disk images to the frontend and/or enables extra ++ * disk control functionality by the frontend. ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58 ++ /* const struct retro_disk_control_ext_callback * -- ++ * Sets an interface which frontend can use to eject and insert ++ * disk images, and also obtain information about individual ++ * disk image files registered by the core. ++ * This is used for games which consist of multiple images and ++ * must be manually swapped out by the user (e.g. PSX, floppy disk ++ * based systems). ++ */ ++ ++#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59 ++ /* unsigned * -- ++ * Unsigned value is the API version number of the message ++ * interface supported by the frontend. If callback returns ++ * false, API version is assumed to be 0. ++ * ++ * In legacy code, messages may be displayed in an ++ * implementation-specific manner by passing a struct ++ * of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE. ++ * This may be still be done regardless of the message ++ * interface version. ++ * ++ * If version is >= 1 however, messages may instead be ++ * displayed by passing a struct of type retro_message_ext ++ * to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the ++ * core to specify message logging level, priority and ++ * destination (OSD, logging interface or both). ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60 ++ /* const struct retro_message_ext * -- ++ * Sets a message to be displayed in an implementation-specific ++ * manner for a certain amount of 'frames'. Additionally allows ++ * the core to specify message logging level, priority and ++ * destination (OSD, logging interface or both). ++ * Should not be used for trivial messages, which should simply be ++ * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a ++ * fallback, stderr). ++ */ ++ ++#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61 ++ /* unsigned * -- ++ * Unsigned value is the number of active input devices ++ * provided by the frontend. This may change between ++ * frames, but will remain constant for the duration ++ * of each frame. ++ * If callback returns true, a core need not poll any ++ * input device with an index greater than or equal to ++ * the number of active devices. ++ * If callback returns false, the number of active input ++ * devices is unknown. In this case, all input devices ++ * should be considered active. ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62 ++ /* const struct retro_audio_buffer_status_callback * -- ++ * Lets the core know the occupancy level of the frontend ++ * audio buffer. Can be used by a core to attempt frame ++ * skipping in order to avoid buffer under-runs. ++ * A core may pass NULL to disable buffer status reporting ++ * in the frontend. ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63 ++ /* const unsigned * -- ++ * Sets minimum frontend audio latency in milliseconds. ++ * Resultant audio latency may be larger than set value, ++ * or smaller if a hardware limit is encountered. A frontend ++ * is expected to honour requests up to 512 ms. ++ * ++ * - If value is less than current frontend ++ * audio latency, callback has no effect ++ * - If value is zero, default frontend audio ++ * latency is set ++ * ++ * May be used by a core to increase audio latency and ++ * therefore decrease the probability of buffer under-runs ++ * (crackling) when performing 'intensive' operations. ++ * A core utilising RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK ++ * to implement audio-buffer-based frame skipping may achieve ++ * optimal results by setting the audio latency to a 'high' ++ * (typically 6x or 8x) integer multiple of the expected ++ * frame time. ++ * ++ * WARNING: This can only be called from within retro_run(). ++ * Calling this can require a full reinitialization of audio ++ * drivers in the frontend, so it is important to call it very ++ * sparingly, and usually only with the users explicit consent. ++ * An eventual driver reinitialize will happen so that audio ++ * callbacks happening after this call within the same retro_run() ++ * call will target the newly initialized driver. ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64 ++ /* const struct retro_fastforwarding_override * -- ++ * Used by a libretro core to override the current ++ * fastforwarding mode of the frontend. ++ * If NULL is passed to this function, the frontend ++ * will return true if fastforwarding override ++ * functionality is supported (no change in ++ * fastforwarding state will occur in this case). ++ */ ++ ++#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65 ++ /* const struct retro_system_content_info_override * -- ++ * Allows an implementation to override 'global' content ++ * info parameters reported by retro_get_system_info(). ++ * Overrides also affect subsystem content info parameters ++ * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO. ++ * This function must be called inside retro_set_environment(). ++ * If callback returns false, content info overrides ++ * are unsupported by the frontend, and will be ignored. ++ * If callback returns true, extended game info may be ++ * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT ++ * in retro_load_game() or retro_load_game_special(). ++ * ++ * 'data' points to an array of retro_system_content_info_override ++ * structs terminated by a { NULL, false, false } element. ++ * If 'data' is NULL, no changes will be made to the frontend; ++ * a core may therefore pass NULL in order to test whether ++ * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and ++ * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported ++ * by the frontend. ++ * ++ * For struct member descriptions, see the definition of ++ * struct retro_system_content_info_override. ++ * ++ * Example: ++ * ++ * - struct retro_system_info: ++ * { ++ * "My Core", // library_name ++ * "v1.0", // library_version ++ * "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions ++ * true, // need_fullpath ++ * false // block_extract ++ * } ++ * ++ * - Array of struct retro_system_content_info_override: ++ * { ++ * { ++ * "md|sms|gg", // extensions ++ * false, // need_fullpath ++ * true // persistent_data ++ * }, ++ * { ++ * "sg", // extensions ++ * false, // need_fullpath ++ * false // persistent_data ++ * }, ++ * { NULL, false, false } ++ * } ++ * ++ * Result: ++ * - Files of type m3u, cue, iso, chd will not be ++ * loaded by the frontend. Frontend will pass a ++ * valid path to the core, and core will handle ++ * loading internally ++ * - Files of type md, sms, gg will be loaded by ++ * the frontend. A valid memory buffer will be ++ * passed to the core. This memory buffer will ++ * remain valid until retro_deinit() returns ++ * - Files of type sg will be loaded by the frontend. ++ * A valid memory buffer will be passed to the core. ++ * This memory buffer will remain valid until ++ * retro_load_game() (or retro_load_game_special()) ++ * returns ++ * ++ * NOTE: If an extension is listed multiple times in ++ * an array of retro_system_content_info_override ++ * structs, only the first instance will be registered ++ */ ++ ++#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66 ++ /* const struct retro_game_info_ext ** -- ++ * Allows an implementation to fetch extended game ++ * information, providing additional content path ++ * and memory buffer status details. ++ * This function may only be called inside ++ * retro_load_game() or retro_load_game_special(). ++ * If callback returns false, extended game information ++ * is unsupported by the frontend. In this case, only ++ * regular retro_game_info will be available. ++ * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed ++ * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE ++ * returns true. ++ * ++ * 'data' points to an array of retro_game_info_ext structs. ++ * ++ * For struct member descriptions, see the definition of ++ * struct retro_game_info_ext. ++ * ++ * - If function is called inside retro_load_game(), ++ * the retro_game_info_ext array is guaranteed to ++ * have a size of 1 - i.e. the returned pointer may ++ * be used to access directly the members of the ++ * first retro_game_info_ext struct, for example: ++ * ++ * struct retro_game_info_ext *game_info_ext; ++ * if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext)) ++ * printf("Content Directory: %s\n", game_info_ext->dir); ++ * ++ * - If the function is called inside retro_load_game_special(), ++ * the retro_game_info_ext array is guaranteed to have a ++ * size equal to the num_info argument passed to ++ * retro_load_game_special() ++ */ ++ + /* VFS functionality */ + + /* File paths: +@@ -1382,17 +1629,17 @@ typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle * + struct retro_vfs_interface + { + /* VFS API v1 */ +- retro_vfs_get_path_t get_path; +- retro_vfs_open_t open; +- retro_vfs_close_t close; +- retro_vfs_size_t size; +- retro_vfs_tell_t tell; +- retro_vfs_seek_t seek; +- retro_vfs_read_t read; +- retro_vfs_write_t write; +- retro_vfs_flush_t flush; +- retro_vfs_remove_t remove; +- retro_vfs_rename_t rename; ++ retro_vfs_get_path_t get_path; ++ retro_vfs_open_t open; ++ retro_vfs_close_t close; ++ retro_vfs_size_t size; ++ retro_vfs_tell_t tell; ++ retro_vfs_seek_t seek; ++ retro_vfs_read_t read; ++ retro_vfs_write_t write; ++ retro_vfs_flush_t flush; ++ retro_vfs_remove_t remove; ++ retro_vfs_rename_t rename; + /* VFS API v2 */ + retro_vfs_truncate_t truncate; + /* VFS API v3 */ +@@ -1420,11 +1667,11 @@ struct retro_vfs_interface_info + + enum retro_hw_render_interface_type + { +- RETRO_HW_RENDER_INTERFACE_VULKAN = 0, +- RETRO_HW_RENDER_INTERFACE_D3D9 = 1, +- RETRO_HW_RENDER_INTERFACE_D3D10 = 2, +- RETRO_HW_RENDER_INTERFACE_D3D11 = 3, +- RETRO_HW_RENDER_INTERFACE_D3D12 = 4, ++ RETRO_HW_RENDER_INTERFACE_VULKAN = 0, ++ RETRO_HW_RENDER_INTERFACE_D3D9 = 1, ++ RETRO_HW_RENDER_INTERFACE_D3D10 = 2, ++ RETRO_HW_RENDER_INTERFACE_D3D11 = 3, ++ RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, + RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX + }; +@@ -1922,6 +2169,10 @@ enum retro_sensor_action + { + RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, + RETRO_SENSOR_ACCELEROMETER_DISABLE, ++ RETRO_SENSOR_GYROSCOPE_ENABLE, ++ RETRO_SENSOR_GYROSCOPE_DISABLE, ++ RETRO_SENSOR_ILLUMINANCE_ENABLE, ++ RETRO_SENSOR_ILLUMINANCE_DISABLE, + + RETRO_SENSOR_DUMMY = INT_MAX + }; +@@ -1930,6 +2181,10 @@ enum retro_sensor_action + #define RETRO_SENSOR_ACCELEROMETER_X 0 + #define RETRO_SENSOR_ACCELEROMETER_Y 1 + #define RETRO_SENSOR_ACCELEROMETER_Z 2 ++#define RETRO_SENSOR_GYROSCOPE_X 3 ++#define RETRO_SENSOR_GYROSCOPE_Y 4 ++#define RETRO_SENSOR_GYROSCOPE_Z 5 ++#define RETRO_SENSOR_ILLUMINANCE 6 + + typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port, + enum retro_sensor_action action, unsigned rate); +@@ -2127,6 +2382,30 @@ struct retro_frame_time_callback + retro_usec_t reference; + }; + ++/* Notifies a libretro core of the current occupancy ++ * level of the frontend audio buffer. ++ * ++ * - active: 'true' if audio buffer is currently ++ * in use. Will be 'false' if audio is ++ * disabled in the frontend ++ * ++ * - occupancy: Given as a value in the range [0,100], ++ * corresponding to the occupancy percentage ++ * of the audio buffer ++ * ++ * - underrun_likely: 'true' if the frontend expects an ++ * audio buffer underrun during the ++ * next frame (indicates that a core ++ * should attempt frame skipping) ++ * ++ * It will be called right before retro_run() every frame. */ ++typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)( ++ bool active, unsigned occupancy, bool underrun_likely); ++struct retro_audio_buffer_status_callback ++{ ++ retro_audio_buffer_status_callback_t callback; ++}; ++ + /* Pass this to retro_video_refresh_t if rendering to hardware. + * Passing NULL to retro_video_refresh_t is still a frame dupe as normal. + * */ +@@ -2287,7 +2566,8 @@ struct retro_keyboard_callback + retro_keyboard_event_t callback; + }; + +-/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. ++/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE & ++ * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. + * Should be set for implementations which can swap out multiple disk + * images in runtime. + * +@@ -2345,6 +2625,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index, + * with replace_image_index. */ + typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); + ++/* Sets initial image to insert in drive when calling ++ * core_load_game(). ++ * Since we cannot pass the initial index when loading ++ * content (this would require a major API change), this ++ * is set by the frontend *before* calling the core's ++ * retro_load_game()/retro_load_game_special() implementation. ++ * A core should therefore cache the index/path values and handle ++ * them inside retro_load_game()/retro_load_game_special(). ++ * - If 'index' is invalid (index >= get_num_images()), the ++ * core should ignore the set value and instead use 0 ++ * - 'path' is used purely for error checking - i.e. when ++ * content is loaded, the core should verify that the ++ * disk specified by 'index' has the specified file path. ++ * This is to guard against auto selecting the wrong image ++ * if (for example) the user should modify an existing M3U ++ * playlist. We have to let the core handle this because ++ * set_initial_image() must be called before loading content, ++ * i.e. the frontend cannot access image paths in advance ++ * and thus cannot perform the error check itself. ++ * If set path and content path do not match, the core should ++ * ignore the set 'index' value and instead use 0 ++ * Returns 'false' if index or 'path' are invalid, or core ++ * does not support this functionality ++ */ ++typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path); ++ ++/* Fetches the path of the specified disk image file. ++ * Returns 'false' if index is invalid (index >= get_num_images()) ++ * or path is otherwise unavailable. ++ */ ++typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len); ++ ++/* Fetches a core-provided 'label' for the specified disk ++ * image file. In the simplest case this may be a file name ++ * (without extension), but for cores with more complex ++ * content requirements information may be provided to ++ * facilitate user disk swapping - for example, a core ++ * running floppy-disk-based content may uniquely label ++ * save disks, data disks, level disks, etc. with names ++ * corresponding to in-game disk change prompts (so the ++ * frontend can provide better user guidance than a 'dumb' ++ * disk index value). ++ * Returns 'false' if index is invalid (index >= get_num_images()) ++ * or label is otherwise unavailable. ++ */ ++typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len); ++ + struct retro_disk_control_callback + { + retro_set_eject_state_t set_eject_state; +@@ -2358,6 +2685,27 @@ struct retro_disk_control_callback + retro_add_image_index_t add_image_index; + }; + ++struct retro_disk_control_ext_callback ++{ ++ retro_set_eject_state_t set_eject_state; ++ retro_get_eject_state_t get_eject_state; ++ ++ retro_get_image_index_t get_image_index; ++ retro_set_image_index_t set_image_index; ++ retro_get_num_images_t get_num_images; ++ ++ retro_replace_image_index_t replace_image_index; ++ retro_add_image_index_t add_image_index; ++ ++ /* NOTE: Frontend will only attempt to record/restore ++ * last used disk index if both set_initial_image() ++ * and get_image_path() are implemented */ ++ retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */ ++ ++ retro_get_image_path_t get_image_path; /* Optional - may be NULL */ ++ retro_get_image_label_t get_image_label; /* Optional - may be NULL */ ++}; ++ + enum retro_pixel_format + { + /* 0RGB1555, native endian. +@@ -2388,6 +2736,104 @@ struct retro_message + unsigned frames; /* Duration in frames of message. */ + }; + ++enum retro_message_target ++{ ++ RETRO_MESSAGE_TARGET_ALL = 0, ++ RETRO_MESSAGE_TARGET_OSD, ++ RETRO_MESSAGE_TARGET_LOG ++}; ++ ++enum retro_message_type ++{ ++ RETRO_MESSAGE_TYPE_NOTIFICATION = 0, ++ RETRO_MESSAGE_TYPE_NOTIFICATION_ALT, ++ RETRO_MESSAGE_TYPE_STATUS, ++ RETRO_MESSAGE_TYPE_PROGRESS ++}; ++ ++struct retro_message_ext ++{ ++ /* Message string to be displayed/logged */ ++ const char *msg; ++ /* Duration (in ms) of message when targeting the OSD */ ++ unsigned duration; ++ /* Message priority when targeting the OSD ++ * > When multiple concurrent messages are sent to ++ * the frontend and the frontend does not have the ++ * capacity to display them all, messages with the ++ * *highest* priority value should be shown ++ * > There is no upper limit to a message priority ++ * value (within the bounds of the unsigned data type) ++ * > In the reference frontend (RetroArch), the same ++ * priority values are used for frontend-generated ++ * notifications, which are typically assigned values ++ * between 0 and 3 depending upon importance */ ++ unsigned priority; ++ /* Message logging level (info, warn, error, etc.) */ ++ enum retro_log_level level; ++ /* Message destination: OSD, logging interface or both */ ++ enum retro_message_target target; ++ /* Message 'type' when targeting the OSD ++ * > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a ++ * message should be handled in identical fashion to ++ * a standard frontend-generated notification ++ * > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that ++ * message is a notification that requires user attention ++ * or action, but that it should be displayed in a manner ++ * that differs from standard frontend-generated notifications. ++ * This would typically correspond to messages that should be ++ * displayed immediately (independently from any internal ++ * frontend message queue), and/or which should be visually ++ * distinguishable from frontend-generated notifications. ++ * For example, a core may wish to inform the user of ++ * information related to a disk-change event. It is ++ * expected that the frontend itself may provide a ++ * notification in this case; if the core sends a ++ * message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an ++ * uncomfortable 'double-notification' may occur. A message ++ * of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore ++ * be presented such that visual conflict with regular ++ * notifications does not occur ++ * > RETRO_MESSAGE_TYPE_STATUS: Indicates that message ++ * is not a standard notification. This typically ++ * corresponds to 'status' indicators, such as a core's ++ * internal FPS, which are intended to be displayed ++ * either permanently while a core is running, or in ++ * a manner that does not suggest user attention or action ++ * is required. 'Status' type messages should therefore be ++ * displayed in a different on-screen location and in a manner ++ * easily distinguishable from both standard frontend-generated ++ * notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT ++ * > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports ++ * the progress of an internal core task. For example, in cases ++ * where a core itself handles the loading of content from a file, ++ * this may correspond to the percentage of the file that has been ++ * read. Alternatively, an audio/video playback core may use a ++ * message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current ++ * playback position as a percentage of the runtime. 'Progress' type ++ * messages should therefore be displayed as a literal progress bar, ++ * where: ++ * - 'retro_message_ext.msg' is the progress bar title/label ++ * - 'retro_message_ext.progress' determines the length of ++ * the progress bar ++ * NOTE: Message type is a *hint*, and may be ignored ++ * by the frontend. If a frontend lacks support for ++ * displaying messages via alternate means than standard ++ * frontend-generated notifications, it will treat *all* ++ * messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */ ++ enum retro_message_type type; ++ /* Task progress when targeting the OSD and message is ++ * of type RETRO_MESSAGE_TYPE_PROGRESS ++ * > -1: Unmetered/indeterminate ++ * > 0-100: Current progress percentage ++ * NOTE: Since message type is a hint, a frontend may ignore ++ * progress values. Where relevant, a core should therefore ++ * include progress percentage within the message string, ++ * such that the message intent remains clear when displayed ++ * as a standard frontend-generated notification */ ++ int8_t progress; ++}; ++ + /* Describes how the libretro implementation maps a libretro input bind + * to its internal input system through a human readable string. + * This string can be used to better let a user configure input. */ +@@ -2408,7 +2854,7 @@ struct retro_input_descriptor + struct retro_system_info + { + /* All pointers are owned by libretro implementation, and pointers must +- * remain valid until retro_deinit() is called. */ ++ * remain valid until it is unloaded. */ + + const char *library_name; /* Descriptive name of library. Should not + * contain any version numbers, etc. */ +@@ -2450,6 +2896,213 @@ struct retro_system_info + bool block_extract; + }; + ++/* Defines overrides which modify frontend handling of ++ * specific content file types. ++ * An array of retro_system_content_info_override is ++ * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE ++ * NOTE: In the following descriptions, references to ++ * retro_load_game() may be replaced with ++ * retro_load_game_special() */ ++struct retro_system_content_info_override ++{ ++ /* A list of file extensions for which the override ++ * should apply, delimited by a 'pipe' character ++ * (e.g. "md|sms|gg") ++ * Permitted file extensions are limited to those ++ * included in retro_system_info::valid_extensions ++ * and/or retro_subsystem_rom_info::valid_extensions */ ++ const char *extensions; ++ ++ /* Overrides the need_fullpath value set in ++ * retro_system_info and/or retro_subsystem_rom_info. ++ * To reiterate: ++ * ++ * If need_fullpath is true and retro_load_game() is called: ++ * - retro_game_info::path is guaranteed to contain a valid ++ * path to an existent file ++ * - retro_game_info::data and retro_game_info::size are invalid ++ * ++ * If need_fullpath is false and retro_load_game() is called: ++ * - retro_game_info::path may be NULL ++ * - retro_game_info::data and retro_game_info::size are guaranteed ++ * to be valid ++ * ++ * In addition: ++ * ++ * If need_fullpath is true and retro_load_game() is called: ++ * - retro_game_info_ext::full_path is guaranteed to contain a valid ++ * path to an existent file ++ * - retro_game_info_ext::archive_path may be NULL ++ * - retro_game_info_ext::archive_file may be NULL ++ * - retro_game_info_ext::dir is guaranteed to contain a valid path ++ * to the directory in which the content file exists ++ * - retro_game_info_ext::name is guaranteed to contain the ++ * basename of the content file, without extension ++ * - retro_game_info_ext::ext is guaranteed to contain the ++ * extension of the content file in lower case format ++ * - retro_game_info_ext::data and retro_game_info_ext::size ++ * are invalid ++ * ++ * If need_fullpath is false and retro_load_game() is called: ++ * - If retro_game_info_ext::file_in_archive is false: ++ * - retro_game_info_ext::full_path is guaranteed to contain ++ * a valid path to an existent file ++ * - retro_game_info_ext::archive_path may be NULL ++ * - retro_game_info_ext::archive_file may be NULL ++ * - retro_game_info_ext::dir is guaranteed to contain a ++ * valid path to the directory in which the content file exists ++ * - retro_game_info_ext::name is guaranteed to contain the ++ * basename of the content file, without extension ++ * - retro_game_info_ext::ext is guaranteed to contain the ++ * extension of the content file in lower case format ++ * - If retro_game_info_ext::file_in_archive is true: ++ * - retro_game_info_ext::full_path may be NULL ++ * - retro_game_info_ext::archive_path is guaranteed to ++ * contain a valid path to an existent compressed file ++ * inside which the content file is located ++ * - retro_game_info_ext::archive_file is guaranteed to ++ * contain a valid path to an existent content file ++ * inside the compressed file referred to by ++ * retro_game_info_ext::archive_path ++ * e.g. for a compressed file '/path/to/foo.zip' ++ * containing 'bar.sfc' ++ * > retro_game_info_ext::archive_path will be '/path/to/foo.zip' ++ * > retro_game_info_ext::archive_file will be 'bar.sfc' ++ * - retro_game_info_ext::dir is guaranteed to contain a ++ * valid path to the directory in which the compressed file ++ * (containing the content file) exists ++ * - retro_game_info_ext::name is guaranteed to contain ++ * EITHER ++ * 1) the basename of the compressed file (containing ++ * the content file), without extension ++ * OR ++ * 2) the basename of the content file inside the ++ * compressed file, without extension ++ * In either case, a core should consider 'name' to ++ * be the canonical name/ID of the the content file ++ * - retro_game_info_ext::ext is guaranteed to contain the ++ * extension of the content file inside the compressed file, ++ * in lower case format ++ * - retro_game_info_ext::data and retro_game_info_ext::size are ++ * guaranteed to be valid */ ++ bool need_fullpath; ++ ++ /* If need_fullpath is false, specifies whether the content ++ * data buffer available in retro_load_game() is 'persistent' ++ * ++ * If persistent_data is false and retro_load_game() is called: ++ * - retro_game_info::data and retro_game_info::size ++ * are valid only until retro_load_game() returns ++ * - retro_game_info_ext::data and retro_game_info_ext::size ++ * are valid only until retro_load_game() returns ++ * ++ * If persistent_data is true and retro_load_game() is called: ++ * - retro_game_info::data and retro_game_info::size ++ * are valid until retro_deinit() returns ++ * - retro_game_info_ext::data and retro_game_info_ext::size ++ * are valid until retro_deinit() returns */ ++ bool persistent_data; ++}; ++ ++/* Similar to retro_game_info, but provides extended ++ * information about the source content file and ++ * game memory buffer status. ++ * And array of retro_game_info_ext is returned by ++ * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT ++ * NOTE: In the following descriptions, references to ++ * retro_load_game() may be replaced with ++ * retro_load_game_special() */ ++struct retro_game_info_ext ++{ ++ /* - If file_in_archive is false, contains a valid ++ * path to an existent content file (UTF-8 encoded) ++ * - If file_in_archive is true, may be NULL */ ++ const char *full_path; ++ ++ /* - If file_in_archive is false, may be NULL ++ * - If file_in_archive is true, contains a valid path ++ * to an existent compressed file inside which the ++ * content file is located (UTF-8 encoded) */ ++ const char *archive_path; ++ ++ /* - If file_in_archive is false, may be NULL ++ * - If file_in_archive is true, contain a valid path ++ * to an existent content file inside the compressed ++ * file referred to by archive_path (UTF-8 encoded) ++ * e.g. for a compressed file '/path/to/foo.zip' ++ * containing 'bar.sfc' ++ * > archive_path will be '/path/to/foo.zip' ++ * > archive_file will be 'bar.sfc' */ ++ const char *archive_file; ++ ++ /* - If file_in_archive is false, contains a valid path ++ * to the directory in which the content file exists ++ * (UTF-8 encoded) ++ * - If file_in_archive is true, contains a valid path ++ * to the directory in which the compressed file ++ * (containing the content file) exists (UTF-8 encoded) */ ++ const char *dir; ++ ++ /* Contains the canonical name/ID of the content file ++ * (UTF-8 encoded). Intended for use when identifying ++ * 'complementary' content named after the loaded file - ++ * i.e. companion data of a different format (a CD image ++ * required by a ROM), texture packs, internally handled ++ * save files, etc. ++ * - If file_in_archive is false, contains the basename ++ * of the content file, without extension ++ * - If file_in_archive is true, then string is ++ * implementation specific. A frontend may choose to ++ * set a name value of: ++ * EITHER ++ * 1) the basename of the compressed file (containing ++ * the content file), without extension ++ * OR ++ * 2) the basename of the content file inside the ++ * compressed file, without extension ++ * RetroArch sets the 'name' value according to (1). ++ * A frontend that supports routine loading of ++ * content from archives containing multiple unrelated ++ * content files may set the 'name' value according ++ * to (2). */ ++ const char *name; ++ ++ /* - If file_in_archive is false, contains the extension ++ * of the content file in lower case format ++ * - If file_in_archive is true, contains the extension ++ * of the content file inside the compressed file, ++ * in lower case format */ ++ const char *ext; ++ ++ /* String of implementation specific meta-data. */ ++ const char *meta; ++ ++ /* Memory buffer of loaded game content. Will be NULL: ++ * IF ++ * - retro_system_info::need_fullpath is true and ++ * retro_system_content_info_override::need_fullpath ++ * is unset ++ * OR ++ * - retro_system_content_info_override::need_fullpath ++ * is true */ ++ const void *data; ++ ++ /* Size of game content memory buffer, in bytes */ ++ size_t size; ++ ++ /* True if loaded content file is inside a compressed ++ * archive */ ++ bool file_in_archive; ++ ++ /* - If data is NULL, value is unset/ignored ++ * - If data is non-NULL: ++ * - If persistent_data is false, data and size are ++ * valid only until retro_load_game() returns ++ * - If persistent_data is true, data and size are ++ * are valid until retro_deinit() returns */ ++ bool persistent_data; ++}; ++ + struct retro_game_geometry + { + unsigned base_width; /* Nominal video width of game. */ +@@ -2607,6 +3260,47 @@ struct retro_framebuffer + Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ + }; + ++/* Used by a libretro core to override the current ++ * fastforwarding mode of the frontend */ ++struct retro_fastforwarding_override ++{ ++ /* Specifies the runtime speed multiplier that ++ * will be applied when 'fastforward' is true. ++ * For example, a value of 5.0 when running 60 FPS ++ * content will cap the fast-forward rate at 300 FPS. ++ * Note that the target multiplier may not be achieved ++ * if the host hardware has insufficient processing ++ * power. ++ * Setting a value of 0.0 (or greater than 0.0 but ++ * less than 1.0) will result in an uncapped ++ * fast-forward rate (limited only by hardware ++ * capacity). ++ * If the value is negative, it will be ignored ++ * (i.e. the frontend will use a runtime speed ++ * multiplier of its own choosing) */ ++ float ratio; ++ ++ /* If true, fastforwarding mode will be enabled. ++ * If false, fastforwarding mode will be disabled. */ ++ bool fastforward; ++ ++ /* If true, and if supported by the frontend, an ++ * on-screen notification will be displayed while ++ * 'fastforward' is true. ++ * If false, and if supported by the frontend, any ++ * on-screen fast-forward notifications will be ++ * suppressed */ ++ bool notification; ++ ++ /* If true, the core will have sole control over ++ * when fastforwarding mode is enabled/disabled; ++ * the frontend will not be able to change the ++ * state set by 'fastforward' until either ++ * 'inhibit_toggle' is set to false, or the core ++ * is unloaded */ ++ bool inhibit_toggle; ++}; ++ + /* Callbacks */ + + /* Environment callback. Gives implementations a way of performing diff --git a/patches/snes9x2002/1001-audio-frameskip.patch b/patches/snes9x2002/1001-audio-frameskip.patch new file mode 100644 index 0000000..2154500 --- /dev/null +++ b/patches/snes9x2002/1001-audio-frameskip.patch @@ -0,0 +1,247 @@ +diff --git a/libretro/libretro.c b/libretro/libretro.c +index bc64376..b09354a 100644 +--- a/libretro/libretro.c ++++ b/libretro/libretro.c +@@ -96,6 +96,21 @@ bool8 ROMAPUEnabled = 0; + bool overclock_cycles = false; + int one_c, slow_one_c, two_c; + ++static unsigned frameskip_type = 0; ++static unsigned frameskip_threshold = 0; ++static uint16_t frameskip_counter = 0; ++static unsigned frameskip_interval = 0; ++ ++static bool retro_audio_buff_active = false; ++static unsigned retro_audio_buff_occupancy = 0; ++static bool retro_audio_buff_underrun = false; ++/* Maximum number of consecutive frames that ++ * can be skipped */ ++#define FRAMESKIP_MAX 30 ++ ++static unsigned retro_audio_latency = 0; ++static bool update_audio_latency = false; ++ + static memstream_t *s_stream = NULL; + + static int s_open(const char *fname, const char *mode) +@@ -208,6 +223,57 @@ void retro_get_system_info(struct retro_system_info *info) + info->block_extract = false; + } + ++static void retro_audio_buff_status_cb( ++ bool active, unsigned occupancy, bool underrun_likely) ++{ ++ retro_audio_buff_active = active; ++ retro_audio_buff_occupancy = occupancy; ++ retro_audio_buff_underrun = underrun_likely; ++} ++ ++static void retro_set_audio_buff_status_cb(void) ++{ ++ if (frameskip_type > 0) ++ { ++ struct retro_audio_buffer_status_callback buf_status_cb; ++ ++ buf_status_cb.callback = retro_audio_buff_status_cb; ++ if (!environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, ++ &buf_status_cb)) ++ { ++ retro_audio_buff_active = false; ++ retro_audio_buff_occupancy = 0; ++ retro_audio_buff_underrun = false; ++ retro_audio_latency = 0; ++ } ++ else ++ { ++ /* Frameskip is enabled - increase frontend ++ * audio latency to minimise potential ++ * buffer underruns */ ++ uint32_t frame_time_usec = Settings.FrameTime; ++ ++ if (Settings.ForceNTSC) ++ frame_time_usec = Settings.FrameTimeNTSC; ++ if (Settings.ForcePAL) ++ frame_time_usec = Settings.FrameTimePAL; ++ ++ /* Set latency to 6x current frame time... */ ++ retro_audio_latency = (unsigned)(6 * frame_time_usec / 1000); ++ ++ /* ...then round up to nearest multiple of 32 */ ++ retro_audio_latency = (retro_audio_latency + 0x1F) & ~0x1F; ++ } ++ } ++ else ++ { ++ environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL); ++ retro_audio_latency = 0; ++ } ++ ++ update_audio_latency = true; ++} ++ + static int16 audio_buf[0x10000]; + static unsigned avail; + static float samplerate = 32040.5f; +@@ -339,6 +405,9 @@ void retro_init (void) + { + static const struct retro_variable vars[] = + { ++ { "snes9x2002_frameskip", "Frameskip ; disabled|auto|threshold" }, ++ { "snes9x2002_frameskip_threshold", "FS Threshold (%); 30|40|50|60" }, ++ { "snes9x2002_frameskip_interval", "FS Interval; 1|2|3|4|5|6|7|8|9" }, + { "snes9x2002_overclock_cycles", "Overclock (Restart); disabled|compatible|max" }, + { NULL, NULL }, + }; +@@ -383,6 +452,14 @@ void retro_deinit(void) + GFX.SubZBuffer_buffer = NULL; + + libretro_supports_bitmasks = false; ++ frameskip_type = 0; ++ frameskip_threshold = 0; ++ frameskip_counter = 0; ++ retro_audio_buff_active = false; ++ retro_audio_buff_occupancy = 0; ++ retro_audio_buff_underrun = false; ++ retro_audio_latency = 0; ++ update_audio_latency = false; + } + + void retro_reset (void) +@@ -423,9 +500,42 @@ static void report_buttons (void) + } + } + +-static void check_variables(void) ++static void check_variables(bool first_run) + { + struct retro_variable var; ++ bool prev_force_ntsc; ++ bool prev_force_pal; ++ bool prev_frameskip_type; ++ ++ var.key = "snes9x2002_frameskip"; ++ var.value = NULL; ++ ++ prev_frameskip_type = frameskip_type; ++ frameskip_type = 0; ++ ++ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) ++ { ++ if (strcmp(var.value, "auto") == 0) ++ frameskip_type = 1; ++ if (strcmp(var.value, "threshold") == 0) ++ frameskip_type = 2; ++ } ++ ++ var.key = "snes9x2002_frameskip_threshold"; ++ var.value = NULL; ++ ++ frameskip_threshold = 30; ++ ++ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) ++ frameskip_threshold = strtol(var.value, NULL, 10); ++ ++ var.key = "snes9x2002_frameskip_interval"; ++ var.value = NULL; ++ ++ frameskip_interval = 1; ++ ++ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) ++ frameskip_interval = strtol(var.value, NULL, 10); + + var.key = "snes9x2002_overclock_cycles"; + var.value = NULL; +@@ -449,6 +559,13 @@ static void check_variables(void) + else + overclock_cycles = false; + } ++ ++ /* Reinitialise frameskipping, if required */ ++ if (!first_run && ++ ((frameskip_type != prev_frameskip_type) || ++ (Settings.ForceNTSC != prev_force_ntsc) || ++ (Settings.ForcePAL != prev_force_pal))) ++ retro_set_audio_buff_status_cb(); + } + + //#define FRAME_SKIP +@@ -458,7 +575,7 @@ void retro_run (void) + bool updated = false; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) +- check_variables(); ++ check_variables(false); + + #ifdef FRAME_SKIP + IPPU.RenderThisFrame = !IPPU.RenderThisFrame; +@@ -466,6 +583,53 @@ void retro_run (void) + IPPU.RenderThisFrame = TRUE; + #endif + ++ /* Check whether current frame should ++ * be skipped */ ++ if ((frameskip_type > 0) && ++ retro_audio_buff_active && ++ IPPU.RenderThisFrame) ++ { ++ bool skip_frame; ++ ++ switch (frameskip_type) ++ { ++ case 1: /* auto */ ++ skip_frame = retro_audio_buff_underrun; ++ break; ++ case 2: /* threshold */ ++ skip_frame = (retro_audio_buff_occupancy < frameskip_threshold); ++ break; ++ default: ++ skip_frame = false; ++ break; ++ } ++ ++ if (skip_frame) ++ { ++ if(frameskip_counter < frameskip_interval) ++ { ++ IPPU.RenderThisFrame = false; ++ frameskip_counter++; ++ } ++ else ++ frameskip_counter = 0; ++ } ++ else ++ frameskip_counter = 0; ++ } ++ ++ /* If frameskip/timing settings have changed, ++ * update frontend audio latency ++ * > Can do this before or after the frameskip ++ * check, but doing it after means we at least ++ * retain the current frame's audio output */ ++ if (update_audio_latency) ++ { ++ environ_cb(RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY, ++ &retro_audio_latency); ++ update_audio_latency = false; ++ } ++ + poll_cb(); + report_buttons(); + +@@ -559,7 +723,7 @@ bool retro_load_game(const struct retro_game_info *game) + bool8 loaded; + enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565; + +- check_variables(); ++ check_variables(true); + + if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) + return false; +@@ -585,6 +749,7 @@ bool retro_load_game(const struct retro_game_info *game) + + memset(audio_buf, 0, sizeof(audio_buf)); + ++ retro_set_audio_buff_status_cb(); + return true; + } + -- cgit v1.2.3