Files
psxrecomp/runtime/include/present_ring.h
T
Matthew Stanley b85f10959b widescreen: pillarbox 2D-only scenes in native-wide; HUD corner re-anchor for tag titles; present ring
2D-only-scene classifier (fixes room/fall/title-card stretch, Tomba):
- Native-wide's 2D-backdrop stretch fires wholesale in scenes whose
  background phase never ends (room interiors, sky-only falls), stretching
  the whole frame. Such scenes now present native 4:3 from the faithful
  canonical buffer (gpu_ws_present_native_43).
- The world signal is DEEP UNTAGGED POLYGON OVERHANG: polys whose raw SX
  extent crosses >=24px past the canonical window, >=4 per frame, sustained
  2+ consecutive frames. Lineage of rejected signals (each defeated by a
  real scene, census-evidenced): shaded-prim presence (title-card letter
  tiles are gouraud), GTE projection volume (task-jingle projects
  world-scale counts; title screen idles at 1680 verts), any-poly overhang
  (card letters slide in from off-screen), shallow overhang (jingle
  sparkles poke <=20px). Outdoor terrain measures 55 deep-overhang
  polys/frame vs 0-1 for every observed 2D scene/effect.
- Scoped to sprite-tag titles: full_2d (MMX6) and gte_game_mode (Ape)
  classification is unchanged.

Native-wide present invariant:
- A game frame that cannot present wide (compositor fallback) pillarboxes
  4:3 instead of stretching the canonical read across the wide window
  (all backends; squash mode still stretches by design).

HUD corner re-anchoring for sprite-tag titles ([widescreen] nw_hud_corners):
- Poly/line prims never shift (they are the world / tagged billboards);
  rect-family prims shift only when UNTAGGED — the proven hud_sprt_squash
  discriminator — so enabling nw_hud_corners is safe without a packet
  arena range.

Observability (always-on, institutional):
- present_ring: per-present classification ring (path, present width,
  game_mode, native_43, wide fallback, tag age, gte_verts, ovh_prims)
  for every backend; TCP "present_ring". Answers "why did this frame
  stretch" after the fact.
- gpu_state ws block gains last_3d_frame, gte_verts, last_world3d_frame,
  ovh_prims, last_ovh_frame; GTE vert counting is now always-on.

Input injection drives the full pad model:
- set_input/press now resolve pad type like real sampling: injected d-pad
  drops a hybrid pad to digital (movement works), optional lx/ly/rx/ry
  stick override (0..255), type via the coherent request channel.
  Previously buttons-only: menus reacted, walking never did.

Savestate honesty:
- savestate_request_save/load return staged/refused; the TCP handler
  reports ok:false instead of silently acking loads it cannot perform
  (LLE host-fiber runs). Torn-restore reliability audit remains open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:23:44 -07:00

49 lines
2.0 KiB
C

#ifndef PSXRECOMP_PRESENT_RING_H
#define PSXRECOMP_PRESENT_RING_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Present-classification ring: one entry per present decision in
* sdl_vblank_present, for EVERY backend (software, GL, Vulkan). Records how
* the frame was classified (FMV/full-2D 4:3 pillarbox, native-wide, or the
* canonical read) and whether a native-wide present fell back to the
* canonical width — the fallback is invisible on screen except as a
* horizontal stretch, so it must be observable in data. Always-on; queried
* via the TCP debug server "present_ring" command. */
typedef enum {
PRES_PATH_BLANK = 0, /* display disabled — blank frame */
PRES_PATH_NATIVE_43 = 1, /* FMV / full-2D frame, 4:3 pillarbox */
PRES_PATH_WIDE = 2, /* native-wide surface (canonical + EXTRA) */
PRES_PATH_CANONICAL = 3, /* canonical read; stretches when the window
is wider than the display aspect */
} PresPath;
typedef struct {
uint32_t frame; /* s_frame_count at present time */
uint16_t disp_w, disp_h;/* GPU display size */
uint16_t present_w; /* width actually presented */
uint16_t nw_extra; /* native-wide growth configured this frame */
uint8_t path; /* PresPath */
uint8_t wide_fellback; /* wide present attempted but surface missing */
uint8_t game_mode; /* ws gameplay-vs-2D classification */
uint8_t native_43; /* gpu_ws_present_native_43() at present time */
int32_t tag_delta; /* frames since newest sprite tag (clamped) */
uint16_t gte_verts; /* RTPS/RTPT verts, last completed frame */
uint16_t ovh_prims; /* overhanging polys, last completed frame (the
2D-only-scene classifier's world signal) */
} PresRingEntry;
uint64_t present_ring_total(void);
int present_ring_get(uint64_t seq, PresRingEntry* out);
#ifdef __cplusplus
}
#endif
#endif /* PSXRECOMP_PRESENT_RING_H */