mirror of
https://github.com/libretro/virtualjaguar-libretro.git
synced 2026-11-07 04:36:00 -10:00
The GPU and DSP idle-loop fast-forward was off whenever blit memoization was enabled (or in verify mode). Only blitMemoRecording needs to gate it: while a blit is being recorded, the JaguarRead family notes every read, and skipped loads would change what the memo records. Recording is set only around BlitMemoLaunch's synchronous engine run (a GPU store to B_CMD can launch one with GPUExec on the stack, but no GPU or DSP instruction executes until it returns), so the check is belt-and-braces. blitMemoMode on its own leaves the read hook off, and the write hook (main-RAM page generations) is never reached by an admitted loop body: the DSP admits no store, and the GPU admits only long stores into GPU local RAM, which GPUWriteLong serves without any memo hook. The skipped iterations leave the memo exactly as interpreting them would. The [perf] suppression warning, the option sublabel's "Inactive" note, the blit_memo option text and the settings guide no longer list blit memoization as an idle-skip suppressor. Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
aaa9b5946c
commit
db90f8e3ac
5 files changed
+20
-25
No files matched your search
@@ -299,10 +299,10 @@ landed afterwards and the option now drives both.
|
||||
|---|---|
|
||||
| **DRAM Timing** | enabled |
|
||||
| **GPU/DSP Pipeline Timing** | enabled |
|
||||
| **Blit Memoization** | enabled or verify |
|
||||
|
||||
It stays active under **RISC (GPU/DSP) Clock Scale** and **M68K Clock Scale** at
|
||||
any value, and under **Blitter Bus Timing**. (Verified against
|
||||
any value, under **Blitter Bus Timing**, and under **Blit Memoization** (which
|
||||
was on the list before v4.0). (Verified against
|
||||
`src/jerry/dsp.c`, `DSPExec()`.) The RISC clock scale used to be on the list
|
||||
above; the skip is exact under any scale now (it measures the cost of a loop
|
||||
iteration in the same scaled currency the budget is handed out in), so an
|
||||
|
||||
+3
-16
@@ -2440,12 +2440,12 @@ static void perf_conflict_append(char *buf, size_t cap, const char *what)
|
||||
}
|
||||
|
||||
/* Which options currently switch the RISC idle-skip off. Mirrors the gate
|
||||
* at the top of DSPExec() (src/jerry/dsp.c) -- see the comment above for what
|
||||
* is deliberately absent. Shared by the log warning below and the option
|
||||
* at the top of DSPExec() (src/jerry/dsp_exec_untimed.h) -- see the comment
|
||||
* above for what is deliberately absent. Blit memoization is absent too
|
||||
* (#952): it no longer switches the skip off. Shared by the log warning below and the option
|
||||
* sublabel (#841), so the two can never name different suppressors. */
|
||||
#define IDLE_SUP_DRAM 1u
|
||||
#define IDLE_SUP_PIPE 2u
|
||||
#define IDLE_SUP_MEMO 4u
|
||||
|
||||
static unsigned idle_skip_suppressor_mask(void)
|
||||
{
|
||||
@@ -2455,8 +2455,6 @@ static unsigned idle_skip_suppressor_mask(void)
|
||||
mask |= IDLE_SUP_DRAM;
|
||||
if (vjs.gpuPipelineTiming)
|
||||
mask |= IDLE_SUP_PIPE;
|
||||
if (blitMemoMode != BLIT_MEMO_OFF || blitMemoRecording)
|
||||
mask |= IDLE_SUP_MEMO;
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -2474,8 +2472,6 @@ static void perf_warn_idle_skip_suppressed(void)
|
||||
perf_conflict_append(who, sizeof(who), "virtualjaguar_dram_timing");
|
||||
if (mask & IDLE_SUP_PIPE)
|
||||
perf_conflict_append(who, sizeof(who), "virtualjaguar_gpu_pipeline_timing");
|
||||
if (mask & IDLE_SUP_MEMO)
|
||||
perf_conflict_append(who, sizeof(who), "virtualjaguar_blit_memo");
|
||||
|
||||
if (who[0] == '\0')
|
||||
return;
|
||||
@@ -2729,15 +2725,6 @@ static void explain_compute(explain_amend_t *out, int *count)
|
||||
explain_option_name(i, name, sizeof(name));
|
||||
perf_conflict_append(who, sizeof(who), name);
|
||||
}
|
||||
if (mask & IDLE_SUP_MEMO)
|
||||
i = explain_find_def("virtualjaguar_blit_memo");
|
||||
else
|
||||
i = -1;
|
||||
if (i >= 0)
|
||||
{
|
||||
explain_option_name(i, name, sizeof(name));
|
||||
perf_conflict_append(who, sizeof(who), name);
|
||||
}
|
||||
if (who[0])
|
||||
{
|
||||
snprintf(note, sizeof(note), "Inactive: suppressed by %s.", who);
|
||||
|
||||
@@ -254,7 +254,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
||||
"virtualjaguar_blit_memo",
|
||||
"Blit Memoization (Per-Title)",
|
||||
NULL,
|
||||
"Skip blits whose inputs are provably unchanged since an identical earlier blit (some titles re-render the same scene every engine cycle while the player is idle). Output is bit-identical by construction. Enabled per title via the enhancement database; not available for CD content. 'Verify' never skips -- it runs every would-be skip and logs any divergence, for validating new titles. Switches off DSP Idle-Loop Fast-Forward while enabled.",
|
||||
"Skip blits whose inputs are provably unchanged since an identical earlier blit (some titles re-render the same scene every engine cycle while the player is idle). Output is bit-identical by construction. Enabled per title via the enhancement database; not available for CD content. 'Verify' never skips -- it runs every would-be skip and logs any divergence, for validating new titles.",
|
||||
NULL,
|
||||
"speed",
|
||||
{
|
||||
|
||||
@@ -54,10 +54,18 @@ static DSP_NOINLINE void DSP_UNTIMED_NAME(int32_t cycles)
|
||||
* per-instruction state the affine extrapolation does not model, so
|
||||
* any of them turns the whole thing off:
|
||||
* - vjs.riscIdleSkip: the user-facing core option itself;
|
||||
* - blitMemoMode / blitMemoRecording: the JaguarRead and JaguarWrite
|
||||
* families note reads and writes for the memo (blit_memo.h:64-65,
|
||||
* src/core/jaguar.c:1139), and skipping loads would change what
|
||||
* the memo records;
|
||||
* - blitMemoRecording: while a blit is being recorded the
|
||||
* JaguarRead family notes every read for the memo, and skipping
|
||||
* loads would change what it records. Recording is set only
|
||||
* around BlitMemoLaunch's synchronous engine run, during which
|
||||
* no GPU or DSP instruction executes, so this is belt-and-braces.
|
||||
* blitMemoMode alone is NOT a gate (#952): outside recording the
|
||||
* read hook is off, and the write hook (main-RAM page
|
||||
* generations) is never reached by an admitted body -- the DSP
|
||||
* admits no store at all, and the GPU admits only GPU-local-RAM
|
||||
* long stores, which GPUWriteLong serves without any memo hook.
|
||||
* The skipped iterations therefore leave the memo exactly as
|
||||
* interpreting them would;
|
||||
* - riscClockScalePct is deliberately NOT a gate (#378 overclock
|
||||
* presets): SCALE_RISC_CYCLES is applied where the budget is handed out (jaguar.c), not inside
|
||||
* DSPExec, so `cycles` here is already in the same currency the
|
||||
@@ -87,7 +95,7 @@ static DSP_NOINLINE void DSP_UNTIMED_NAME(int32_t cycles)
|
||||
* two loads per slice on trace builds and nothing at all on
|
||||
* release builds. */
|
||||
idleSkipActive = vjs.riscIdleSkip
|
||||
&& !blitMemoMode && !blitMemoRecording
|
||||
&& !blitMemoRecording
|
||||
&& !busArbiter.enabled
|
||||
&& !vjs.gpuPipelineTiming
|
||||
&& !(dsp_control & 0x18);
|
||||
|
||||
+1
-1
@@ -2671,7 +2671,7 @@ void GPUExec(int32_t cycles)
|
||||
* GPUChargeBusStall is reached only by a blitter-register access,
|
||||
* which GPU_IDLE_EA_OK (RAM / local SRAM only) never admits. */
|
||||
idleSkipActive = vjs.riscIdleSkip
|
||||
&& !blitMemoMode && !blitMemoRecording
|
||||
&& !blitMemoRecording
|
||||
&& !busArbiter.enabled
|
||||
&& !vjs.gpuPipelineTiming
|
||||
&& !(gpu_control & 0x18);
|
||||
|
||||
Reference in new issue
Block a user