Files
psxrecomp/runtime/tests/test_ws_feedback_rect.c
T
Zap0xfce2 1b778616b7 feat(widescreen): continue framebuffer-feedback sprites into native-wide bands (#692)
* feat(widescreen): continue framebuffer-feedback sprites into native-wide bands

Titles tag a 15-bit sprite that copies a framebuffer 1:1 (gpu_ws_tag_feedback_rect / psx_mod_tag_feedback_rect). Where it touches the draw area's edge, gpu.c emits band spans and the new optional backend op wide_feedback_rect (GL incl. render thread, software) samples the source buffer's wide surface. Band texels count as bit 15 set, as the centre does once the trail blends.

The software rasterizer now writes the texel's bit 15 into the framebuffer, and wide_full can dump the surface alpha ("alpha":1).

* fix(widescreen): quantise band feedback like packed VRAM

The centre samples 5-bit packed VRAM each frame; the band copy read the 8-bit wide surface and modulated with /128, so the bands drifted ~3 grey levels brighter and left a step at the 4:3 edge. Truncate like PACK_FS and modulate like TEX_FS.

* Reject fully clipped sprites before extending feedback margins

* Complete isolated resident and PGXP fixture collaborators

* Preserve existing line endings in the review fixes

---------

Co-authored-by: Matthew Stanley <1379tech@gmail.com>
2026-10-19 11:44:13 -07:00

70 lines
2.4 KiB
C

#include "ws_feedback_rect.h"
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
/* Kula's lethargy sprites: draw buffer at VRAM x 320, 320 wide, 16:9 margin. */
enum { LEFT = 320, WIDTH = 320, MARGIN = 54 };
static int span_equals(const WsFeedbackSpan *span, int32_t dst_x, int32_t src_x,
int32_t w) {
return span->dst_x == dst_x && span->src_x == src_x && span->w == w;
}
static void test_left_edge_sprite_gets_left_band(void) {
WsFeedbackSpan spans[2];
int count = ws_feedback_rect_spans(320, 256, 0, LEFT, WIDTH, MARGIN, spans);
assert(count == 1 && span_equals(&spans[0], 266, -54, 54));
}
static void test_right_edge_sprite_gets_right_band(void) {
WsFeedbackSpan spans[2];
int count = ws_feedback_rect_spans(576, 64, 256, LEFT, WIDTH, MARGIN, spans);
assert(count == 1 && span_equals(&spans[0], 640, 320, 54));
}
static void test_full_width_sprite_gets_both_bands(void) {
WsFeedbackSpan spans[2];
int count = ws_feedback_rect_spans(320, 320, 0, LEFT, WIDTH, MARGIN, spans);
assert(count == 2 && span_equals(&spans[1], 640, 320, 54));
}
static void test_inner_sprite_gets_no_band(void) {
WsFeedbackSpan spans[2];
assert(ws_feedback_rect_spans(400, 64, 80, LEFT, WIDTH, MARGIN, spans) == 0);
}
static void test_offscreen_sprite_gets_no_band(void) {
WsFeedbackSpan spans[2];
assert(ws_feedback_rect_spans(LEFT - 64, 32, 0, LEFT, WIDTH, MARGIN, spans) == 0);
assert(ws_feedback_rect_spans(LEFT - 32, 32, 0, LEFT, WIDTH, MARGIN, spans) == 0);
assert(ws_feedback_rect_spans(LEFT + WIDTH, 32, 0, LEFT, WIDTH, MARGIN, spans) == 0);
assert(ws_feedback_rect_spans(LEFT + WIDTH + 16, 32, 0, LEFT, WIDTH, MARGIN, spans) == 0);
}
static void test_zero_margin_gets_no_band(void) {
WsFeedbackSpan spans[2];
assert(ws_feedback_rect_spans(320, 320, 0, LEFT, WIDTH, 0, spans) == 0);
}
static void test_empty_sprite_rejected(void) {
WsFeedbackSpan spans[2];
assert(ws_feedback_rect_spans(320, 0, 0, LEFT, WIDTH, MARGIN, spans) == 0);
}
int main(void) {
test_left_edge_sprite_gets_left_band();
test_right_edge_sprite_gets_right_band();
test_full_width_sprite_gets_both_bands();
test_inner_sprite_gets_no_band();
test_offscreen_sprite_gets_no_band();
test_zero_margin_gets_no_band();
test_empty_sprite_rejected();
puts("ws_feedback_rect: all tests passed");
return 0;
}