mirror of
https://github.com/libretro/virtualjaguar-libretro.git
synced 2026-11-07 04:36:00 -10:00
fix(libretro): latch the BIOS and PAL options at content load (#858)
check_variables() re-runs whenever ANY core option changes, and it re-applied 'BIOS (Cartridges)' and 'PAL' every time. retro_load_game() resolves vjs.useJaguarBIOS after its option read (a GPU-only/jagcrypt cart forces the boot ROM on; CD boot mode sets it from bootConfig.showBootROM), and the DSP reads that flag at runtime. So on such a cart, touching an unrelated option silently turned the boot-ROM flag back off mid-session. PAL rewrote vjs.hardwareTypeNTSC live, so the clock macros switched standards while the AV timing (negotiated only at load) did not. Both are now applied only before content is loaded, the same way internal_resolution is. After load a change only logs a one-shot "takes effect on restart" notice. 'BIOS (Cartridges)' gains the "Restart required" sublabel marker, and moves from the live list to the load-only list in test_option_explain case 8; settings guide section 7 lists it. Test: test_cart_needs_bios gains a mid-session arm. It loads a GPU-only cart with bios=HLE and pal=disabled, changes an unrelated option, then PAL itself, and checks that useJaguarBIOS stays 1 and the standard stays NTSC. develop fails 3 of its 4 checks (useJaguarBIOS=0 after the unrelated change, NTSC flipped); with the fix all pass. Closes #858 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
5756a3e7e8
commit
da241c9406
5 files changed
+129
-12
No files matched your search
@@ -553,6 +553,7 @@ option) includes **Restart required: applied when content is loaded.**
|
||||
|---|---|
|
||||
| `internal_resolution` | Internal Resolution |
|
||||
| `pal` | PAL |
|
||||
| `bios` | BIOS (Cartridges) — HLE or the real boot ROM |
|
||||
| `bios_type` | Cart BIOS Type — *which* boot ROM (Series K / Model M / Custom) |
|
||||
| `cd_bios_type` | CD BIOS Type |
|
||||
| `cd_boot_mode` | CD Boot Mode |
|
||||
|
||||
+43
-8
@@ -143,6 +143,12 @@ static int video_buffer_alloc_pixels = VIDEO_BUFFER_PIXELS;
|
||||
/* One-shot latch for the "restart required" notice when the
|
||||
* internal-resolution option changes mid-game. */
|
||||
static int hires_restart_notice_logged = 0;
|
||||
/* Load-time latches for the boot ROM and PAL options (#858): the option
|
||||
* value seen at load, and a one-shot "takes effect on restart" notice. */
|
||||
static bool bios_option_at_load = false;
|
||||
static bool ntsc_option_at_load = true;
|
||||
static int bios_restart_notice_logged = 0;
|
||||
static int pal_restart_notice_logged = 0;
|
||||
/* Same one-shot latch for the enhancement-hooks gate (issue #370). Hooks
|
||||
* are applied once at content load; toggling mid-session cannot un-patch
|
||||
* (reverting would need a saved original the design deliberately does not
|
||||
@@ -3788,15 +3794,33 @@ static void check_variables(void)
|
||||
voicechat_close_mic();
|
||||
}
|
||||
|
||||
/* Boot ROM and video standard are latched at content load (#858).
|
||||
* retro_load_game() resolves vjs.useJaguarBIOS after this read (GPU-only
|
||||
* cart autodetect, CD boot mode -> bootConfig.showBootROM), and the DSP
|
||||
* reads it at runtime; PAL feeds the clock macros, but AV timing is only
|
||||
* negotiated at load. Re-applying either on a later option change (any
|
||||
* option change re-runs this function) would undo the resolution or
|
||||
* half-apply the standard, so after load only log the restart notice. */
|
||||
var.key = "virtualjaguar_bios";
|
||||
var.value = NULL;
|
||||
|
||||
if (get_variable_pertitle(&var) && var.value)
|
||||
{
|
||||
if (strcmp(var.value, "enabled") == 0)
|
||||
vjs.useJaguarBIOS = true;
|
||||
else
|
||||
vjs.useJaguarBIOS = false;
|
||||
bool bios_want = (strcmp(var.value, "enabled") == 0);
|
||||
if (!content_loaded)
|
||||
{
|
||||
vjs.useJaguarBIOS = bios_want;
|
||||
bios_option_at_load = bios_want;
|
||||
bios_restart_notice_logged = 0;
|
||||
}
|
||||
else if (bios_want == bios_option_at_load)
|
||||
bios_restart_notice_logged = 0;
|
||||
else if (!bios_restart_notice_logged)
|
||||
{
|
||||
LOG_INF("[BIOS] boot ROM option change to %s takes effect on restart\n",
|
||||
var.value);
|
||||
bios_restart_notice_logged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var.key = "virtualjaguar_bios_type";
|
||||
@@ -3817,10 +3841,21 @@ static void check_variables(void)
|
||||
|
||||
if (get_variable_pertitle(&var) && var.value)
|
||||
{
|
||||
if (strcmp(var.value, "enabled") == 0)
|
||||
vjs.hardwareTypeNTSC = false;
|
||||
else
|
||||
vjs.hardwareTypeNTSC = true;
|
||||
bool ntsc_want = (strcmp(var.value, "enabled") != 0);
|
||||
if (!content_loaded)
|
||||
{
|
||||
vjs.hardwareTypeNTSC = ntsc_want;
|
||||
ntsc_option_at_load = ntsc_want;
|
||||
pal_restart_notice_logged = 0;
|
||||
}
|
||||
else if (ntsc_want == ntsc_option_at_load)
|
||||
pal_restart_notice_logged = 0;
|
||||
else if (!pal_restart_notice_logged)
|
||||
{
|
||||
LOG_INF("[VIDEO] PAL option change to %s takes effect on restart\n",
|
||||
var.value);
|
||||
pal_restart_notice_logged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var.key = "virtualjaguar_memory_track";
|
||||
|
||||
@@ -588,7 +588,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
||||
"virtualjaguar_bios",
|
||||
"BIOS (Cartridges)",
|
||||
NULL,
|
||||
"Which BIOS a CARTRIDGE boots with. 'HLE' has the core emulate the BIOS setup and services itself: most commercial titles boot faster and the boot animation is skipped. 'Real' runs the actual Jaguar boot ROM, which some titles require. Both boot ROM images are built into the core, so neither setting needs a file. GPU-only/jagcrypt carts (BootIntro demos) turn the real boot ROM on even when this is set to HLE -- they contain no 68K program for HLE to start. Ignored for CD content: 'CD Boot Mode' decides there.",
|
||||
"Restart required: applied when content is loaded. Which BIOS a CARTRIDGE boots with. 'HLE' has the core emulate the BIOS setup and services itself: most commercial titles boot faster and the boot animation is skipped. 'Real' runs the actual Jaguar boot ROM, which some titles require. Both boot ROM images are built into the core, so neither setting needs a file. GPU-only/jagcrypt carts (BootIntro demos) turn the real boot ROM on even when this is set to HLE -- they contain no 68K program for HLE to start. Ignored for CD content: 'CD Boot Mode' decides there.",
|
||||
NULL,
|
||||
"bios_boot",
|
||||
{
|
||||
|
||||
@@ -316,6 +316,84 @@ static int run_autodetect_arm(int argc, char **argv, const char *rom_path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #858: once content is loaded, changing ANY option re-runs
|
||||
* check_variables(). It must not re-apply 'BIOS (Cartridges)' over the
|
||||
* load-time resolution (a GPU-only cart forces the boot ROM on), nor flip
|
||||
* PAL mid-session. Load the GPU-only cart with bios=HLE and pal=disabled,
|
||||
* change an unrelated option, then also flip pal itself, and check both
|
||||
* flags never move. */
|
||||
static int run_midsession_latch_arm(int argc, char **argv, const char *rom_path)
|
||||
{
|
||||
harness_config cfg = HARNESS_CONFIG_DEFAULT;
|
||||
struct vjs_prefix *vjs;
|
||||
unsigned scale_idx, pal_idx, i;
|
||||
int ok = 1;
|
||||
|
||||
if (!harness_init_from_args(&cfg, argc, argv))
|
||||
return 1;
|
||||
cfg.use_bios = 0;
|
||||
cfg.rom_path = rom_path;
|
||||
cfg.frames = 1;
|
||||
if (cfg.num_options + 3 > HARNESS_MAX_OPTIONS)
|
||||
{
|
||||
fprintf(stderr, "FAIL: midsession: option table full\n");
|
||||
return 1;
|
||||
}
|
||||
cfg.options[cfg.num_options].key = "virtualjaguar_bios";
|
||||
cfg.options[cfg.num_options].value = "disabled";
|
||||
cfg.num_options++;
|
||||
pal_idx = cfg.num_options;
|
||||
cfg.options[cfg.num_options].key = "virtualjaguar_pal";
|
||||
cfg.options[cfg.num_options].value = "disabled";
|
||||
cfg.num_options++;
|
||||
scale_idx = cfg.num_options;
|
||||
cfg.options[cfg.num_options].key = "virtualjaguar_risc_clock_scale";
|
||||
cfg.options[cfg.num_options].value = "1x";
|
||||
cfg.num_options++;
|
||||
|
||||
if (!harness_load_rom(&cfg))
|
||||
{
|
||||
fprintf(stderr, "FAIL: midsession: load_rom\n");
|
||||
harness_shutdown(&cfg);
|
||||
return 1;
|
||||
}
|
||||
vjs = (struct vjs_prefix *)harness_dlsym(&cfg, "vjs");
|
||||
if (!vjs)
|
||||
{
|
||||
fprintf(stderr, "FAIL: midsession: vjs not exported\n");
|
||||
harness_shutdown(&cfg);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
harness_step(&cfg);
|
||||
ok &= check_boot_flag(&cfg, 1, "midsession_loaded_gpu_only_cart");
|
||||
|
||||
/* An unrelated option change re-runs check_variables(). */
|
||||
cfg.options[scale_idx].value = "2x";
|
||||
harness_notify_variable_update();
|
||||
for (i = 0; i < 3; i++)
|
||||
harness_step(&cfg);
|
||||
ok &= check_boot_flag(&cfg, 1, "midsession_unrelated_change_keeps_bios");
|
||||
|
||||
/* PAL itself flipped mid-session: the standard stays NTSC until restart. */
|
||||
cfg.options[pal_idx].value = "enabled";
|
||||
harness_notify_variable_update();
|
||||
for (i = 0; i < 3; i++)
|
||||
harness_step(&cfg);
|
||||
if (!vjs->hardwareTypeNTSC)
|
||||
{
|
||||
fprintf(stderr, "FAIL: midsession_pal_latched: hardwareTypeNTSC flipped "
|
||||
"mid-session\n");
|
||||
ok = 0;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "PASS: midsession_pal_latched (still NTSC)\n");
|
||||
ok &= check_boot_flag(&cfg, 1, "midsession_pal_change_keeps_bios");
|
||||
|
||||
harness_shutdown(&cfg);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
static const char *default_core_path(void)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
@@ -384,6 +462,9 @@ int main(int argc, char **argv)
|
||||
if (run_autodetect_arm(argc, argv, ff_path, 1,
|
||||
"autodetect_ff_pad"))
|
||||
fail++;
|
||||
fprintf(stderr, "=== mid-session option latch (#858) ===\n");
|
||||
if (run_midsession_latch_arm(argc, argv, ff_path))
|
||||
fail++;
|
||||
remove(ff_path);
|
||||
|
||||
if (!build_rayman_demo_shape(&buf, &size) ||
|
||||
|
||||
@@ -124,10 +124,11 @@ static void run_frames(harness_config *cfg, unsigned n)
|
||||
}
|
||||
|
||||
/* The options read ONLY at content load (verified one by one against where
|
||||
* libretro.c consumes them -- see the #850 commit). `bios` is deliberately
|
||||
* absent: check_variables() rewrites vjs.useJaguarBIOS live. */
|
||||
* libretro.c consumes them -- see the #850 commit; `bios` joined in #858
|
||||
* once check_variables() stopped rewriting vjs.useJaguarBIOS live). */
|
||||
static const char * const restart_keys[] = {
|
||||
"virtualjaguar_internal_resolution",
|
||||
"virtualjaguar_bios",
|
||||
"virtualjaguar_enhancement_hooks",
|
||||
"virtualjaguar_pal",
|
||||
"virtualjaguar_bios_type",
|
||||
@@ -160,7 +161,6 @@ static const char * const live_keys[] = {
|
||||
"virtualjaguar_texture_dump",
|
||||
"virtualjaguar_texture_replace",
|
||||
"virtualjaguar_jgd_sd",
|
||||
"virtualjaguar_bios",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user