Files
psxrecomp/runtime/include/render_pass_plan.h
T
Shokunin eb6b8e49b9 Render passes: publish overlay cycles first; test the store policy; verify devices
- Publish an overlay DLL's pending cycles before a pass freezes the clock;
  otherwise the pass's first store would publish them into the frozen clock
  and the restore would drop them from the live timeline.
- The pass store policy moves into render_pass_plan.c as
  render_pass_mmio_class() and gets a table test (SPU key-on, CD, timers,
  SIO, MDEC and other DMA channels dropped; GP0, GP1 DMA mode/info, GPU and
  OTC DMA, DICR/DPCR, I_STAT/I_MASK allowed).
- PSX_RENDER_PASS_VERIFY also hashes CD, SPU, SIO and MDEC state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 21:02:47 -07:00

70 lines
3.2 KiB
C

#ifndef PSX_RENDER_PASS_PLAN_H
#define PSX_RENDER_PASS_PLAN_H
/* Pure planning and selection math for host-timed render passes
* (render_pass.c, gpu_gl_renderer.c). No runtime state; unit-tested by
* runtime/tests/test_render_pass_plan.c.
*
* Vocabulary. A game frame F is first presented at host tick `frame_start`
* and stays on screen for `frame_length` host ticks (its flip period in guest
* VBlanks times the presenter's source period). Phase p in [0, 1) is the
* position inside that window. Phase 0 is the game's own image of F; a pass
* rendered at phase a shows the game state a of the way from F to the next
* frame. Phases are carried as Q16 (65536 = 1). */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RENDER_PASS_MAX_PHASES 16u
typedef struct RenderPassPlanInput {
double next_deadline; /* the presenter's next output deadline (ticks) */
double target_period; /* ticks per output frame; <= 0 = unknown */
double frame_start; /* predicted first-present tick of the frame */
double frame_length; /* ticks the frame stays on screen */
double pass_cost; /* smoothed host ticks per pass; 0 = unknown */
double budget; /* host ticks the passes may use; < 0 = unlimited */
uint32_t max; /* caller's array capacity */
} RenderPassPlanInput;
/* Fill alpha_q16[] with the ascending phases the presenter will show during
* the frame (the output deadlines that fall strictly inside it, excluding
* ones within 1/64 of phase 0, which the game's own image already covers).
* When the budget cannot pay for all of them, an evenly spread subset is
* returned; *wanted (optional) receives the unshed count. Returns the count
* (0 when nothing is wanted or affordable). */
uint32_t render_pass_plan_phases(const RenderPassPlanInput *in,
uint32_t *alpha_q16, uint32_t *wanted);
/* Pick what to show at phase p (0..1+) from a frame's rendered items.
* phases[0..n) are ascending Q16 phases, phases[0] == 0 being the game's
* image. Sets *lo and *hi (item indices) and *t (blend weight of hi, 0..1):
* inside [phases[i], phases[i+1]] the two neighbours are blended; past the
* last item it is held (nothing newer exists yet). Returns 0 when n == 0. */
int render_pass_select(const uint32_t *phases, uint32_t n, double p,
uint32_t *lo, uint32_t *hi, float *t);
/* Exponential moving average used for the per-pass host cost. */
double render_pass_ema(double current, double sample);
/* Next frame's pass budget from the last frame: the host time the presenter
* spent idle-waiting plus the time passes used, scaled by `share` (0..1) and
* clamped to [0, frame_length]. No history (both zero) -> share of the frame. */
double render_pass_budget(double idle_ticks, double pass_ticks,
double frame_length, double share);
/* Store policy inside a pass (memory.c): -1 = the MMIO store may reach its
* device (GP0; GP1 DMA mode 0x04 / info 0x10; GPU and OTC DMA channels;
* DPCR/DICR; I_STAT/I_MASK -- all restored after the pass), otherwise the
* RENDER_PASS_DROP_* class it is dropped and counted under (render_pass.h). */
int render_pass_mmio_class(uint32_t phys, uint32_t val, uint32_t width);
#ifdef __cplusplus
}
#endif
#endif