mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
6f37a0edee
(cherry picked from commit b0f7b2be8e)
751 lines
42 KiB
C
751 lines
42 KiB
C
/* gpu.h — PS1 GPU hardware simulation (Phase 3).
|
|
*
|
|
* Implements GPUSTAT, GP0, GP1, and 1024x512 16-bit VRAM.
|
|
* No rendering to screen — just correct hardware state transitions.
|
|
*/
|
|
|
|
#ifndef PSXRECOMP_GPU_H
|
|
#define PSXRECOMP_GPU_H
|
|
|
|
#include <stdint.h>
|
|
|
|
typedef struct CPUState CPUState;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
void gpu_init(void);
|
|
uint32_t gpu_read_gpustat(void); /* 0x1F801814 read */
|
|
uint32_t gpu_read_gpuread(void); /* 0x1F801810 read */
|
|
void gpu_write_gp0(uint32_t val); /* 0x1F801810 write */
|
|
void gpu_write_gp1(uint32_t val); /* 0x1F801814 write */
|
|
void gpu_set_gp0_source(uint32_t addr); /* diagnostic source for next GP0 word */
|
|
/* Linked-list provenance for the next GP0 words. `word_count == 0` identifies
|
|
* an ordering-table link node; packet nodes retain the most recently visited
|
|
* OT rank. This lets diagnostics distinguish front-layer UI packets from
|
|
* depth-sorted world packets without guessing from primitive shape. */
|
|
void gpu_set_gp0_linked_list_node(uint32_t addr, uint32_t word_count);
|
|
void gpu_vblank_tick(void); /* Toggle LCF, called at each simulated vblank */
|
|
/* Video standard before the first GP1(08h) (disc region: 1 = PAL). Applies
|
|
* now and on every later gpu_init(); GP1(00h) still resets to NTSC. */
|
|
void gpu_set_power_on_video_mode(int pal);
|
|
|
|
/* Display presentation accessors (Phase 3). */
|
|
const uint16_t* gpu_get_vram(void); /* Pointer to 1024x512 16-bit VRAM */
|
|
|
|
typedef struct {
|
|
uint32_t display_x, display_y; /* VRAM start of display area (GP1(05h)) */
|
|
uint32_t width, height; /* Derived from display mode + ranges */
|
|
uint32_t screen_height; /* PAL/NTSC active canvas for depth24 */
|
|
uint32_t screen_origin_y; /* Visible source origin in that canvas */
|
|
uint32_t screen_source_skip_y; /* VRAM rows clipped above active video */
|
|
int32_t screen_offset_y; /* GP1(07h) position relative to TV centre */
|
|
int depth24; /* GP1(08h) display depth flag: RGB888 scanout */
|
|
int disabled; /* GP1(03h) display disable flag */
|
|
} GpuDisplayInfo;
|
|
|
|
void gpu_get_display_info(GpuDisplayInfo* out);
|
|
/* Render-pass GPU register checkpoint (render_pass.c). One at a time. */
|
|
int gpu_pass_checkpoint_save(void);
|
|
void gpu_pass_checkpoint_restore(void);
|
|
uint64_t gpu_pass_state_hash(void);
|
|
|
|
/* Perspective-correct UV arming rate, per condition. armed/attempts is the
|
|
* real perspective coverage: attempts counts only textured triangles, so it is
|
|
* the denominator that gp0_draw (which includes untextured primitives that are
|
|
* correctly never armed) cannot provide. Diagnostic; any pointer may be NULL. */
|
|
void gpu_texture_correction_stats(uint64_t *attempts, uint64_t *armed,
|
|
uint64_t *no_correction,
|
|
uint64_t *no_source, uint64_t *no_depth);
|
|
/* GP1(08h) bit4 — 24-bit display. Renderers skip FBO upload queues while set:
|
|
* packed RGB888 lives in the CPU mirror; treating A0 rects as 1555 FBO uploads
|
|
* both wastes bandwidth and force-flushes when UP_RECTS_MAX is hit (MotK FMV). */
|
|
int gpu_display_is_depth24(void);
|
|
void gpu_display_pixel_rgb(const GpuDisplayInfo* di, uint32_t x, uint32_t y,
|
|
uint8_t* r, uint8_t* g, uint8_t* b);
|
|
/* Same decode against any 1024x512 VRAM image (e.g. a display-ring snapshot)
|
|
* instead of live VRAM: 15-bit or depth24 per `di`. */
|
|
void gpu_display_pixel_rgb_in(const uint16_t* image, const GpuDisplayInfo* di,
|
|
uint32_t x, uint32_t y,
|
|
uint8_t* r, uint8_t* g, uint8_t* b);
|
|
uint32_t gpu_display_pixel_argb(const GpuDisplayInfo* di, uint32_t x, uint32_t y);
|
|
/* Batch equivalent of calling gpu_display_pixel_argb(di, x, y) for x in
|
|
* [0, count) on a depth24 (FMV) scanline — same output, far less per-pixel
|
|
* overhead. `out` must hold at least `count` uint32_t ARGB entries. */
|
|
void gpu_depth24_present_row(const GpuDisplayInfo* di, uint32_t y, uint32_t* out,
|
|
uint32_t count);
|
|
/* Stage a depth24 frame into a w x di->screen_height ARGB canvas and
|
|
* black-fill trailing columns no upload covered (see gpu.c). Returns the
|
|
* source rows staged. */
|
|
uint32_t gpu_depth24_stage_scanout(const GpuDisplayInfo* di, uint32_t* buf,
|
|
uint32_t w, uint32_t margin);
|
|
/* Depth24: RGB columns covered by CPU→VRAM uploads since the last reset.
|
|
* Returns 0 when no uploads yet, crtc_w when coverage is full/unknown-beyond,
|
|
* else the covered RGB width. Present black-fills [limit, crtc_w) without
|
|
* shrinking the CRTC-derived draw width (avoids a flickering black pillar). */
|
|
uint32_t gpu_depth24_rgb_limit(uint32_t display_x, uint32_t crtc_w);
|
|
void gpu_depth24_upload_span_reset(void);
|
|
/* MotK intro cuts retarget GP1(07h): the guest-state hold counts down at
|
|
* guest VBlank (gpu_vblank_tick). Returns non-zero while the latest guest
|
|
* VBlank was held (read-only; guest state in the GPU snap): presents should
|
|
* skip Swap (keep the prior frame) so stale trailing
|
|
* VRAM never flashes. */
|
|
int gpu_depth24_present_hold_tick(void);
|
|
/* After savestate restore: clear ephemeral hold so the restored depth24
|
|
* frame can present immediately (span/prev_h come from the GPU snap). */
|
|
void gpu_depth24_on_savestate_loaded(void);
|
|
/* GP1(06h)/GP1(07h)/GP1(08h) fields for debug (gpu_state). */
|
|
void gpu_get_crtc_debug(uint32_t *x1, uint32_t *x2, uint32_t *y1, uint32_t *y2,
|
|
uint32_t *hres1_out, uint32_t *hres2_out);
|
|
uint64_t gpu_get_gp0_count(void); /* Total GP0 writes since init */
|
|
void gpu_get_gp0_stats(uint64_t* nop, uint64_t* fill, uint64_t* draw, uint64_t* env, uint64_t* copy);
|
|
/* Fixed command words; -1 denotes a terminated polyline, 0 an unknown opcode.
|
|
* Transfer payloads follow the returned header length. */
|
|
int gpu_gp0_command_word_count(uint8_t opcode);
|
|
|
|
typedef struct {
|
|
uint32_t left, top, right, bottom;
|
|
int32_t offset_x, offset_y;
|
|
} GpuDrawArea;
|
|
void gpu_get_draw_area(GpuDrawArea* out);
|
|
/* Non-zero when the frame that just reached vblank used two side-by-side draw
|
|
* areas. Presentation-only helpers use this to expand a local split-screen
|
|
* viewport without changing the underlying framebuffer or netplay hashes. */
|
|
int gpu_last_frame_vertical_split_screen(void);
|
|
int32_t psx_ws_local_viewport_width(int32_t vanilla);
|
|
void gpu_ws_set_local_viewport_width_sites(const uint32_t *sites, int count);
|
|
/* The title's local viewport uses the native-wide per-camera renderer. */
|
|
void gpu_ws_set_local_viewport_native_wide(int enabled);
|
|
int psx_ws_is_local_viewport_width_site(uint32_t pc);
|
|
void gpu_vertical_split_debug(int *active, int *left_age, int *right_age);
|
|
uint16_t gpu_vram_peek(int x, int y);
|
|
|
|
/* Shaded quad vertex capture (Phase 4.5 debug). */
|
|
typedef struct {
|
|
int32_t vx[4], vy[4];
|
|
uint32_t color[4];
|
|
} GpuSqCapEntry;
|
|
void gpu_arm_shaded_quad_capture(void);
|
|
int gpu_get_shaded_quad_capture(const GpuSqCapEntry** out);
|
|
|
|
/* Per-frame GP0 command ring (always-on in debug-tool builds).
|
|
* Each entry records up to GPU_GP0_RING_MAX_WORDS command words, including
|
|
* the header; longer commands are truncated.
|
|
* Stamped with the s_frame_count value at issue time so a debug
|
|
* client can pull all commands for any frame in the ring window.
|
|
* PSX_NO_DEBUG_TOOLS builds report zero total/capacity and empty dumps/spans. */
|
|
#define GPU_GP0_RING_MAX_WORDS 12
|
|
typedef struct {
|
|
uint32_t frame;
|
|
uint32_t seq;
|
|
uint32_t src_addr; /* RAM/MMIO source address of command header, if known */
|
|
uint32_t pc; /* g_debug_last_store_pc when command completes */
|
|
uint32_t func; /* g_debug_current_func_addr at issue (executing guest fn) */
|
|
uint32_t ra; /* guest $ra at issue: direct caller of the leaf GP0 helper */
|
|
uint8_t opcode;
|
|
uint8_t n_words; /* total command length; >MAX means truncated */
|
|
uint16_t ot_rank; /* linked-list OT rank, 0xFFFF outside/unknown */
|
|
uint32_t cmd[GPU_GP0_RING_MAX_WORDS];
|
|
/* Builder attribution (populated only for VRAM->VRAM copies, op 0x80):
|
|
* bounded guest-stack unwind of validated return addresses, innermost
|
|
* first. Lets a caller skip the libgpu funnel band and name the game-level
|
|
* routine that assembled the copy. Zero for non-copy commands. */
|
|
uint32_t bld[6];
|
|
uint32_t csp; /* raw guest $sp at copy time (diagnostic) */
|
|
} GpuGp0RingEntry;
|
|
|
|
uint64_t gpu_gp0_ring_total(void);
|
|
uint32_t gpu_gp0_ring_capacity(void);
|
|
uint32_t gpu_gp0_ring_max_words(void);
|
|
int gpu_gp0_ring_dump_frame(uint32_t frame, GpuGp0RingEntry *out, int max_out);
|
|
void gpu_gp0_ring_frame_span(uint32_t *out_oldest, uint32_t *out_newest);
|
|
|
|
/* Vblank presentation callback — called from gpu_vblank_tick().
|
|
* Under netplay the callback is deferred to gpu_vblank_flush_present() at
|
|
* BB / IRQ-check edges so finish_frame digests are not sampled mid-block.
|
|
* Flush also holds while sio_hold_present_for_card() so native save/load
|
|
* busy-waits are not interrupted by MotK-style BB-edge commit. */
|
|
typedef void (*gpu_vblank_cb)(void);
|
|
void gpu_set_vblank_callback(gpu_vblank_cb cb);
|
|
void gpu_vblank_flush_present(void);
|
|
void gpu_vblank_clear_deferred_present(void);
|
|
/* Queue one deferred present (netplay RB resume when I_STAT already has
|
|
* VBlank — snap resync cleared the pending callback). */
|
|
void gpu_vblank_arm_deferred_present(void);
|
|
/* 1 while a netplay deferred present is armed (MotK CD54 VBlank hold). */
|
|
int gpu_vblank_present_pending(void);
|
|
/* Clear flush_present reentrancy guard before longjmp (flush_resume). */
|
|
void gpu_vblank_release_present_flush_guard(void);
|
|
|
|
/* Present-time screen-colour model (see color_lut.h ScreenKind: 0=raw,
|
|
* 1=crt, 2=composite, 3=trinitron). Config/launcher-driven; the PSX_SCREEN
|
|
* env var, if set, overrides this. Default 0 (raw) is byte-identical. */
|
|
void gpu_set_screen_kind(int kind);
|
|
|
|
/* Widescreen proportion correction (active only when aspect != 4:3 and the
|
|
* game's [widescreen] block opts in — see config_loader.h). Tagged
|
|
* character/billboard prims are re-squashed around their projected anchor;
|
|
* untagged SPRT prims (screen-space HUD/menus) around the display centre.
|
|
* psx_ws_sprite_tag is the per-prim callback the recompiler emits at the
|
|
* entry of each [widescreen] sprite_tag_funcs function. */
|
|
/* mode: 0 = off (4:3 identity), 1 = squash (legacy hack), 2 = native-wide
|
|
* (render the wider FOV into a wider frame, present 1:1; GTE not squashed). */
|
|
void gpu_ws_configure(int aspect_num, int aspect_den,
|
|
uint32_t sprite_anchor_addr, int hud_sprt_squash, int mode);
|
|
/* [widescreen] full_2d: opt a pure-2D sprite game into the widescreen present
|
|
* path (treat every in-game frame as gameplay, since it never tags 3D prims). */
|
|
void gpu_ws_set_full_2d(int on);
|
|
/* Signed 16-bit camera/min/max; active is a nonzero byte. Requires bg2d hooks.
|
|
* Zero addresses disable the feature. No guest memory is written. */
|
|
void gpu_ws_set_view_anchor(uint32_t camera, uint32_t min, uint32_t max, uint32_t active);
|
|
/* Optional authored scene bounds when native camera locks do not delimit
|
|
* visible geometry. Set before layer setup; disable when leaving the scene.
|
|
* Changes presentation only, and has no effect without view anchoring. */
|
|
void gpu_ws_set_view_bounds_override(int enabled, int minimum, int maximum);
|
|
/* Bracket each bg2d packet producer, with its guest packet pointer. The
|
|
* independent-layer mask identifies parallax backdrops that may anchor to
|
|
* their own map edges; linked/foreground layers retain the world origin. */
|
|
void gpu_ws_bg2d_begin_view_layer(unsigned layer, uint32_t packet, unsigned independent_mask);
|
|
void gpu_ws_bg2d_end_view_layer(unsigned layer, uint32_t packet);
|
|
/* Opt-in host-produced SPRT_16 packets, 32-byte slots in enhancement DMA RAM.
|
|
* The 16-byte standard packet is followed by signed view shift, left/right
|
|
* padding and GPU_WS_BG2D_PACKET_MAGIC, optionally ORed with MIRROR_X.
|
|
* Coordinates use signed 16-bit X; ordinary
|
|
* packets retain PS1 signed 11-bit coordinates. The guest tile loop/ring stays
|
|
* native while this arena is registered. Allocate once during mod activation. */
|
|
void gpu_ws_bg2d_set_host_arena(uint32_t base, uint32_t size);
|
|
#define GPU_WS_BG2D_PACKET_MAGIC 0x58364247u
|
|
#define GPU_WS_BG2D_BANK_PACKET_MAGIC 0x58364248u
|
|
/* Bank packets pack signed shift in +16 low half and immutable bank ID in
|
|
* its high half. Their indices use the bank, but palettes remain live VRAM.
|
|
* Keep the original magic readable for pending packets in older snapshots. */
|
|
#define GPU_WS_BG2D_MIRROR_X 0x80000000u
|
|
struct WsViewAnchor;
|
|
int gpu_ws_bg2d_get_view(unsigned layer, struct WsViewAnchor *view);
|
|
void gpu_ws_set_auto_ui_squash(int on);
|
|
/* [widescreen] auto_ui_anchor = "in_place": each UI run squashes about its own
|
|
* centre rather than an edge/centre third (default "edges"). */
|
|
void gpu_ws_set_auto_ui_in_place(int on);
|
|
/* [widescreen] auto_ui_size: 1 = proportional (the auto-UI HUD shrinks by
|
|
* sqrt((16:9) / aspect) beyond 16:9), 0 = original. */
|
|
void gpu_ws_set_auto_ui_proportional(int on);
|
|
/* [widescreen.bg2d] Capcom 2D background tile-loop widen — hooked at the renderer's
|
|
* column-count / start-tile-col / start-screen-x instructions. Identity at 4:3
|
|
* and in the engine's 512 hi-res mode. */
|
|
void gpu_ws_bg2d_configure(uint32_t layer_base, uint32_t ring_base,
|
|
uint32_t map_size_addr, uint32_t layer_stride_addr,
|
|
uint32_t ring_cols, uint32_t layer_count,
|
|
uint32_t layer_struct_stride, uint32_t packet_cap);
|
|
/* Some Capcom variants (MMX5/MMX6) can compose a layer's scroll with a parent
|
|
* selected by byte +0x52. MMX4's streamer always uses each layer's own scroll. */
|
|
void gpu_ws_bg2d_set_parent_links(int on);
|
|
int psx_ws_bg2d_cols(int base);
|
|
int psx_ws_bg2d_startcol(int col, unsigned mask);
|
|
int psx_ws_bg2d_startx(int x);
|
|
int psx_ws_bg2d_stream_left(int x);
|
|
int psx_ws_bg2d_stream_right(int x);
|
|
int psx_ws_bg2d_undercap(int counter, int native_cap);
|
|
/* MISNAMED, NOT MMX6-SPECIFIC, AND NOT SAFE TO DELETE (surveyed 2026-07-27).
|
|
*
|
|
* These read as "MMX6 compat shims" and the comment here used to say exactly
|
|
* that. They are not. They are the widescreen-2D entry points that the
|
|
* recompiler emits for ANY title with a [widescreen.bg2d] block, and live
|
|
* generated code in several non-MMX6 games links them today:
|
|
*
|
|
* psx_ws_mmx6_bg_cols/startcol/startx/stream_left/stream_right
|
|
* -> CrashBashRecomp, MegaManX5Recomp, TsumuRecomp (+ -release)
|
|
* psx_ws_mmx6_bg_undercap (below, in gpu.c)
|
|
* -> ApeEscapeRecomp, CrashBashRecomp, MegaManX4Recomp,
|
|
* MegaManX5Recomp, TsumuRecomp, Vigilante8PSXRecomp, THPS2
|
|
*
|
|
* Each one forwards to its psx_ws_bg2d_* twin above, which is the real
|
|
* implementation. Only the NAME is historical: this began as MMX6 widescreen
|
|
* work and was generalised without renaming the emitted symbols.
|
|
*
|
|
* Deleting or renaming them breaks widescreen in every repo listed above, and
|
|
* a rename cannot be runtime-only: the names are emitted by
|
|
* recompiler/src/code_generator.cpp, which is in codegen_hash_sources.cmake,
|
|
* so changing it rolls the overlay cache tag and forces a regen + reshard of
|
|
* every title. That is the reason this is still called mmx6 in 2026.
|
|
*
|
|
* Verify before touching, don't trust this comment: grep the generated trees
|
|
* of the game repos for psx_ws_mmx6_bg_undercap and see who turns up.
|
|
*/
|
|
int psx_ws_mmx6_bg_cols(int base);
|
|
int psx_ws_mmx6_bg_startcol(int col);
|
|
int psx_ws_mmx6_bg_startx(int x);
|
|
int psx_ws_mmx6_bg_stream_left(int x);
|
|
int psx_ws_mmx6_bg_stream_right(int x);
|
|
struct CPUState;
|
|
void psx_ws_sprite_tag(struct CPUState* cpu);
|
|
/* Explicit screen-space tags for trusted title mods. Tag the P_TAG address
|
|
* before submission; no guest packets are changed. Anchors/period are authored
|
|
* display pixels. Unlike billboard tags these do not classify a frame as 3D.
|
|
* Corrections are identity at 4:3 and on pure-2D screens. Tiled tags apply only
|
|
* to variable textured rectangles and repeat a title-proven composite period.
|
|
* A tiled strip reconstructs a horizontally clipped source: authored U is its
|
|
* left crop, so restore X-U, U=0 and source_width before repeating. */
|
|
void gpu_ws_tag_screen_prim(uint32_t prim, int32_t anchor);
|
|
/* Resize an untextured quad group between two independently anchored edges.
|
|
* Useful for health gauges that should fill the available width while their
|
|
* labels and neighboring timer keep their original proportions. */
|
|
void gpu_ws_tag_stretched_prim(uint32_t prim, int32_t left, int32_t right,
|
|
int32_t left_anchor, int32_t right_anchor);
|
|
void gpu_ws_tag_tiled_strip(uint32_t prim, int32_t anchor,
|
|
int32_t period, int32_t source_width);
|
|
|
|
/* Native-wide (mode 2) on a game frame. ws_nw_extra() is the total width the
|
|
* frame grows by, in display pixels (the present path widens the display read
|
|
* by this; 0 when native-wide is inactive). */
|
|
int ws_native_wide_active(void);
|
|
int ws_nw_extra(void);
|
|
/* Configured per-side reveal, excluding the world-culling safety envelope.
|
|
* Available before scene classification so first-frame overlays can fit. */
|
|
int gpu_ws_configured_x_reveal(void);
|
|
int ws_nw_present_width(void);
|
|
/* Display width (native px) the native-wide margins are derived from. */
|
|
int gpu_ws_display_width(void);
|
|
void gpu_ws_set_netplay_local_viewport(int enabled, int slot);
|
|
int gpu_ws_netplay_local_viewport_base_x(void);
|
|
int gpu_ws_netplay_local_viewport_width(void);
|
|
/* True when the current frame must present at native 4:3 (FMV video or a
|
|
* full-2D menu/title screen), so the squash is suppressed and content drawn
|
|
* pixel-native. The present path uses the same predicate to pillarbox. */
|
|
int gpu_ws_present_native_43(void);
|
|
/* Per-side X cull-margin (screen/world units) emitted into the game's draw-
|
|
* cull immediates by the recompiler ([widescreen.cull]); 0 unless stretching. */
|
|
int psx_ws_x_margin(void);
|
|
/* Netplay own-view mods: while on, psx_ws_x_margin() is 0 (the stock cull)
|
|
* except inside a sandboxed local-view render (render_pass.c sets the scope). */
|
|
void gpu_ws_set_local_view_only(int on);
|
|
void gpu_ws_set_local_view_scope(int on);
|
|
int gpu_ws_local_view_only(void);
|
|
void gpu_ws_set_cull_guard_pixels(int pixels);
|
|
/* Bias/range activation-window margin. This may include an additional
|
|
* resident-object lead while render/terrain paths retain psx_ws_x_margin(). */
|
|
int psx_ws_activation_margin(void);
|
|
void gpu_ws_set_activation_guard_pixels(int pixels);
|
|
void gpu_ws_set_explicit_cull_sites(const uint32_t *bias, int nbias,
|
|
const uint32_t *slti, int nslti,
|
|
const uint32_t *range, int nrange);
|
|
void gpu_ws_set_slti_lower_cull_sites(const uint32_t *sites, int nsites);
|
|
void gpu_ws_set_negsub_cull_sites(const uint32_t *sites, int nsites);
|
|
void gpu_ws_set_vxrange_cull_sites(const uint32_t *sites, int nsites);
|
|
void gpu_ws_set_depth_cull_sites(const uint32_t *sites, int nsites);
|
|
void gpu_ws_set_plane_nx_sites(const uint32_t *sites, int nsites);
|
|
void gpu_ws_set_xclip_load_sites(const uint32_t *sites, int nsites);
|
|
/* Interpreter copies of the explicit branch kinds ([widescreen.cull]
|
|
* bltz_sites, bgez_sites, branch_keep_sites) and of clip_edge_x_load_sites
|
|
* with its screen width (clip_edge_width). Native code compiles them in. */
|
|
void gpu_ws_set_branch_cull_sites(const uint32_t *bltz, int nbltz,
|
|
const uint32_t *bgez, int nbgez,
|
|
const uint32_t *keep, int nkeep);
|
|
void gpu_ws_set_clip_edge_x_load_sites(const uint32_t *sites, int nsites,
|
|
uint32_t width);
|
|
void gpu_ws_set_cull_keep_sites(const uint32_t *addresses,
|
|
const uint32_t *expected,
|
|
const uint32_t *results, int nsites);
|
|
/* [[widescreen.cull.sxy]]: packed-SXY all-vertices reject folds. Per site i,
|
|
* vertices[i] (3 or 4) ANDs at fold_addresses[i*4 + k] with words
|
|
* fold_expected[i*4 + k] and SXY operand vertex_regs[i*4 + k], then the
|
|
* beq/bne consumer. The recompiler config loader has validated the shape. */
|
|
#define PSX_WS_SXY_CULL_SITES_MAX 64
|
|
void gpu_ws_set_sxy_cull_sites(const uint32_t *vertices,
|
|
const uint32_t *fold_addresses,
|
|
const uint32_t *fold_expected,
|
|
const uint32_t *vertex_regs,
|
|
const uint32_t *consumer_addresses,
|
|
const uint32_t *consumer_expected, int nsites);
|
|
void gpu_ws_set_angle_sites(const uint32_t *addresses,
|
|
const uint32_t *expected, int nsites);
|
|
/* [[widescreen.cull.scale]]: full-word-guarded SLT/SLTU sites whose rs (0) or
|
|
* rt (1) operand is a runtime +/-half_extent*z frustum bound. */
|
|
void gpu_ws_set_cull_scale_sites(const uint32_t *addresses,
|
|
const uint32_t *expected,
|
|
const uint32_t *operands,
|
|
const uint32_t *half_extents, int nsites);
|
|
void gpu_ws_set_aspect_cone(const uint32_t *addresses,
|
|
const uint32_t *expected,
|
|
const uint32_t *cosine_thresholds,
|
|
const uint32_t *object_regs,
|
|
const uint32_t *x_regs,
|
|
const uint32_t *z_regs,
|
|
const uint32_t *y_regs,
|
|
const uint32_t *queue_guards,
|
|
int nsites,
|
|
uint32_t forward_addr,
|
|
uint32_t object_type_offset,
|
|
uint32_t hysteresis_pixels,
|
|
uint32_t queue_reserve,
|
|
const uint32_t queue_count_addrs[3],
|
|
const uint32_t queue_capacities[3],
|
|
const uint32_t queue_type_masks[3]);
|
|
int psx_ws_is_cull_bias_site(uint32_t pc);
|
|
void gpu_ws_set_bias_lower_cull_sites(const uint32_t *sites, int nsites);
|
|
int psx_ws_is_cull_bias_lower_site(uint32_t pc);
|
|
int psx_ws_is_cull_slti_site(uint32_t pc);
|
|
int psx_ws_is_cull_slti_lower_site(uint32_t pc);
|
|
int psx_ws_is_cull_negsub_site(uint32_t pc);
|
|
int psx_ws_is_cull_vxrange_site(uint32_t pc);
|
|
int psx_ws_is_cull_depth_site(uint32_t pc);
|
|
int32_t psx_ws_depth_bound(int32_t imm);
|
|
int psx_ws_is_cull_range_site(uint32_t pc);
|
|
int psx_ws_is_cull_plane_nx_site(uint32_t pc);
|
|
int32_t psx_ws_plane_nx(int32_t nx);
|
|
int psx_ws_is_cull_xclip_load_site(uint32_t pc);
|
|
uint32_t psx_ws_xclip_bound(uint32_t vanilla);
|
|
int psx_ws_is_cull_bltz_site(uint32_t pc);
|
|
int psx_ws_is_cull_bgez_site(uint32_t pc);
|
|
int psx_ws_is_cull_branch_keep_site(uint32_t pc);
|
|
void gpu_ws_set_masked_reject_sites(const uint32_t *addresses,
|
|
const uint32_t *expected, const uint32_t *masks, int count);
|
|
int psx_ws_masked_reject(uint32_t flags, uint32_t mask);
|
|
int psx_ws_masked_reject_site(uint32_t pc, uint32_t instr,
|
|
uint32_t flags, int vanilla);
|
|
int psx_ws_nclip_branch(uint32_t pc, uint32_t instr, int32_t mac0, int vanilla);
|
|
uint64_t gpu_ws_native_wide_nclip_rescues(void);
|
|
int psx_ws_is_cull_clip_edge_x_load_site(uint32_t pc);
|
|
uint32_t psx_ws_clip_edge_width(void);
|
|
uint32_t psx_ws_cull_keep_result(uint32_t vanilla, uint32_t forced);
|
|
int psx_ws_cull_keep_site(uint32_t pc, uint32_t instr, uint32_t vanilla,
|
|
uint32_t *out);
|
|
/* One AND of a [[widescreen.cull.sxy]] fold (ws_cull_edge.h); identity at 4:3. */
|
|
uint32_t psx_ws_cull_sxy_and(uint32_t acc, uint32_t sxy);
|
|
/* Interpreter lookup: the SXY operand register (1..31) when `instr` at `pc`
|
|
* is an AND of a configured fold and every fold and consumer word, read
|
|
* through `read_word` (physical address), matches; else 0. */
|
|
extern int g_psx_ws_sxy_cull_n;
|
|
uint32_t psx_ws_sxy_cull_vertex_reg(uint32_t pc, uint32_t instr,
|
|
uint32_t (*read_word)(uint32_t phys));
|
|
void gpu_ws_set_packed_x_sites(const uint32_t *addresses,
|
|
const uint32_t *expected, int count);
|
|
int psx_ws_cull_packed_x_site(uint32_t pc, uint32_t instr, uint32_t x,
|
|
uint32_t width, uint32_t *out);
|
|
uint32_t psx_ws_angle_widen(uint32_t vanilla);
|
|
int psx_ws_angle_site(uint32_t pc, uint32_t instr, uint32_t *out);
|
|
/* bound * (half_extent + margin) / half_extent; identity at 4:3. */
|
|
int32_t psx_ws_cull_scale(int32_t bound, int32_t half_extent);
|
|
/* Interpreter path for a configured scale site: returns 1 and the widened
|
|
* compare verdict in *out when (pc, instr) is a configured site. */
|
|
int psx_ws_cull_scale_site(uint32_t pc, uint32_t instr, uint32_t rs_value,
|
|
uint32_t rt_value, uint32_t *out);
|
|
uint32_t psx_ws_aspect_cone_result(uint32_t site, uint32_t vanilla,
|
|
uint32_t object, int32_t x, int32_t z,
|
|
int32_t y);
|
|
int psx_ws_aspect_cone_site(CPUState *cpu, uint32_t pc, uint32_t instr,
|
|
uint32_t vanilla, uint32_t *out);
|
|
/* Scale a signed Q16 horizontal gameplay limit into the active native-wide
|
|
* game field. Identity at 4:3 / menus / FMV. */
|
|
int32_t psx_ws_player_x_bound(int32_t vanilla);
|
|
void gpu_ws_set_signed_x_bound_sites(const uint32_t *addresses,
|
|
const uint32_t *expected, int count);
|
|
int psx_ws_is_signed_x_bound_site(uint32_t pc, uint32_t instr);
|
|
/* Widen a signed screen-pixel edge loaded by an explicitly guarded site. */
|
|
int32_t psx_ws_screen_x_bound(int32_t vanilla);
|
|
|
|
/* Shared render-funnel screen-X cull widening ([widescreen.cull] auto_screen_x):
|
|
* the gcc emit and the interpreter both route a flagged
|
|
* `sltiu rt, sx, 0x140/0x141` through this one helper so every overlay execution
|
|
* path widens identically. Returns the sltiu verdict (1 = keep). 0 at 4:3. */
|
|
int psx_ws_cull_sltiu(uint32_t sx, uint32_t imm);
|
|
/* screen_x_sites on `sltu rd, SX, W` (W in a register): -4m <= SX < W. */
|
|
int psx_ws_cull_sltu_band(uint32_t sx, uint32_t bound);
|
|
/* Signed-funnel variants (min/max + center±halfwidth idioms — see
|
|
* ws_cull_detect.h): right-edge widen for `slti v, minSX, W` and left-edge
|
|
* widen for the paired `bltz maxSX` reject. Identity at 4:3. */
|
|
int psx_ws_cull_slti(uint32_t sx, uint32_t imm);
|
|
int psx_ws_cull_slti_lower(uint32_t sx, uint32_t imm);
|
|
int psx_ws_cull_bltz(uint32_t v);
|
|
/* [widescreen.cull] bgez_sites: `bgez SX, keep` keeps while SX >= -margin
|
|
* (the exact partner of bltz_sites; see ws_cull_edge.h). Identity at 4:3. */
|
|
int psx_ws_cull_bgez(uint32_t v);
|
|
/* [widescreen.cull] clip_edge_x_load_sites: a loaded screen-X clip bound of 0
|
|
* becomes -margin and one of `w` becomes w+margin; interior bounds and 4:3
|
|
* are unchanged (see ws_cull_edge.h). */
|
|
uint32_t psx_ws_clip_edge_x(uint32_t v, uint32_t w);
|
|
/* [widescreen.cull] screen_x_sites on `lui` and `bltz`: a screen X kept in the
|
|
* high half of a register. The edge `lui rt, W` becomes (W + margin) << 16 and
|
|
* the `bltz` is taken while SX < -margin (see ws_cull_edge.h). Identity at
|
|
* 4:3. */
|
|
uint32_t psx_ws_cull_lui_hi(uint32_t imm);
|
|
int psx_ws_cull_bltz_hi(uint32_t v);
|
|
void gpu_ws_set_cull_screen_x_sites(const uint32_t *sites, int nsites);
|
|
int psx_ws_is_cull_screen_x_site(uint32_t pc);
|
|
int psx_ws_cull_vxrange(uint32_t x, uint32_t imm);
|
|
/* True if a run of instruction words carries the screen-extent reject signature
|
|
* (a width compare AND a height compare from the configured immediate sets).
|
|
* Used by the interp to gate the widening to real render funnels. */
|
|
int psx_ws_func_has_screen_cull(const uint32_t *words, int n);
|
|
/* Classify words[idx] as an X left-edge reject bltz (runtime imm sets). */
|
|
int psx_ws_cull_bltz_at(const uint32_t *words, int n, int idx);
|
|
/* Per-game cull signature immediates ([widescreen.cull] screen_w_imms /
|
|
* screen_h_imms); defaults 0x140/0x141 + 0xE0/0xF1. */
|
|
void gpu_ws_set_cull_imms(const uint32_t *w, int nw, const uint32_t *h, int nh);
|
|
int psx_ws_is_cull_w_imm(uint32_t imm);
|
|
/* Per-game opt-in gates for the pattern-scanned interp widen hooks
|
|
* (auto_screen_x cull + auto_backdrop preload). Default OFF: a title that
|
|
* never opted in must never have its live code pattern-scanned and rewritten. */
|
|
void gpu_ws_set_auto_hooks(int cull_on, int backdrop_on);
|
|
int psx_ws_auto_cull_on(void);
|
|
/* Perspective-correct UV interpolation for textured world polygons
|
|
* ([video] perspective_texturing). Also turns on the SWC2 RAM-provenance
|
|
* tracking it needs, so a polygon only qualifies when every position word in
|
|
* its DMA packet was written by a GTE projection store. Default off. */
|
|
void gpu_texture_correction_set(int enabled);
|
|
int gpu_texture_correction_enabled(void);
|
|
/* Triangles drawn with perspective-correct UVs since startup. */
|
|
uint32_t gpu_texture_correction_hits(void);
|
|
/* GTE-activity gameplay detector ([widescreen] gte_game_mode) for 3D titles
|
|
* with no sprite-tag helper: gte.cpp notes every RTPS/RTPT projection; a frame
|
|
* that projects enough vertices is stamped as gameplay. */
|
|
void gpu_ws_set_gte_game_mode(int on);
|
|
void gpu_ws_set_precise_nclip(int on);
|
|
void psx_ws_note_gte_project(int nverts);
|
|
/* Optional authoritative gameplay-state gate. When configured, it replaces
|
|
* heuristic gameplay classification for native-wide presentation. */
|
|
void gpu_ws_set_gameplay_state_gate(uint32_t addr,
|
|
const uint32_t *values, int nvalues);
|
|
/* [netplay] local_viewport_state_*: a split frame counts as a vertical split
|
|
* (netplay local viewport) only while this word holds one of the values. */
|
|
void gpu_ws_set_local_viewport_state_gate(uint32_t addr,
|
|
const uint32_t *values, int nvalues);
|
|
/* Native-wide HUD corner re-anchoring ([widescreen] nw_hud_corners): push
|
|
* outer-third screen-space HUD primitives out to the true wide-frame corners
|
|
* (they otherwise sit inset by the reveal). Runtime-only. Off by default. */
|
|
void gpu_ws_set_nw_hud_corners(int on);
|
|
void gpu_ws_tag_hud_primitive(uint32_t primitive, int edge);
|
|
void gpu_ws_tag_world_primitive(uint32_t primitive, int is_world);
|
|
void gpu_ws_set_adaptive_backdrop_preload(int enabled);
|
|
/* Explicit screen-space HUD packet anchor from a trusted title plugin.
|
|
* Native-wide translates; projection-and-stretch scales about the anchor.
|
|
* `prim` is the address of the PsyQ P_TAG word; the drawn command starts at
|
|
* prim+4. anchor: -1 = left, 0 = center, +1 = right. */
|
|
void gpu_ws_tag_hud_prim(uint32_t prim, int anchor);
|
|
/* Stretch a trusted authored background primitive about the display center in
|
|
* the native-wide output only (GL/SW). prim+4 is the command address, including
|
|
* for a command embedded inside a longer DMA packet. Only opaque polygons and
|
|
* variable textured rectangles (64h/65h) are accepted; address, full packet
|
|
* contents, and frame freshness are guarded.
|
|
* Tag the complete background composite before submitting its ordering table.
|
|
* The caller proves background identity/coverage; no guest data is modified. */
|
|
void gpu_ws_tag_background_prim(uint32_t prim);
|
|
/* Always-on counters for the explicit HUD-anchor and background tag tables:
|
|
* how many tags a title plugin offered, how many were rejected at insert
|
|
* (native-wide not configured / unreadable or unsupported command), and why
|
|
* executing primitives that matched a tagged address were or were not
|
|
* honoured. TCP: {"cmd":"ws_tag_stats"}. */
|
|
typedef struct GpuWsTagStats {
|
|
uint64_t tag_calls;
|
|
uint64_t tag_rejected;
|
|
uint64_t hit;
|
|
uint64_t stale;
|
|
uint64_t guard_mismatch;
|
|
uint32_t last_tag_frame;
|
|
uint32_t last_hit_frame;
|
|
} GpuWsTagStats;
|
|
void gpu_ws_get_tag_stats(GpuWsTagStats *hud, GpuWsTagStats *background);
|
|
/* Freeze/unfreeze the always-on GP0 command ring (capture mark). */
|
|
void gpu_gp0_ring_set_frozen(int frozen);
|
|
/* Fresh packet tags are eligible for background classification. */
|
|
int gpu_ws_background_stretch_active(void);
|
|
/* A tagged background can remain in a wide surface after its packet expires.
|
|
* Once used, retain full compositing until GPU reset or snapshot restoration.
|
|
* Packet freshness must never re-enable canonical-center overwrites. */
|
|
int gpu_ws_background_requires_full_composite(void);
|
|
/* Clear synthetic margins to black over an opaque 0x64/65 rectangle's Y band
|
|
* immediately before it executes. Packet-guarded; canonical VRAM is untouched. */
|
|
void gpu_ws_tag_black_reveal_rect(uint32_t prim);
|
|
/* Repeat an opaque, already-clipped textured rectangle into native-wide
|
|
* reveal margins only. The caller verifies the composite's source period.
|
|
* Original UVs, texel density, and canonical VRAM writes are unchanged. */
|
|
void gpu_ws_tag_repeat_rect(uint32_t prim, int32_t period);
|
|
/* Title-identified 15-bit sprite (0x64-0x67) that copies a framebuffer 1:1,
|
|
* e.g. a motion trail. Where it touches the draw area's edge, native-wide
|
|
* continues it into the bands from the source buffer's wide surface.
|
|
* Packet-guarded for the current frame; canonical VRAM is untouched. */
|
|
void gpu_ws_tag_feedback_rect(uint32_t prim);
|
|
/* Title-identified flat screen mask: extend vertical sides or horizontal
|
|
* letterbox panels to adaptive edges, preserving the interior opening.
|
|
* Packet guarded, cleared on reset/load, inert outside native-wide gameplay. */
|
|
void gpu_ws_tag_screen_mask_quad(uint32_t prim);
|
|
/* Title-owned flat/Gouraud radial screen mask. Render-only scale about the
|
|
* display centre; guest coordinates and timing stay unchanged. Scale >= 1,
|
|
* inert at 4:3, packet guarded and reset alongside other transient tags. */
|
|
void gpu_ws_tag_radial_screen_mask_quad(uint32_t prim, float scale);
|
|
/* Pure emulation-thread predicate for a known native-only effect/scene.
|
|
* Nonzero forces native 4:3; zero defers. No GPU calls or guest writes inside.
|
|
* Host configuration survives reset/load; classification reads live state. */
|
|
void gpu_ws_set_native_scene_predicate(int (*predicate)(void));
|
|
/* Targeted alternative for sprite-heavy 2D games: corner-anchor only primitives
|
|
* whose ordering-table packet lives in the configured half-open RAM range. */
|
|
void gpu_ws_set_nw_left_hud_packet_range(uint32_t lo, uint32_t hi);
|
|
void gpu_ws_begin_linked_list(void);
|
|
void gpu_ws_end_linked_list(void);
|
|
void gpu_ws_prepass_linked_list(uint32_t start_addr);
|
|
void gpu_ws_validate_linked_list_header(uint32_t addr, uint32_t header);
|
|
void gpu_ws_validate_linked_list_node(uint32_t addr, uint32_t num_words);
|
|
void gpu_ws_restore_linked_list_rank(uint32_t rank);
|
|
/* Native-wide full-frame 2D backdrop stretch ([widescreen] nw_backdrop):
|
|
* stretch a screen-space quad that covers the whole 4:3 framebuffer (sky
|
|
* gradient / backdrop image) to fill the wide frame, so it no longer
|
|
* pillarboxes at the reveal margins. Runtime-only. Off by default. */
|
|
void gpu_ws_set_nw_backdrop(int on);
|
|
int gpu_ws_native_wide_projection_correction(uint64_t *vertices);
|
|
/* Native-wide flat-polygon backdrop stretch ([widescreen] nw_flat_backdrop):
|
|
* stretch untextured primitives in the wide mirror without changing the
|
|
* canonical 4:3 framebuffer. Intended for flat-colour sky/water backdrops. */
|
|
void gpu_ws_set_nw_flat_backdrop(int on);
|
|
int gpu_ws_nw_flat_backdrop_enabled(void);
|
|
/* Stretch the title-opted textured pre-3D backdrop phase in the wide mirror. */
|
|
void gpu_ws_set_nw_phase_backdrop(int on);
|
|
|
|
/* Backdrop screen-X correction ([widescreen.backdrop] x_sites). The parallax
|
|
* 2D backdrop layer computes screen-X without the GTE, so it misses the
|
|
* widescreen squash; the recompiler emits this on each backdrop handler's
|
|
* final screenX store to squash it around the screen centre (identity at 4:3).
|
|
* Pulls far backdrop pieces in from past the 320px edge to cover the 16:9 FOV. */
|
|
int psx_ws_backdrop_x(int x);
|
|
|
|
/* Backdrop PRELOAD ([widescreen.cull] auto_backdrop). psx_ws_backdrop_preload()
|
|
* is nonzero only while native-wide widescreen is engaged (0 at 4:3 / boot /
|
|
* FMV / full-2D), so the rewrite is byte-identical when off. psx_ws_backdrop_value()
|
|
* is the one value substitution shared by the gcc emit and the
|
|
* interpreter for a detected window bound: it returns `orig` unless preload is
|
|
* engaged, in which case it forces the bound to preload the WHOLE finite tile
|
|
* row (START -> 0, END -> large sentinel pinned by the generator's high clamp to
|
|
* extent-1). Every column is submitted, so the widened 16:9 viewport never gaps;
|
|
* the generator's clamps + the byte-sized row extent keep it bounded. */
|
|
int psx_ws_backdrop_preload(void);
|
|
uint32_t psx_ws_backdrop_value(uint32_t orig, int is_end, int window_cols);
|
|
|
|
/* auto_backdrop diagnostic ring (always-on). The interpreter records every
|
|
* window rewrite (with the live extent / DL count / camera-X); `ws_backdrop_ring`
|
|
* dumps it. psx_ws_backdrop_ring_json() formats the recent entries into `buf`
|
|
* (returns bytes written, excluding the caller's JSON envelope). */
|
|
void psx_ws_backdrop_ring_note(uint32_t pc, int kind, int wcols, uint32_t orig,
|
|
uint32_t finalv, int extent, int camx, int count,
|
|
uint32_t base, uint32_t dl);
|
|
int psx_ws_backdrop_ring_json(char *buf, int cap);
|
|
|
|
/* auto_ui_squash partition dump (`ws_ui_groups`). Reports, for the last UI
|
|
* prepass, each primitive's raw key inputs (CLUT/texpage band/family via op,
|
|
* y, h) alongside its union-find root and final anchor — enough to tell whether
|
|
* two HUD primitives shared a run, and which key component split them if not. */
|
|
int psx_ws_ui_groups_json(char *buf, int cap);
|
|
|
|
/* Live-tunable backdrop widen amount (ws_backdrop_margin command): <0 whole-row,
|
|
* 0 off, >0 N-column widen. g_ws_bd_from_interp is the interp's one-shot
|
|
* "I will record the rich entry myself" flag (see gpu.c / dirty_ram_interp.c). */
|
|
extern int g_ws_bd_margin;
|
|
extern int g_ws_bd_from_interp;
|
|
|
|
/* Native-wide: nonzero if the GP0 prim currently being drawn is sprite-tagged
|
|
* (a character / Tomba / HUD element). The GL 2D-backdrop stretch uses this to
|
|
* EXCLUDE foreground sprites (only the untagged 2D backdrop is stretched). */
|
|
int psx_ws_prim_is_tagged(void);
|
|
|
|
/* Flower-field backdrop data-structure address range + a predicate matching the
|
|
* prim being drawn against it (gp0_cmd_source_addr ∈ [lo,hi]). The dirty-RAM
|
|
* interp sets lo/hi when the backdrop generator runs; the GL stretch gate uses
|
|
* psx_ws_prim_in_backdrop() to identify the flower-field tiles precisely. */
|
|
extern uint32_t g_ws_backdrop_lo, g_ws_backdrop_hi;
|
|
int psx_ws_prim_in_backdrop(void);
|
|
|
|
/* Backdrop store-site registry: the runtime registers the [widescreen.backdrop]
|
|
* x_sites here (from game.toml) so the dirty-RAM interpreter applies the same
|
|
* psx_ws_backdrop_x() squash at those `sh` PCs that the recompiler emits into
|
|
* native cache DLLs — overlay code frequently runs interpreted, where the emit
|
|
* can't reach. PCs are masked to the physical (KUSEG) range. */
|
|
void psx_ws_set_backdrop_sites(const uint32_t* pcs, int n);
|
|
int psx_ws_is_backdrop_site(uint32_t pc);
|
|
|
|
/* Live widescreen state for diagnostics (TCP gpu_state). All pointers
|
|
* optional. last_tag_frame/cur_frame let the caller see game_mode freshness. */
|
|
typedef struct {
|
|
int configured; /* ws_xnum != ws_xden */
|
|
int active; /* squash currently applied this frame */
|
|
int game_mode; /* tagged char/billboard prim within 2 frames */
|
|
int present_native_43; /* frame presents pillarboxed 4:3 (FMV/full-2D) */
|
|
int x_margin; /* psx_ws_x_margin() right now */
|
|
int activation_margin; /* psx_ws_activation_margin() right now */
|
|
int xnum, xden; /* squash factor */
|
|
int mode; /* 0 = off, 1 = squash, 2 = native-wide */
|
|
int nw_extra; /* native-wide frame growth (display px), 0 if off */
|
|
int view_anchor, view_left, view_right, view_shift, view_pad_left, view_pad_right;
|
|
uint64_t cur_frame;
|
|
uint32_t bg2d_generations; /* Game background submissions, independent of vblank. */
|
|
uint32_t last_tag_frame; /* frame of newest tagged prim */
|
|
uint32_t last_3d_frame; /* frame of newest shaded prim (diagnostic) */
|
|
uint32_t gte_verts; /* RTPS/RTPT verts in the last completed frame */
|
|
uint32_t last_world3d_frame;/* newest SUSTAINED world-scale projection frame */
|
|
uint32_t ovh_prims; /* overhanging polys in the last completed frame */
|
|
uint32_t last_ovh_frame; /* newest SUSTAINED polygon-overhang frame (the
|
|
2D-only-scene classifier's world signal) */
|
|
int auto_ui_squash; /* final-OT grouped UI correction configured */
|
|
int auto_ui_in_place; /* runs anchor at their own centre, not thirds */
|
|
int auto_ui_dense; /* current list classified as a dense menu */
|
|
uint32_t auto_ui_ot_rank; /* highest populated UI rank in current list */
|
|
uint64_t auto_ui_candidates;
|
|
uint64_t auto_ui_transforms;
|
|
uint64_t aspect_cone_calls;
|
|
uint64_t aspect_cone_43_identity;
|
|
uint64_t aspect_cone_vanilla_keep;
|
|
uint64_t aspect_cone_visible_keep;
|
|
uint64_t aspect_cone_guard_keep;
|
|
uint64_t aspect_cone_hysteresis_keep;
|
|
uint64_t aspect_cone_outside_reject;
|
|
uint64_t aspect_cone_queue_reject;
|
|
uint32_t aspect_cone_queue_highwater[3];
|
|
uint64_t angle_calls;
|
|
uint64_t angle_43_identity;
|
|
uint32_t angle_max_vanilla;
|
|
uint32_t angle_max_widened;
|
|
/* Finite 2D backdrop verdict (ws_backdrop_extent.h), newest evaluation. */
|
|
int bd_veto; /* scene presented 4:3: backdrop stops short */
|
|
uint32_t bd_eval_frame, bd_rects, bd_last_short;
|
|
int bd_full, bd_short;
|
|
int32_t bd_min_x, bd_max_x, bd_reveal;
|
|
uint32_t bd_canon_pct, bd_left_pct, bd_right_pct;
|
|
uint64_t bd_evaluations, bd_short_frames;
|
|
} GpuWsDebug;
|
|
void gpu_ws_get_debug(GpuWsDebug* out);
|
|
|
|
typedef struct {
|
|
uint32_t address;
|
|
uint64_t calls;
|
|
uint64_t identity_43;
|
|
uint64_t vanilla_keep;
|
|
uint64_t visible_keep;
|
|
uint64_t guard_keep;
|
|
uint64_t hysteresis_keep;
|
|
uint64_t outside_reject;
|
|
uint64_t queue_reject;
|
|
} GpuWsAspectConeSiteDebug;
|
|
/* Exact-site telemetry for separating actor-list and per-child participation
|
|
* predicates. Returns zero when address is not configured. */
|
|
int gpu_ws_get_aspect_cone_site_debug(
|
|
uint32_t address, GpuWsAspectConeSiteDebug* out);
|
|
|
|
/* Diagnostic: force psx_ws_x_margin() to return v (>=0) regardless of state,
|
|
* or -1 to restore the normal computed margin. For live cull-margin sweeps. */
|
|
void gpu_ws_set_margin_override(int v);
|
|
|
|
/* Native-wide HUD corner re-anchoring: allow TAGGED rect-family prims to
|
|
* shift too (live A/B via TCP ws_hud_mode; some HUD composites render
|
|
* through the tagged sprite funnel). */
|
|
void gpu_ws_set_nw_hud_tag_rects(int on);
|
|
|
|
/* Always-on draw-census ring: every drawn primitive records frame / source
|
|
* addr / camera / first-vertex screen pos, so object spawn/despawn and edge
|
|
* culls are observable in data. Dump frames [f0,f1] to a CSV file. */
|
|
int gpu_ws_census_dump(uint32_t f0, uint32_t f1, const char *path);
|
|
void gpu_ws_census_set(int on);
|
|
uint64_t gpu_ws_census_seq(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PSXRECOMP_GPU_H */
|