Skip to content

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

Merged
mstan merged 4 commits into
RetroPortingToolKit:masterfrom
yacineolivier-maker:feat-hd-texture-filtering-indexed
Oct 24, 2026
Merged

mstan merged 4 commits into
RetroPortingToolKit:masterfrom
yacineolivier-maker:feat-hd-texture-filtering-indexed

Conversation

@yacineolivier-maker

@yacineolivier-maker yacineolivier-maker commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor
  • 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.

Verification

  • Game-agnostic: no title check or game address in the framework; behaviour is unchanged unless an HD texture pack is loaded (filtered sampling only with a non-nearest texture filter).
  • Build: R4 (tetrisgm/RidgeRacerType4Recomp master 737827c, USA config, its committed generated C) built against this branch alone: cmake-clang-v1 1.0.14 (clang, Ninja, Release), Windows 11.
  • Runtime: exercised in R4's PAL build (SCES-01706) with all of our framework branches combined on current master fe8d937d: boot, menus, a full Time Attack lap. The same changes on the previous base (379565a6) went through several days of play-testing: intro movie, menus, races, VS split screen, attract demo. Windows 11, i5-12400F, RTX 3060, OpenGL renderer; Vulkan and the software renderer were not tested.
  • Pin / regen: runtime only, no regen. A game consumes it with a pin bump.

Game side: tetrisgm/RidgeRacerType4Recomp#49 (PAL / Europe support) and tetrisgm/RidgeRacerType4Recomp#50 (race HUD, car effects, lighting; overview in tetrisgm/RidgeRacerType4Recomp#51)

I cannot follow up on review comments, sorry. Maintainers are welcome to edit, split, take over or close this.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Rkyma8rbyPiccs9n2bkyG6

@mstan mstan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed head ee77457.

The pack features are meaningful, and pack import/filter selection provides the elective enhancement boundary. Correct edge clamping and residency invalidation should then work automatically within that selected path. Please split or clearly qualify the unrelated changes here: sampling/indexed-palette support, cache policy, and invalidation/lifetime optimization. A 2 GiB default GL cache budget is a substantial change from 128 MiB and is not justified for all supported GPUs by one R4 pack; retain a conservative default or derive a documented bounded budget with allocation-failure fallback. Add executable pack fixtures for exact-palette precedence over indexed fallback, live CLUT changes, partial/wrapped upload invalidation, negative cache entries, and eviction/reload. The new retire_unused condition skips retirement when a write removes one source but splits another, leaving the total residency count unchanged or higher; verify that this cannot keep orphaned sources/pending observations beyond the documented budgets. A no-pack boot does not validate these feature paths. Tracking: beads-8zz2.

@mstan mstan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased onto current master and pushed 61b177b. Preserved master's released-source invalidation rule: dropping one tracked upload while splitting another can leave the resident count unchanged, so count change cannot determine whether pending dumps must finalize. Added that regression plus indexed fallback/exact-palette/live-CLUT coverage and removed embedded source NUL literals.

Both pack suites pass. The combined real NVIDIA HD fixture passes HIW off (209 checks), HIW on (208) and its native reference (19). Two old native-color expectations also failed on master; corrected assertions now require preserving source STP (83ff/83e0). The 2 GiB elective GPU-cache default is not being rejected merely for size. External large-pack/R4 timing and memory qualification remains unverified.

@mstan mstan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up validation at 1b8f8ea: added a real indexed-PNG upload/match/decode/GL-shader regression. Replacement index 2 selects the live blue CLUT entry, changing that CLUT entry produces red without changing/redecoding the replacement, and canonical VRAM retains the native source-index green. The combined hardware fixture now passes 218 checks (HIW off), 217 (on) and native reference 19. This closes the previously missing positive GPU indexed-path coverage; external R4/large-pack performance remains a separate unclaimed qualification.

@mstan mstan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalidation/retirement findings and positive GPU indexed-path coverage are resolved: exact/fallback palette matching and live CLUT changes pass through actual PNG upload/match/decode/shader execution. The elective cache budget is not blocked merely for its size. Updated hardware checks: 218 HIW off, 217 HIW on, 19 native reference, all zero failures.

The exact head is included in review/psx-prs-20261024 (b788fda). The selected Tomba!, Mega Man X6 and Ape Escape baseline/candidate builds pass gameplay and current-build save/load; original cards are unchanged. Capped runtime checks show no material frame-rate regression in the tested scenes. The owner has now confirmed all three title windows look fine.

Scope: Tomba/MMX6 use documented compatible remote ancestors because their latest feature heads also fail on frozen master due missing engine APIs; this is not qualification of those latest feature heads or of real multiplayer, whole-game content, external R4 assets, peak throughput, or physical fullscreen compositor behavior. Separate held PRs/drafts retain their own feature-contract questions. No merge is performed by this review.

yacineolivier-maker and others added 4 commits October 24, 2026 12:30
…ed 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
@mstan
mstan force-pushed the feat-hd-texture-filtering-indexed branch from 1b8f8ea to 8ff16e2 Compare October 24, 2026 19:35

@mstan mstan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased onto current master ddf1dfd after #174/#755/#715/#716. The only conflict was adjacent debug commands; both perf and hd_uploads implementations/registrations are retained. Range-diff confirms the three repair/fixture commits are unchanged and the original feature patch differs only in debug-command context. Full optimized native runtime builds, and all eight relevant override/package/pack/postfx/host-time checks pass. Existing real GL indexed/live-CLUT evidence remains applicable to the unchanged feature code. Owner accepted the title bundle and explicitly authorized this merge.

@mstan
mstan merged commit 6f84a29 into RetroPortingToolKit:master Oct 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants