HD textures: filtered sampling, a cache sized for a whole pack, indexed keys

- Filtered replacement sampling: with any texture filter but nearest, the
  replacement is sampled through its mip chain (textureGrad), the footprint
  clamped to the primitive's own UV bounds so atlas neighbours cannot bleed
  in. Texture windows (repeat) and UVs outside the page keep hd_texel.
- Edge clamp: an out-of-bounds sample clamped to the primitive's UV bounds
  takes the edge's sub-texel position too (keeping the outside fraction read
  a 1 px sliver of the next glyph at sprite borders).
- GL cache: 4096 slots and a PSX_HD_GL_CACHE_MIB budget (default 2048 MiB)
  with a direct-mapped hint table; a 4x pack of one race scene is several
  hundred textures, and the old 256 slot / 128 MiB cache re-uploaded and
  re-mipped them every frame.
- Invalidation: duck_texture_pack_invalidate returns early when a native
  write touches no residency or cache entry (almost every draw under HD
  authority lands on the frame buffer), and retire_unused walks the
  residency lists once instead of once per source.
- Indexed replacements: a TTTTTTTT-index.png key resolves through the palette
  in use at draw time, for packs whose textures are shared by several CLUTs.
- Debug: TCP {"cmd":"hd_uploads","x":..,"y":..} lists the texture uploads
  covering a VRAM point (pack authoring).

Measured with a full HD HUD and course pack for R4: steady 60 fps in races
where the old cache dropped to the high 20s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rkyma8rbyPiccs9n2bkyG6
This commit is contained in:
yacineolivier-maker
2026-10-20 21:59:04 +02:00
committed by Matthew Stanley
parent ddf1dfdbd4
commit f7fed074f1
6 changed files with 181 additions and 23 deletions
+9
View File
@@ -25,6 +25,13 @@ enum HdTextureLookupStatus {
HD_TEXTURE_LOOKUP_AMBIGUOUS = 2
};
/* Palette identity of an indexed replacement, named TTTTTTTT-index.png: its
* red channel holds CLUT indices (alpha 0 = transparent) and the renderer
* resolves them through the live CLUT of each draw, so one image serves every
* palette the game draws the texture with (highlights, fades). An exact
* TTTTTTTT-PPPPPPPP image still wins for its own palette. */
#define HD_TEXTURE_PALETTE_INDEXED 0xFFFFFFFFu
typedef struct HdTexturePackInfo {
const char* asset_root; /* valid until hd_texture_pack_destroy */
const char* replacement_root; /* valid until hd_texture_pack_destroy */
@@ -109,6 +116,8 @@ uint32_t hd_texture_hash_clut(const uint16_t* vram,
/* Upload bytes are row-major logical upload words, independent of destination
* wrapping. Tracking invalidates/splits every intersected older residency.
* Width <= 1024 and height <= 512; X/Y may wrap. */
int hd_texture_pack_debug_uploads_at(const HdTexturePack* pack, unsigned x, unsigned y,
char* out, size_t cap);
int hd_texture_pack_track_upload(HdTexturePack* pack,
uint16_t x,
uint16_t y,