Files
psxrecomp/runtime/include/gpu_sw_renderer.h
T
Matthew Stanley 8490d8b4cb feat(widescreen): native-wide via separate wide compositor surface (SW) + draw-census
Render the genuine 16:9 FOV at correct proportions instead of squash-then-stretch,
using a separate per-framebuffer wide surface so canonical PSX VRAM stays faithful
(4:3 / non-opted games byte-identical; the wide canvas only exists when opted in).

- Wide-aspect mode descriptor (off / squash / native-wide) in gpu.c; opt-in via
  [video] aspect_ratio. GTE fed the 4:3 ratio (identity, no squash) in native-wide;
  canonical draw_offset/draw_area left faithful (no VRAM widening, no wrap).
- Separate wide present-surfaces (gpu_sw_renderer.c) keyed by back-buffer base:
  framebuffer prims mirrored at local x = vram_x - base_x + OFFSET; margins cleared
  via the frame-clear mirror; present reads the displayed buffer's surface 1:1.
  Eliminates the A/B bleed + flicker (and the segfault) of the shared-canvas attempt.
  gr_* vtable extended; GL backend reports unsupported -> canonical present until
  the GL port (task 8).
- psx_ws_x_margin native-wide-aware (reuses the existing [widescreen.cull] emit).
  CONFIRMED a no-op for Tomba's edge objects: they spawn via a non-FUN_80022E44
  path (the foreground classifier is already 16:9-safe). See handoff.
- Draw-census extended with per-prim screen-X extent + back-buffer base for the
  native-wide void diagnosis; ws_nw TCP toggle; gpu_state ws.mode/nw_extra.
- Controller: "auto"/"gamepad"/"controller" device = first available SDL pad.

WIP checkpoint. SW compositor works: flicker fixed, faithful, terrain platform
fills the wide frame. REMAINING: discrete foreground OBJECTS (rock pillar, tree
branch, bushes) + the parallax backdrop are still culled at the 4:3 edge via a
separate generation/spawn path (wtrace the OT display-list writers next); GL
compositor port. Detail in NATIVE_WIDE_PLAN.md + the session handoff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 15:49:30 -07:00

110 lines
5.0 KiB
C

#ifndef PSX_GPU_SW_RENDERER_H
#define PSX_GPU_SW_RENDERER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Maximum internal-resolution supersampling factor (linear, per axis). */
#define SW_MAX_INTERNAL_SCALE 4
/* Initialize software renderer */
void sw_renderer_init(uint16_t* vram);
/* Internal-resolution supersampling (SSAA).
* scale == 1 : disabled, renderer behaves exactly as native VRAM only.
* scale > 1 : maintain an S*-scaled mirror of VRAM; the display reads the
* mirror (sw_render_display_hires) and the present path
* downsamples to the window. Clamped to SW_MAX_INTERNAL_SCALE.
* Must be called once after sw_renderer_init, before drawing begins. */
void sw_renderer_set_scale(int scale);
int sw_renderer_scale(void);
/* Texture filtering. 0 = nearest (native PSX look, default), 1 = bilinear
* (smooths textures/2D backgrounds; blends in RGB after the CLUT lookup,
* transparency-aware). Independent of supersampling. */
void sw_set_texture_filter(int bilinear);
int sw_texture_filter(void);
/* Draw state — must be set by gpu.c before each primitive */
void sw_set_semi_transparency(int enabled, int mode);
void sw_set_mask_bits(int set_bit, int check_bit);
void sw_set_texture_window(uint32_t raw);
void sw_set_color_modulation(int r, int g, int b, int raw_texture);
/* Drawing primitives — called from gpu.c command processing */
void sw_fill_rect(int x, int y, int w, int h, uint16_t color);
void sw_copy_rect(int src_x, int src_y, int dst_x, int dst_y, int w, int h);
void sw_draw_flat_triangle(int x0, int y0, int x1, int y1, int x2, int y2,
uint16_t color);
void sw_draw_gouraud_triangle(int x0, int y0, uint16_t c0,
int x1, int y1, uint16_t c1,
int x2, int y2, uint16_t c2);
void sw_draw_textured_triangle(int x0, int y0, int u0, int v0,
int x1, int y1, int u1, int v1,
int x2, int y2, int u2, int v2,
uint16_t clut_x, uint16_t clut_y,
uint16_t texpage);
void sw_draw_shaded_textured_triangle(int x0, int y0, int u0, int v0,
uint32_t color0,
int x1, int y1, int u1, int v1,
uint32_t color1,
int x2, int y2, int u2, int v2,
uint32_t color2,
uint16_t clut_x, uint16_t clut_y,
uint16_t texpage, int raw_texture);
void sw_draw_flat_rect(int x, int y, int w, int h, uint16_t color);
void sw_draw_textured_rect(int x, int y, int w, int h,
int u, int v,
uint16_t clut_x, uint16_t clut_y,
uint16_t texpage);
void sw_draw_textured_rect_scaled(int x, int y, int w, int h,
int u0, int v0, int u1, int v1,
uint16_t clut_x, uint16_t clut_y,
uint16_t texpage);
void sw_draw_line(int x0, int y0, int x1, int y1, uint16_t color);
void sw_draw_shaded_line(int x0, int y0, uint16_t c0,
int x1, int y1, uint16_t c1);
/* Copy display region to a 32-bit RGBA buffer for SDL presentation.
Returns number of pixels written. */
int sw_render_display(uint32_t* out_pixels, int out_pitch,
int disp_x, int disp_y, int disp_w, int disp_h);
/* Like sw_render_display, but reads the hi-res mirror and emits the region
at (disp_w*scale x disp_h*scale). Falls back to sw_render_display when
supersampling is disabled. Returns number of pixels written. */
int sw_render_display_hires(uint32_t* out_pixels, int out_pitch,
int disp_x, int disp_y, int disp_w, int disp_h);
/* VRAM transfer (CPU->VRAM, VRAM->CPU) */
void sw_vram_write(int x, int y, uint16_t pixel);
uint16_t sw_vram_read(int x, int y);
void sw_vram_transfer_in(int x, int y, int w, int h, const uint16_t* data);
void sw_vram_transfer_out(int x, int y, int w, int h, uint16_t* data);
/* Set draw area and draw offset */
void sw_set_draw_area(int x1, int y1, int x2, int y2);
void sw_get_draw_area(int *x1, int *y1, int *x2, int *y2);
void sw_set_draw_offset(int x, int y);
/* Native-wide compositor (see gpu_sw_renderer.c). Canonical VRAM stays faithful;
* framebuffer draws are mirrored into independent wide surfaces keyed by buffer
* base_x. wide_w<=0 disables. set_target selects/clears the mirror per back
* buffer; render_wide_display is the present source for the displayed buffer. */
void sw_wide_configure(int wide_w, int offset);
void sw_wide_set_target(int base_x);
void sw_wide_disable_target(void);
void sw_wide_clear(int base_x, int y, int h, uint16_t color);
int sw_render_wide_display(uint32_t* out_pixels, int out_pitch, int base_x,
int disp_y, int disp_h);
int sw_wide_width(void);
#ifdef __cplusplus
}
#endif
#endif /* PSX_GPU_SW_RENDERER_H */