core_info: let a running core override stale savestate metadata for basic support

Core info files gate savestate functionality
(core_info_current_supports_savestate_level), and they can go stale in
the blocking direction: a core that implements serialization after its
info file declared 'savestate = false' keeps getting 'Core does not
support save states' on every manual save/load attempt, even though the
implementation works. The libretro API has no capability flag to
consult, so the only ground truth available is a nonzero
retro_serialize_size() from the running core itself.

For BASIC support only - user-initiated save/load - fall back to that
ground truth when the metadata claims non-support: if the core is
running and reports a nonzero serializable size, allow the operation.
Higher support levels (rewind, run-ahead, netplay) still require
explicit metadata, since they engage automatic high-frequency
serialization that a bare nonzero size does not prove fast or safe
enough; and the probe only runs in the previously-failing path, so
cores with correct metadata see no behavior change. The existing
core_info_savestate_bypass setting is untouched and still overrides
everything.

Motivating case: boom3 gained full savestate support while its info
file still declares 'savestate = false'; every frontend savestate
attempt was rejected without ever asking the core.
This commit is contained in:
audit authored and libretroadmin committed 2026-07-04 19:47:37 +02:00
1 parent 2715e8a31a
commit 9a20309811
1 file changed
+21
+21
View File
@@ -33,6 +33,8 @@
#include "verbosity.h"
#include "core_info.h"
#include "core.h"
#include "runloop.h"
#include "file_path_special.h"
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
@@ -2890,6 +2892,25 @@ static bool core_info_current_supports_savestate_level(uint32_t min_level)
* is supported */
if (!p_coreinfo->current)
return true;
if (p_coreinfo->current->savestate_support_level >= min_level)
return true;
/* The info file claims this level is unsupported. Info files can go
* stale in the blocking direction: a core that gains serialization
* support keeps being rejected here until its metadata is updated,
* even though the implementation works (and the API itself has no
* capability flag to consult - a nonzero retro_serialize_size() from
* the running core is the only ground truth available).
*
* For BASIC support (user-initiated save/load), let the running core
* override stale metadata: if it reports a nonzero serializable size,
* savestates demonstrably work. Higher support levels (rewind,
* run-ahead, netplay) still require explicit metadata, since those
* engage automatic high-frequency serialization that a bare nonzero
* size does not prove safe or fast enough. */
if (min_level <= CORE_INFO_SAVESTATE_BASIC
&& (runloop_get_flags() & RUNLOOP_FLAG_CORE_RUNNING)
&& core_serialize_size() > 0)
return true;
return p_coreinfo->current->savestate_support_level >= min_level;
}