mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 17:09:57 -04:00
The prepared list named its shader variants and nothing about where they came from, so an update that keeps the prepared shaders (shader_carry) kept the old list whatever seed the new kit writes: variants only the new seed names, from a newer pipeline list or a change to which variants are prepared, were translated when play first drew them. The existing identities do not cover this: nx2navi_xlate.id and identities.txt name translators, which decide cache keys and what is carried over, not which variants are listed. The list is now version 2 (runtime/prp_file.h): after the head come the sha256 of seed-programs.bin, the sha256 of seed-answers.bin and the translator identity, written by gfx_shader_prepare_seed; the three readers go through gfx_shader_prepared_read and still read a version 1 list. At an update step_shaders writes the seed first (prepare_shaders.py --no-run, about 4 s) and keeps the list only when its digests are that seed's (make_game.py seed_changed); another seed, or a list that does not say, is prepared again. Another translator alone still carries over: input ids do not depend on the translator, and preparing everything again for it is what carrying was made to avoid. Checked with tests/prp_file_check.py (the C layout against make_game's reader), three launcher tests, and the exe's --prepare-shaders on a seed without records in a folder of its own: the digests it wrote are those of the seed files, one byte more in the seed reads as changed, and after preparing again it does not. A version 1 list of 42,142 variants and the same list as version 2 are both read whole by --probe-prewarm. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
67 lines
3.7 KiB
C
67 lines
3.7 KiB
C
// The layout of shader-prepared.bin, the list of shader variants a preparation translated and built ahead of play
|
|
// (runtime/gfx_shader.c gfx_shader_prepare_seed writes it; gfx_shader_warm_list and runtime/vk_pipeline.c lw_start,
|
|
// lb_warm_prepared read it; tools/make_game.py prepared_from reads its head).
|
|
//
|
|
// "NX2NSPRP", version (u32), record size (u32, 36)
|
|
// version 2 only: what the list was prepared from, 96 bytes: the sha256 of seed-programs.bin, the sha256 of
|
|
// seed-answers.bin (each over the whole file), and the translator identity (the 32 bytes of nx2navi_xlate.id,
|
|
// before the host options are mixed in)
|
|
// records: stage, priority, 2 zero bytes, input id (32 bytes); in priority order, one per input id
|
|
//
|
|
// A version 1 file has no such block: it does not say what it was prepared from. The seed decides which variants are in
|
|
// the list, and nothing else recorded it: a build that came with another seed (more shaders listed, another pipeline
|
|
// list) kept the old list, and the variants only the new seed names were translated when play first drew them. With
|
|
// the block the build compares it with the seed it has just written and prepares again when they differ
|
|
// (tools/make_game.py step_shaders). The translator identity is recorded for the same comparison; a list prepared by
|
|
// another translator is not discarded for that alone, since input ids do not depend on the translator and the game
|
|
// carries the translations over (gfx_shader.c, "Carry").
|
|
// tests/prp_file_check.py checks this header against the reader in tools/make_game.py.
|
|
#pragma once
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#define PRP_MAGIC "NX2NSPRP"
|
|
#define PRP_VERSION 2
|
|
#define PRP_REC 36
|
|
#define PRP_HEAD 16 // magic, version, record size
|
|
#define PRP_FROM_SIZE 96
|
|
|
|
typedef struct {
|
|
uint8_t programs[32]; // sha256 of seed-programs.bin
|
|
uint8_t answers[32]; // sha256 of seed-answers.bin
|
|
uint8_t translator[32]; // the translator identity
|
|
} PrpFrom;
|
|
|
|
// The head of a version 2 file into out (PRP_HEAD + PRP_FROM_SIZE bytes); returns that size.
|
|
static inline size_t prp_head_write(uint8_t *out, const PrpFrom *from) {
|
|
uint32_t v = PRP_VERSION, r = PRP_REC;
|
|
memcpy(out, PRP_MAGIC, 8), memcpy(out + 8, &v, 4), memcpy(out + 12, &r, 4);
|
|
memcpy(out + PRP_HEAD, from->programs, 32), memcpy(out + PRP_HEAD + 32, from->answers, 32);
|
|
memcpy(out + PRP_HEAD + 64, from->translator, 32);
|
|
return PRP_HEAD + PRP_FROM_SIZE;
|
|
}
|
|
|
|
// The records of the file f of size bytes: a pointer into f and their count in *n; NULL for a file that is no prepared
|
|
// list or has no whole record. *has_from: 1 with *from filled for a version 2 file, 0 for a version 1 file.
|
|
static inline const uint8_t *prp_parse(const uint8_t *f, uint64_t size, size_t *n, PrpFrom *from, int *has_from) {
|
|
uint32_t v = 0, r = 0;
|
|
*n = 0, *has_from = 0;
|
|
if (!f || size < PRP_HEAD || memcmp(f, PRP_MAGIC, 8)) return NULL;
|
|
memcpy(&v, f + 8, 4), memcpy(&r, f + 12, 4);
|
|
if (r != PRP_REC || (v != 1 && v != 2)) return NULL;
|
|
uint64_t at = PRP_HEAD;
|
|
if (v == 2) {
|
|
if (size < PRP_HEAD + PRP_FROM_SIZE) return NULL;
|
|
memcpy(from->programs, f + PRP_HEAD, 32), memcpy(from->answers, f + PRP_HEAD + 32, 32);
|
|
memcpy(from->translator, f + PRP_HEAD + 64, 32);
|
|
*has_from = 1, at += PRP_FROM_SIZE;
|
|
}
|
|
*n = (size_t)((size - at) / PRP_REC);
|
|
return *n ? f + at : NULL;
|
|
}
|
|
|
|
// runtime/gfx_shader.c: the records of the prepared list at path (PRP_REC bytes each, malloc'd; their count in *n),
|
|
// NULL without any. *from, *has_from (both optional): what a version 2 file says it was prepared from.
|
|
uint8_t *gfx_shader_prepared_read(const char *path, size_t *n, PrpFrom *from, int *has_from);
|