runtime/ps2ui.h declares the whole runtime interface. The header is C99, has an extern "C" guard, and includes gsKit.h and kernel.h itself, so it needs gsKit on the include path on the console and the vendored copy on a host. Count the prototypes with the command below.
The 29 functions appear in the group tables below, once each. Every signature was compiled in this session from a scratch file that calls each function once, using the host flags from runtime/Makefile.
The scope column says which names a call resolves. "Blob" means the whole file. "Screen" means the current screen only, so a name that exists on another screen returns the failure value. Error codes and what triggers them are on Errors and constants. The per-frame call order is on The frame loop.
Zeroes ctx, validates, points ctx into data and arena. A refused blob never writes the arena. arena must be PS2UI_ARENA_ALIGN aligned and at least ps2ui_arena_size() bytes.
int ps2ui_upload(ps2ui_ctx *ctx, GSGLOBAL *gs)
0 / -1
blob
Sums VRAM for every texture first. On -1 nothing is transferred and ctx->uploaded stays 0. Streamed slots are budgeted but not bound until tex_set.
runtime text, else the placeholder, or NULL for an unknown name
blob
Slot lookup walks every slot in the blob, at ps2ui.c. Two screens cannot share a slot name and stay distinguishable. Focus and visibility lookups walk only the current screen's range, at ps2ui.c.
len must equal the slot's reservation exactly. texels becomes the DMA source: 16-aligned, alive and unmoved while the slot can draw. Nothing is copied. Call again to swap.
colors is linear; the CSM1 permutation is applied on the way in. Recolours every texture sharing the index. ncolors below the baked width leaves the tail transparent black. Refused before upload.
int ps2ui_theme_set(ps2ui_ctx *ctx, unsigned theme)
code
blob
Moves the live tint row. No GS traffic. Takes effect on the next render. Row 0 is the only legal value on a one-row blob.
uint32_t ps2ui_clut_csm1(uint32_t index)
the permuted index
none
Swaps bits 3 and 4. An involution over 0..255. Exposed for tests.
Streaming and palette swaps are described on Streaming art. The tint table and theme_set are described on Theming.
int ps2ui_visible_set(ps2ui_ctx *ctx, const char *name, int visible)
1 / 0
screen
Hides or shows one focus node's subtree, slots included. Geometry does not reflow. A hidden node is skipped by move. The bit survives a screen round trip.
int ps2ui_visible_get(const ps2ui_ctx *ctx, const char *name)
1 shown, 0 hidden, PS2UI_VISIBLE_UNKNOWN for an unknown name
int ps2ui_offset_set(ps2ui_ctx *ctx, int dx, int dy)
code
blob
Draw-time translation of every command and derived scissor. The canvas scissor stays put. A value outside int16 is PS2UI_ERR_RANGE and the old offset stays.
void ps2ui_offset_get(const ps2ui_ctx *ctx, int *dx, int *dy)
none
blob
Either pointer may be NULL. Queries stay in UI coordinates; add the offset when drawing beside the UI.
ps2ui_ctx is a public struct, and the app owns its storage. Read the fields below directly. Write the ones marked with a function through that function only, because render indexes tables by screen, focus and theme without re-checking them.
field
type
meaning
write through
hdr
const ps2ui_header *
the blob header: counts, canvas, feature bits, display aspect
The focused node's geometry is ctx->focus_nodes[ctx->focus], a ps2ui_focus_node with x, y, w, h in UI coordinates. The counters are described on Telemetry.
The runtime has one fixed-size limit. Table counts are bounded by the format's uint16_t fields and the arena is sized from them, so no texture, slot, screen or list-row cap exists.
name
value
meaning
PS2UI_VERSION
7
the blob format version; load refuses any other with PS2UI_ERR_VERSION
PS2UI_MAX_SCISSOR_DEPTH
8
scissor stack depth in render; the baker refuses deeper nesting
PS2UI_LIST_NAME_MAX
64
stack buffer for a built row name, prefix plus digits plus NUL; not a table bound
PS2UI_ARENA_ALIGN
16
required arena alignment; the CLUT region is a DMA source
render after a refused or missing upload draws no textures and sets vram_lost
clut_set
upload
render
before upload it returns PS2UI_ERR_STATE; a second upload re-permutes every CLUT from the blob and reverts the swap
tex_set
load
upload or render
none; an unfilled slot is skipped and counted in tex_unfilled
theme_set
load
upload or render
none; it survives an upload, so do a CLUT swap last when using both
list_set_count
list_init
any list move
a list starts empty, so a move before set_count does nothing
list_apply_visibility
list_set_count, and every list_move or list_select
render
rows past the end keep their panel and border drawn
visible_set
screen_set to the screen that owns the node
render
the name resolves on the current screen only; from another screen it returns 0
reading ctx->stats
one render
the next render
a composited frame ends holding only the last render's counters
gsKit_TexManager_nextFrame
the flip, once per frame
the next frame's first render
between two composited renders it ages the first screen's textures and re-uploads them every frame
The blob and the arena outlive the context. The CLUT region is re-read by gsKit whenever it re-binds an evicted texture, which happens at render time. A texels buffer given to tex_set has the same lifetime. The full per-frame sequence is on The frame loop.