Fix New Game fade presentation

This commit is contained in:
gamer147
2026-07-27 12:16:53 -04:00
parent ecf7289c7d
commit 8bc60d89ad
2 changed files with 20 additions and 3 deletions

View File

@@ -2444,7 +2444,12 @@ can start that track normally.
`0xc2` is BGM rather than SFX: `op_0xc2_bgm_fade@0x4204c0` sets run-state `0x200`, arms the service timer, `0xc2` is BGM rather than SFX: `op_0xc2_bgm_fade@0x4204c0` sets run-state `0x200`, arms the service timer,
and calls `bgm_fade_arm@0x464830`. `bgm_fade_tick@0x464960` linearly interpolates current to target percent; and calls `bgm_fade_arm@0x464830`. `bgm_fade_tick@0x464960` linearly interpolates current to target percent;
durations at least 1000 ms take 100 steps, shorter durations take 10, and target zero releases the source. durations at least 1000 ms take 100 steps, shorter durations take 10, and target zero releases the source.
The VM is parked for the requested duration. `0xd9` is adjacent startup control, not audio data: it clears The VM is parked for the requested duration while the native main loop continues rendering. The Godot host
mirrors that ownership split: its VM worker waits on the fade clock only after publishing the completed
pre-fade graphics burst and releasing the script presentation barrier. This is required at
`SC0000@0x7c1`, where the three-second title-BGM fade begins after the New Game scene has already cleared
to black; retaining presentation ownership during the wait incorrectly froze the last menu frame until the
opening CG transition began. `0xd9` is adjacent startup control, not audio data: it clears
run/service bit `0x1000` in the primary and, when active, secondary context and has no VM-visible result. run/service bit `0x1000` in the primary and, when active, secondary context and has no VM-visible result.
Opcode `0x1cf` belongs to the voice/BGM envelope rather than SFX. Handler Opcode `0x1cf` belongs to the voice/BGM envelope rather than SFX. Handler

View File

@@ -1539,8 +1539,20 @@ public sealed class GodotAdvHost : IHost
_main.CallDeferred("FadeBgm", targetPercent, realSeconds); _main.CallDeferred("FadeBgm", targetPercent, realSeconds);
long deadline = _clock.NowMs + ms; long deadline = _clock.NowMs + ms;
IsSleeping = true; IsSleeping = true;
bool scriptSuspended = SuspendScriptForPresentation();
try
{
// Native parks the interpreter in its audio service while the main render loop continues.
// Publish scene changes accumulated before the fade (notably GAMESTART -> SC0000's black
// frame), then leave presentation ownership with the compositor for the timed wait.
RequestSynchronizedPresentation();
while (_clock.NowMs < deadline && !_stopping) _frameSignal.WaitOne(50); while (_clock.NowMs < deadline && !_stopping) _frameSignal.WaitOne(50);
}
finally
{
ResumeScriptAfterPresentation(scriptSuspended);
IsSleeping = false; IsSleeping = false;
}
_timeline?.State("running", new() { ["bgm_fade_complete"] = true }); _timeline?.State("running", new() { ["bgm_fade_complete"] = true });
} }
} }