Add guarded native draw replay, motion interpolation and stable world filtering

This commit is contained in:
Matthew Stanley
2026-10-03 23:35:11 -07:00
parent 030cb00c45
commit d2c8f03e76
66 changed files with 3454 additions and 76 deletions
+79
View File
@@ -2,6 +2,7 @@
#include "cpu_state.h"
#include "nd_intro_ot.h"
#include "pgxp.h"
#include "render_pass_projection.h"
#include <algorithm>
#include <cstdlib>
#include <cstdio>
@@ -12,6 +13,7 @@ extern "C" int gpu_ws_precise_nclip_enabled(void);
/* overlay_loader.c: nonzero while an overlay shadow diff (interpreter record
* plus native replay of one candidate) is running. */
extern "C" int psx_overlay_shadow_diff_active(void);
extern "C" { int (*g_psx_projection_command)(CPUState*, uint32_t) = nullptr; }
namespace PSXRecomp {
namespace GTE {
@@ -372,6 +374,76 @@ extern "C" int gte_geometry_correction_lookup(uint32_t packed,
return 1;
}
/* Render-pass checkpoint for the gte.cpp side of precision tracking: the
* position cache entries a pass writes are journaled and put back, and the
* speculative bracket depth is restored (a watchdog abort can leave one open).
* The PGXP shadows roll back through pgxp_checkpoint_*. */
struct GeomJournalEntry { GeomVertex *slot; GeomVertex old; };
static uint32_t s_gck_depth = 0;
static GeomJournalEntry *s_gck_log = nullptr;
static size_t s_gck_n = 0, s_gck_cap = 0;
static int s_gck_lossy = 0;
static uint32_t s_gck_generation = 0;
static GeomVertex *s_gck_cache = nullptr;
static uint32_t s_gck_spec_depth = 0;
static int s_gck_spec_invalidated = 0;
static uint8_t *s_gck_bits = nullptr; /* one bit per cache slot */
static inline void geom_ck_note(GeomVertex *slot) {
if (s_gck_depth == 0) return;
if (s_geom_cache != s_gck_cache || !s_gck_bits) { s_gck_lossy = 1; return; }
size_t i = (size_t)(slot - s_geom_cache);
uint8_t bit = (uint8_t)(1u << (i & 7u));
if (s_gck_bits[i >> 3] & bit) return; /* journaled this pass */
if (s_gck_n == s_gck_cap) {
size_t cap = s_gck_cap ? s_gck_cap * 2 : 16384;
GeomJournalEntry *p = (GeomJournalEntry *)std::realloc(
s_gck_log, cap * sizeof *p);
if (!p) { s_gck_lossy = 1; return; }
s_gck_log = p;
s_gck_cap = cap;
}
s_gck_bits[i >> 3] |= bit;
s_gck_log[s_gck_n].slot = slot;
s_gck_log[s_gck_n].old = *slot;
s_gck_n++;
}
extern "C" void gte_precision_checkpoint_begin(void) {
pgxp_checkpoint_begin();
if (s_gck_depth++ != 0) return;
if (s_geom_cache && !s_gck_bits)
s_gck_bits = (uint8_t *)std::calloc(GEOM_CACHE_SIZE / 8u, 1);
s_gck_n = 0;
s_gck_generation = s_geom_generation;
s_gck_cache = s_geom_cache;
s_gck_spec_depth = s_speculative_depth;
s_gck_spec_invalidated = s_speculative_timeline_invalidated;
}
extern "C" void gte_precision_checkpoint_rollback(void) {
if (s_gck_depth != 0 && --s_gck_depth == 0) {
for (size_t i = s_gck_n; i-- > 0;) {
GeomVertex *slot = s_gck_log[i].slot;
*slot = s_gck_log[i].old;
size_t k = (size_t)(slot - s_gck_cache);
s_gck_bits[k >> 3] &= (uint8_t)~(1u << (k & 7u));
}
s_gck_n = 0;
s_speculative_depth = s_gck_spec_depth;
s_speculative_timeline_invalidated = s_gck_spec_invalidated;
if (s_gck_lossy || s_geom_cache != s_gck_cache ||
s_geom_generation < s_gck_generation) {
s_gck_lossy = 0;
gte_geom_generation_advance(); /* fail closed */
} else {
s_geom_generation = s_gck_generation;
}
}
pgxp_checkpoint_rollback();
}
static inline void geom_note(uint32_t packed, int64_t x16, int64_t y16) {
if (s_speculative_depth != 0 || s_gte_replay_sandbox || !s_geom_enabled ||
!s_geom_cache) return;
@@ -384,6 +456,7 @@ static inline void geom_note(uint32_t packed, int64_t x16, int64_t y16) {
int64_t slot = geom_slot(packed);
if (slot < 0) return;
GeomVertex &entry = s_geom_cache[slot];
geom_ck_note(&entry);
if (entry.generation == s_geom_generation) {
/* Already occupied this generation: only flag ambiguity if the stored
* sub-pixel position actually DIFFERS — re-projecting the same vertex
@@ -1897,6 +1970,11 @@ static void gte_run_command(PSXRecomp::GTE::GTEState* gte, uint32_t cmd) {
extern "C" void gte_execute(CPUState* cpu, uint32_t cmd) {
using namespace PSXRecomp::GTE;
uint32_t original_transform[8];
const bool observe_projection = g_psx_projection_command &&
((cmd & 63) == 1 || (cmd & 63) == 0x30);
if (observe_projection) std::memcpy(original_transform, cpu->gte_ctrl, sizeof original_transform);
const bool intermediate = observe_projection && g_psx_projection_command(cpu, cmd);
#ifndef PSX_NO_DEBUG_TOOLS
if (!s_gte_replay_sandbox) s_gte_exec_count++;
s_gte_caller_ra = cpu->gpr[31]; /* dome-locate probe: game fn that issued this projection */
@@ -1930,6 +2008,7 @@ extern "C" void gte_execute(CPUState* cpu, uint32_t cmd) {
#endif
gte_export_cpu_state(cpu, &gte);
if (intermediate) std::memcpy(cpu->gte_ctrl, original_transform, sizeof original_transform);
#ifndef PSX_NO_DEBUG_TOOLS
/* ND digit-rain: NdIntroSiblingFaceLoop (jal 0x80069CC4; $ra stays 69C3C..