mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
c3ff07814c
Bound reservations against total retained residency, skip decoding pinned images, and report complete repeated loads truthfully. Cover cap reductions and publication retry in both formats. Tracking: beads-eio.3.386.
227 lines
10 KiB
C
227 lines
10 KiB
C
#ifndef PSXRECOMP_HD_TEXTURE_PACK_H
|
|
#define PSXRECOMP_HD_TEXTURE_PACK_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* External Beetle-style texture-pack loader and VRAM upload tracker.
|
|
* The pack payload is never copied into or owned by the executable. */
|
|
typedef struct HdTexturePack HdTexturePack;
|
|
|
|
enum HdTextureDepth {
|
|
HD_TEXTURE_DEPTH_4BPP = 0,
|
|
HD_TEXTURE_DEPTH_8BPP = 1,
|
|
HD_TEXTURE_DEPTH_16BPP = 2
|
|
};
|
|
|
|
enum HdTextureLookupStatus {
|
|
HD_TEXTURE_LOOKUP_ERROR = -1,
|
|
HD_TEXTURE_LOOKUP_NONE = 0,
|
|
HD_TEXTURE_LOOKUP_FOUND = 1,
|
|
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 */
|
|
size_t replacement_file_count;
|
|
size_t unique_key_count;
|
|
size_t ambiguous_key_count;
|
|
size_t logical_mapping_count;
|
|
} HdTexturePackInfo;
|
|
|
|
typedef struct HdTexturePackEntry {
|
|
uint32_t texture_hash;
|
|
uint32_t palette_hash;
|
|
const char* replacement_path; /* valid until hd_texture_pack_destroy */
|
|
const char* logical_path; /* empty when Hashes.ini has no mapping */
|
|
} HdTexturePackEntry;
|
|
|
|
/* A UV interval is inclusive. first > last means that the 8-bit texture
|
|
* coordinate wraps through 255 -> 0. page_x/page_y are VRAM word coordinates.
|
|
* vram must contain the complete 1024x512 native PSX VRAM image. */
|
|
typedef struct HdTextureDrawQuery {
|
|
uint16_t page_x;
|
|
uint16_t page_y;
|
|
uint8_t depth; /* enum HdTextureDepth */
|
|
uint8_t u_first;
|
|
uint8_t u_last;
|
|
uint8_t v_first;
|
|
uint8_t v_last;
|
|
uint16_t clut_x;
|
|
uint16_t clut_y;
|
|
const uint16_t* vram;
|
|
size_t vram_word_count;
|
|
} HdTextureDrawQuery;
|
|
|
|
typedef struct HdTextureMatch {
|
|
HdTexturePackEntry entry;
|
|
uint64_t upload_serial;
|
|
uint16_t upload_width_words;
|
|
uint16_t upload_height;
|
|
uint16_t source_word_x; /* first queried word within the original upload */
|
|
uint16_t source_y;
|
|
} HdTextureMatch;
|
|
|
|
/* explicit_root wins. When it is NULL/empty, PSXRECOMP_HD_TEXTURE_ROOT is
|
|
* consulted. Accepts either:
|
|
* root/Hashes.ini + exactly one <name>-texture-replacements directory, or
|
|
* the replacement directory directly (Hashes.ini is read from it or parent).
|
|
* Returns 1 on success and leaves *out_pack NULL on failure. */
|
|
int hd_texture_pack_create(const char* explicit_root,
|
|
HdTexturePack** out_pack,
|
|
char* error,
|
|
size_t error_capacity);
|
|
void hd_texture_pack_destroy(HdTexturePack* pack);
|
|
void hd_texture_pack_get_info(const HdTexturePack* pack,
|
|
HdTexturePackInfo* out_info);
|
|
|
|
/* Key-only lookup. Ambiguous numeric aliases (for example 1-2.png and
|
|
* 00000001-2.png) deliberately return AMBIGUOUS instead of selecting by
|
|
* directory enumeration order. */
|
|
int hd_texture_pack_lookup(const HdTexturePack* pack,
|
|
uint32_t texture_hash,
|
|
uint32_t palette_hash,
|
|
HdTexturePackEntry* out_entry);
|
|
|
|
/* The pack's identity: a hash of its replacement keys (nonzero), equal for
|
|
* two loads of the same pack. Binds saved residency to the pack. */
|
|
uint32_t hd_texture_pack_identity(const HdTexturePack* pack);
|
|
/* 1 when any replacement (any palette) is keyed by this upload hash. */
|
|
int hd_texture_pack_has_texture(const HdTexturePack* pack, uint32_t texture_hash);
|
|
|
|
/* Standard reflected IEEE CRC-32 (polynomial 0xEDB88320, initial/final XOR
|
|
* 0xFFFFFFFF), feeding each uint16_t explicitly low byte then high byte. */
|
|
uint32_t hd_texture_crc32_words_le(const uint16_t* words, size_t word_count);
|
|
|
|
/* Hashes the complete live CLUT: 16 entries for 4bpp or 256 for 8bpp. CLUT X
|
|
* wraps at 1024 and Y wraps at 512. 16bpp has no palette and returns zero. */
|
|
uint32_t hd_texture_hash_clut(const uint16_t* vram,
|
|
size_t vram_word_count,
|
|
uint16_t clut_x,
|
|
uint16_t clut_y,
|
|
uint8_t depth);
|
|
|
|
/* 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,
|
|
uint16_t width_words,
|
|
uint16_t height,
|
|
const uint16_t* words,
|
|
size_t word_count,
|
|
uint32_t* out_texture_hash);
|
|
void hd_texture_pack_invalidate(HdTexturePack* pack,
|
|
uint16_t x,
|
|
uint16_t y,
|
|
uint16_t width_words,
|
|
uint16_t height);
|
|
void hd_texture_pack_reset_tracking(HdTexturePack* pack);
|
|
|
|
/* Beetle-style upload residency is host metadata, but it is required for an
|
|
* HD replacement to keep matching after a savestate restores the same VRAM.
|
|
* The portable little-endian state below records only upload identity and the
|
|
* surviving residency fragments; decoded images and GL objects remain caches.
|
|
* save allocates with malloc (caller frees). A NULL pack serializes a valid
|
|
* empty tracker so states remain renderer-independent. check is side-effect
|
|
* free; load has strong replacement semantics and also accepts a NULL pack
|
|
* after validating the wire. */
|
|
int hd_texture_pack_tracking_state_save(const HdTexturePack* pack,
|
|
uint8_t** out_data,
|
|
size_t* out_size);
|
|
int hd_texture_pack_tracking_state_check(const uint8_t* data,
|
|
size_t size);
|
|
int hd_texture_pack_tracking_state_load(HdTexturePack* pack,
|
|
const uint8_t* data,
|
|
size_t size);
|
|
size_t hd_texture_pack_tracking_upload_count(const HdTexturePack* pack);
|
|
|
|
/* Matches only when one uniquely-keyed tracked upload still contains every
|
|
* word touched by the texture page/depth/UV query. Any pack-key or residency
|
|
* ambiguity falls back explicitly via HD_TEXTURE_LOOKUP_AMBIGUOUS. */
|
|
int hd_texture_pack_match(HdTexturePack* pack,
|
|
const HdTextureDrawQuery* query,
|
|
HdTextureMatch* out_match);
|
|
|
|
/* Live GP0 draw adapter: derives page_x/page_y/depth from the PS1 texpage word
|
|
* and applies the same deterministic residency/CLUT/UV match above. This keeps
|
|
* the renderer's texpage interpretation in the focused unit-test surface. */
|
|
int hd_texture_pack_match_draw(HdTexturePack* pack,
|
|
uint16_t texpage,
|
|
uint16_t clut_x,
|
|
uint16_t clut_y,
|
|
uint8_t u_first,
|
|
uint8_t u_last,
|
|
uint8_t v_first,
|
|
uint8_t v_last,
|
|
const uint16_t* vram,
|
|
size_t vram_word_count,
|
|
HdTextureMatch* out_match);
|
|
|
|
/* Optional, bounded, single-worker on-demand PNG decode cache. The request is
|
|
* asynchronous and low-priority on Windows. request_decode returns FOUND when
|
|
* already ready, NONE when queued/in flight, and ERROR for an absent,
|
|
* ambiguous, failed, or over-budget image. acquire_decoded returns FOUND only
|
|
* when ready. A lease keeps pixels alive across cache eviction and pack
|
|
* destruction; always release it with hd_texture_pixels_release. */
|
|
typedef struct HdTexturePixels {
|
|
const uint8_t* rgba;
|
|
uint32_t width;
|
|
uint32_t height;
|
|
uint32_t stride;
|
|
void* lease;
|
|
} HdTexturePixels;
|
|
|
|
void hd_texture_pack_set_decode_budget(HdTexturePack* pack,
|
|
size_t budget_bytes);
|
|
/* Elective full preload: decode unambiguous replacements up front and pin
|
|
* them, bounded by max_bytes of decoded RGBA in aggregate and by max_threads
|
|
* concurrent decodes (the caller's thread included). Pinned images are kept
|
|
* outside the on-demand decode budget, which stays as configured. Images not
|
|
* preloaded (over the cap, unreadable, malformed, a worker failure) are left
|
|
* to the normal asynchronous, budgeted decode path; nothing is marked failed
|
|
* by the preload. Returns 1 when every image was preloaded, 0 for a partial
|
|
* preload (see out), -1 on error. Repeated calls count already pinned images
|
|
* without reading/decoding them again; max_bytes caps the pack's total pinned
|
|
* residency. A cap smaller than existing residency is rejected with -1 and
|
|
* the existing residency reported; it does not discard live pinned images. */
|
|
typedef struct HdTexturePreloadResult {
|
|
int requested; /* unambiguous replacements considered */
|
|
int loaded; /* resident and pinned, including earlier calls */
|
|
int over_budget; /* skipped: the aggregate max_bytes was reached */
|
|
int failed; /* unreadable, malformed, too large, or worker error */
|
|
int worker_errors; /* of failed: a decode that threw (caught) */
|
|
size_t bytes; /* total decoded RGBA pinned by this pack */
|
|
} HdTexturePreloadResult;
|
|
int hd_texture_pack_preload(HdTexturePack* pack, size_t max_bytes,
|
|
unsigned max_threads, HdTexturePreloadResult* out);
|
|
int hd_texture_pack_request_decode(HdTexturePack* pack,
|
|
uint32_t texture_hash,
|
|
uint32_t palette_hash);
|
|
int hd_texture_pack_acquire_decoded(HdTexturePack* pack,
|
|
uint32_t texture_hash,
|
|
uint32_t palette_hash,
|
|
HdTexturePixels* out_pixels);
|
|
void hd_texture_pixels_release(HdTexturePixels* pixels);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PSXRECOMP_HD_TEXTURE_PACK_H */
|