- Game freezes at a specific gameplay spot (not time-dependent — same spot regardless of idle time)
- CPU stuck at
eip=0x800151ed, IF=0, irq=2 (PCRTC/VBLANK only) pg_intr=0x0— NO PGRAPH interrupt pending, NOP is not involvedpmc_intr=0x1000000— only PCRTC (VBLANK) pendingflip_active=1in watchdog during stall- PFIFO eventually idle (
get=put) - Sound continues playing, app responsive, last frame frozen
- Happens on BOTH OpenGL and Vulkan renderers
- Game targets 30fps and uses real-time clock (not VBLANK count) for timing
- Game does NOT speed up with extra VBLANKs (unlike most other games)
- Works perfectly on desktop xemu at 60Hz
- Works on x1_box Android branch (which runs games too fast / fast-forward)
| Feature | Test | Result |
|---|---|---|
| Adaptive VBLANK deferral | Disabled on Android (if(0)) |
Still freezes |
| Lockless fast dispatch | Disabled on Android | Still freezes |
| PFIFO spin loop | Disabled on Android | Still freezes |
| PFIFO lock batching | Disabled on Android | Still freezes |
| Tier-1 recompilation | Fully disabled (!defined(__ANDROID__)) |
Still freezes |
| NOP early-return | Removed (allow overwrite) | Worse — freezes sooner |
| Flip auto-completion | Removed | Worse — freezes sooner |
| NOP 1ms auto-unstall | Disabled in simple mode | Still freezes |
| NOP delivery assist | Disabled in simple mode | Still freezes |
flip_active flag |
Not set on Android | Still freezes |
| Aggressive IF=1 forcing | Every VBLANK for any irq | Worse — freezes sooner |
| TB cache hints (prewarm) | Disabled on Android | Still freezes |
| TB cache hints (record) | Disabled on Android | Still freezes |
| TB cache hints (lookup_tier) | Disabled on Android | Still freezes |
| Simple VBLANK (pure x1_box) | Timer fires PCRTC only, no safety valves | Still freezes |
| Simple VBLANK + gfx_update | Fire PCRTC from display refresh too | Renders, still freezes |
| Simple VBLANK + safety valves | Flip/NOP assists in simple callback | Still freezes |
-
Removing safety mechanisms makes it worse — NOP early-return, flip auto-completion, and forced IF=1 are all actively helping. Without them the freeze triggers sooner.
-
The game doesn't respond to VBLANK rate changes — extra VBLANKs from gfx_update don't speed it up (real-time timing, not VBLANK counting). This rules out VBLANK timing as the cause.
-
x1_box works because of overall faster execution — no tier-1 overhead, no hint system, simpler PFIFO path. Even with all these disabled individually on master, the freeze persists — suggesting a cumulative effect or something else entirely.
-
Pause/unpause temporarily unfreezes — the display loop's "unsticking GPU" code clears stall flags and kicks PFIFO on resume, which breaks the deadlock. But it re-freezes shortly after.
- VGA
gfx_updatecalled on every display refresh (fires PCRTC interrupt from display loop) - No
flip_activestate variable - No adaptive VBLANK deferral
- No VBLANK timer (uses VGA display update instead)
- No flip auto-completion / NOP assists
- No tier-1 recompilation / hint system
- No PFIFO spin loop / lock batching / lockless dispatch
- No frame timing tracking (last_flip_ns, avg_frame_ns)
- Simpler PGRAPH method dispatch (no fast-path table, no generation counters)
Every major feature was disabled individually without fixing the freeze. The cause is either:
- A combination of small changes whose cumulative effect shifts CPU timing enough to trigger a game-specific bug
- A subtle change in a file we haven't examined (GLSL shaders, translate-all.c non-hint code, system/physmem.c)
- Something in the build configuration (compiler flags, optimization level)
accel/tcg/translator.c— page crossing assert→graceful-return changeaccel/tcg/translate-all.c— tier1_consume_request/has_pending_request still runs (scans empty 64-slot table on every TB gen)system/physmem.c— memory access callback tracking (18 lines)system/main.c— exit status handling (11 lines)hw/xbox/nv2a/debug.h— profiling stats infrastructure (287 lines)hw/xbox/nv2a/pgraph/glsl/psh.c— pixel shader gen changes (473 lines)hw/xbox/nv2a/pgraph/glsl/vsh.c— vertex shader changes (40 lines)hw/xbox/nv2a/pgraph/glsl/shaders.c— shader state hashing (49 lines)hw/xbox/nv2a/pgraph/pgraph.c— register category tables, generation counters, masked method LUT (~1000 lines)
git bisect between x1_box and master to find the exact commit. ~100 commits = ~7 builds to test.
pipeline_cache_entry_post_evictassert atdraw.c:359- Pipeline evicted while in use by active command buffer
- Fix:
pre_evictcallback now checksdraw_time >= command_buffer_start_time
- SIGSEGV in
tb_cache_lookup_tierandtb_cache_record_hint - Stale dedup table indices after qsort reordering
- Fix: Bounds checks (
val <= recorded_count),rebuild_dedup_table()after qsort, 4x hash buckets
- 56000+ promotions with thresh=16, request table permanently full
- Dedup table corruption after rewarm qsort
- Fix: Dedup rebuild, 4x hash buckets, tier1_requests clear on flush, CF_INVALID guarded by slot, "Disabled" option in settings
waiting_for_nopstalls PFIFO, CPU can't acknowledge with IF=0- Mitigation: 1ms PFIFO auto-unstall, VBLANK IF=1 assist, NOP early-return for duplicates
is_flip_stall_complete()returns false (READ_3D == WRITE_3D)- Guest VBLANK handler can't run with IF=0
- Mitigation: VBLANK auto-increments READ_3D, clears flags, kicks PFIFO
- Inline rewarm blocks CPU 100-500ms → NOP deadlock
- Fix: Rewarm disabled on Android (sort + dedup rebuild only)
- Tier-1 threshold picker with "Disabled" option (sets threshold to INT_MAX)
- Simple VBLANK toggle — x1_box-style VBLANK without adaptive deferral (debug/experimental)