mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 18:52:11 -04:00
Add ws_ui_groups: expose the auto_ui_squash partition
auto_ui_squash squashes each spatial run of UI primitives about that run's own anchor, so a HUD element split across two runs gets two anchors and comes apart as the frame widens -- elements drifting toward opposite edges, glyphs sliding off the background box they sit on. Diagnosing that required knowing which run each primitive landed in, and nothing exposed it. The two things an observer could reach were both insufficient: group.key is a hash of CLUT/texpage/Y-band/family, so unequal keys say two prims differ without saying WHICH component differed; and the anchor takes only three values (left/centre/right thirds), so equal anchors do not prove two prims actually co-grouped rather than coincidentally landing on the same third. ws_ui_groups dumps, for the last prepass, each primitive's op / key / raw key inputs (y, h, and the derived 24px band and poly-vs-rect family) / union-find root / final anchor, plus the frame-level active, squash, dense, rank, disp_x, disp_w and join_gap. Root plus raw inputs together answer "did these two merge, and if not, what split them". Carries two small support changes: - WsUiGroupItem gains a diagnostic `root`, written by ws_ui_group_assign in all three paths (dense, alloc-failure fallback, and the union-find path). Never read by the transform path. - WsUiPrepassItem retains y/h/op, which the key otherwise folds away. Read-only and query-driven, per the ring-buffer rule: capture is continuous and the observer asks for a window later.
This commit is contained in:
@@ -403,6 +403,12 @@ void psx_ws_backdrop_ring_note(uint32_t pc, int kind, int wcols, uint32_t orig,
|
||||
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). */
|
||||
|
||||
@@ -15,6 +15,14 @@ typedef struct {
|
||||
int32_t x;
|
||||
int32_t width;
|
||||
int32_t anchor;
|
||||
/* Diagnostic only: index of the union-find representative this item
|
||||
* merged into, so an observer can tell "these two share an anchor because
|
||||
* they are one run" from "these two happen to land on the same third".
|
||||
* Anchor equality cannot distinguish those — there are only three anchor
|
||||
* values — and that distinction is the whole question when a HUD element
|
||||
* splits apart under the squash. Written by ws_ui_group_assign; never read
|
||||
* by the transform path. */
|
||||
uint32_t root;
|
||||
} WsUiGroupItem;
|
||||
|
||||
/* Assign one thirds anchor to each complete spatial run. Items with the same
|
||||
|
||||
@@ -7842,6 +7842,31 @@ static void handle_ws_backdrop_ring(int id, const char *json)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* ws_ui_groups: dump the auto_ui_squash partition for the last UI prepass —
|
||||
* per primitive its op / key / raw key inputs (y, h, derived band and family) /
|
||||
* union-find root / final anchor.
|
||||
*
|
||||
* auto_ui_squash squashes each spatial run about its own anchor, so a HUD
|
||||
* element split across two runs gets two anchors and comes apart as the frame
|
||||
* widens (elements drifting to opposite edges, glyphs sliding off their
|
||||
* background box). Diagnosing that needed to know which run each primitive
|
||||
* landed in, and nothing exposed it: `key` is a hash, so unequal keys do not
|
||||
* say WHICH of CLUT/texpage/band/family differed, and `anchor` takes only three
|
||||
* values, so equal anchors do not prove two prims actually co-grouped.
|
||||
* Read-only; sized for the 2048-entry prepass cap. */
|
||||
static void handle_ws_ui_groups(int id, const char *json)
|
||||
{
|
||||
(void)json;
|
||||
size_t cap = 1u << 19; /* 512 KB: 2048 items * ~180 chars */
|
||||
char *buf = (char *)malloc(cap);
|
||||
if (!buf) { send_err(id, "alloc failed"); return; }
|
||||
int hdr = snprintf(buf, cap, "{\"id\":%d,\"ok\":true,", id);
|
||||
int body = psx_ws_ui_groups_json(buf + hdr, (int)cap - hdr - 4);
|
||||
snprintf(buf + hdr + body, cap - (size_t)(hdr + body), "}");
|
||||
debug_server_send_line(buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* ws_backdrop_margin [m=<N>]: live-tune the far-backdrop widen strategy without
|
||||
* a rebuild. m<0 = whole-row preload, m=0 = off, m>0 = widen N columns each side.
|
||||
* No m= just reports the current value. */
|
||||
@@ -13236,6 +13261,7 @@ static const CmdEntry s_commands[] = {
|
||||
{ "ws_aspect", handle_ws_aspect },
|
||||
{ "ws_nw", handle_ws_nw },
|
||||
{ "ws_backdrop_ring", handle_ws_backdrop_ring },
|
||||
{ "ws_ui_groups", handle_ws_ui_groups },
|
||||
{ "ws_backdrop_margin", handle_ws_backdrop_margin },
|
||||
{ "ws_backdrop_stretch", handle_ws_backdrop_stretch },
|
||||
{ "ws_dbg_stretch", handle_ws_dbg_stretch },
|
||||
|
||||
@@ -95,6 +95,13 @@ typedef struct {
|
||||
WsUiGroupItem group;
|
||||
uint32_t src_addr;
|
||||
uint16_t ot_rank;
|
||||
/* Diagnostic only (ws_ui_groups): the key is a hash, so a dump of keys
|
||||
* alone says two prims differ without saying WHICH component differed.
|
||||
* Keep the raw inputs so an observer can attribute a split to the CLUT,
|
||||
* the texpage, the 24px Y band, or the poly-vs-rect family. */
|
||||
int32_t y;
|
||||
int32_t h;
|
||||
uint8_t op;
|
||||
} WsUiPrepassItem;
|
||||
static WsUiPrepassItem ws_ui_prepass[WS_UI_PREPASS_MAX];
|
||||
static uint32_t ws_ui_prepass_count;
|
||||
@@ -1582,6 +1589,43 @@ int psx_ws_backdrop_ring_json(char *buf, int cap) {
|
||||
return off;
|
||||
}
|
||||
|
||||
/* ws_ui_groups — dump the auto_ui_squash partition for the LAST prepass.
|
||||
*
|
||||
* auto_ui_squash squashes each spatial run about its own anchor, so a HUD
|
||||
* element that lands in two runs gets two anchors and comes apart as the frame
|
||||
* widens. Nothing exposed which run a primitive ended up in, which made that
|
||||
* failure mode guesswork: the key is a hash of CLUT/texpage/Y-band/family, so
|
||||
* comparing keys tells you two prims differ without telling you why, and the
|
||||
* anchor takes only three values so anchor equality cannot prove co-grouping.
|
||||
*
|
||||
* This reports both the raw key inputs and the union-find root, which together
|
||||
* answer "did these two merge, and if not, which component split them". */
|
||||
int psx_ws_ui_groups_json(char *buf, int cap) {
|
||||
int off = snprintf(buf, (size_t)cap,
|
||||
"\"active\":%d,\"squash\":%d,\"dense\":%d,\"rank\":%d,"
|
||||
"\"disp_x\":%d,\"disp_w\":%d,\"join_gap\":%d,\"n\":%u,\"items\":[",
|
||||
ws_active(), ws_auto_ui_squash, ws_auto_ui_dense,
|
||||
ws_ui_prepass_rank != 0xFFFFu ? (int)ws_ui_prepass_rank : -1,
|
||||
ws_disp_x(), ws_disp_w(), WS_UI_GROUP_JOIN_GAP, ws_ui_prepass_count);
|
||||
for (uint32_t i = 0; i < ws_ui_prepass_count && off < cap - 220; i++) {
|
||||
const WsUiPrepassItem *it = &ws_ui_prepass[i];
|
||||
/* Recover the key components so a split is attributable. Mirrors
|
||||
* ws_auto_ui_group_key_words; kept in step with it by construction. */
|
||||
int32_t centre_y = it->y + it->h / 2;
|
||||
unsigned band = (unsigned)((centre_y < 0 ? 0 : centre_y / 24) & 0x1F);
|
||||
unsigned family = it->op < 0x60u ? 1u : 2u;
|
||||
off += snprintf(buf + off, (size_t)(cap - off),
|
||||
"%s{\"i\":%u,\"op\":\"%02x\",\"key\":\"%08x\",\"root\":%u,"
|
||||
"\"x\":%d,\"w\":%d,\"y\":%d,\"h\":%d,"
|
||||
"\"band\":%u,\"family\":%u,\"anchor\":%d,\"src\":\"%08x\"}",
|
||||
i ? "," : "", i, it->op, it->group.key, it->group.root,
|
||||
it->group.x, it->group.width, it->y, it->h,
|
||||
band, family, it->group.anchor, it->src_addr);
|
||||
}
|
||||
off += snprintf(buf + off, (size_t)(cap - off), "]");
|
||||
return off;
|
||||
}
|
||||
|
||||
/* Backdrop store-site registry. The [widescreen.backdrop] x_sites are emitted
|
||||
* into native cache-DLL code by the recompiler, but overlay code very often
|
||||
* runs INTERPRETED (no DLL loaded), where the emit can't reach. So the runtime
|
||||
@@ -4546,8 +4590,12 @@ static void ws_ui_prepass_add(const uint32_t *words, uint32_t source_addr,
|
||||
item->group.x = min_x - X;
|
||||
item->group.width = width;
|
||||
item->group.anchor = 0;
|
||||
item->group.root = ws_ui_prepass_count - 1u;
|
||||
item->src_addr = psx_ram_map_read(source_addr & 0x1FFFFFFFu) & ~3u;
|
||||
item->ot_rank = rank;
|
||||
item->y = min_y;
|
||||
item->h = height;
|
||||
item->op = (uint8_t)op;
|
||||
}
|
||||
|
||||
void gpu_ws_prepass_linked_list(uint32_t start_addr) {
|
||||
|
||||
@@ -31,8 +31,10 @@ void ws_ui_group_assign(WsUiGroupItem *items, size_t count,
|
||||
int32_t display_width, int dense_menu) {
|
||||
if (!items || count == 0 || display_width <= 0) return;
|
||||
if (dense_menu) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
items[i].anchor = display_width / 2;
|
||||
items[i].root = (uint32_t)i; /* diag: no runs formed */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,6 +43,7 @@ void ws_ui_group_assign(WsUiGroupItem *items, size_t count,
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
items[i].anchor = ws_ui_anchor_for_bounds(
|
||||
items[i].x, items[i].width, display_width);
|
||||
items[i].root = (uint32_t)i; /* diag: each item stands alone */
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -71,6 +74,7 @@ void ws_ui_group_assign(WsUiGroupItem *items, size_t count,
|
||||
}
|
||||
items[i].anchor =
|
||||
ws_ui_anchor_for_bounds(min_x, max_x - min_x, display_width);
|
||||
items[i].root = (uint32_t)root;
|
||||
}
|
||||
free(parent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user