mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Send Ocarina 1.1.1's one-shot zstd decodes to the host decoder, switched on by zstd_native = 1 until a check run.
A profile of a play session showed the game's own zstd decoder, lifted from ARM64, taking 16 to 19% of all running CPU time on the loading threads: the patch set that sends decodes to the host's libzstd had sites for 1.4.3 only. recomp/patches-v111.txt now has the three calls of ZSTD_decompressMultiFrame (main+0xeb380) of this build, checked against its main by the generator; a lift with them changes three chunks. ov_zstd.c takes the guest function's address by game version. The sites have not been through a check run on this build, and 1.4.3 has a caller that relies on the game decoder's own result, so on 1.1.1 the host function passes every call on to the game's decoder unless zstd_native = 1 is set or zstd_check = 1 runs both and logs what differs. The loading threads' stream feed (main+0xf5c80), which decodes most of the data, is not replaced yet. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -154,7 +154,8 @@
|
||||
# made again within a few frames. The first start after changing it builds the pipelines again. 0: such textures stay.
|
||||
# tex_disuse = 1
|
||||
# Host zstd decoder in place of the game's (0 = the game's), and a check that decodes every call both ways and logs
|
||||
# the differences (1 = on; slow).
|
||||
# the differences (1 = on; slow). Ocarina of Time 1.1.1 keeps the game's decoder while zstd_native is unset: its host
|
||||
# decoding has not been through a check run yet, so there it takes zstd_native = 1 (or the check) to turn it on.
|
||||
# zstd_native = 1
|
||||
# zstd_check = 0
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ set wide_hud NX2NAVI_PATCH_WIDE_HUD 0
|
||||
set wide_movie NX2NAVI_PATCH_WIDE_MOVIE 0
|
||||
set res_fixed NX2NAVI_PATCH_RES_FIXED 0
|
||||
set ostep NX2NAVI_OCARINA_REALTIME 1
|
||||
set zstd NX2NAVI_ZSTD_NATIVE 1
|
||||
|
||||
# Real-time step: the framework's per-frame update (main+0x6e6be0) gives the time manager **[main+0x4c7e890] its
|
||||
# nominal frame through main+0x3b4e300 (+0x10 frames per update, +0x14 the inverse, +0x18 seconds, +0x1c the rate),
|
||||
@@ -88,3 +89,13 @@ site wide_hud main 774368 ad401041 ad401041 @page:x16 fd404a10 6e040431 6e0c2491
|
||||
# Pre-rendered movies: the movie layer's draw (main+0x3b5c71c) builds a viewport over the whole picture (sead viewport
|
||||
# at x29 - 40: min x +8, max x +16); it moves in by the page's margin on each side, the middle 16:9 of the picture.
|
||||
site wide_movie main 3b5c758 a941a269 d100a3b0 bd400a10 bd401211 1e303a32 @page:x17 bd40c233 1e330a52 1e322a10 1e323a31 bd000a10 bd001211 a941a269 # movie layer viewport: ldp x9, x8, [x19, #0x18]
|
||||
|
||||
# The game's zstd decoder (BSD zstd, statically linked into main) through the host's libzstd (runtime/ov_zstd.c): the
|
||||
# three calls of ZSTD_decompressMultiFrame (main+0xeb380: dctx, dst, capacity, src, size, dict, dict size, ddict) go to
|
||||
# the host function on the patch page (+0xff0). main+0xe910c is the file loader's call for a file that fits one read
|
||||
# chunk. Until a check run has compared the two decoders on this build, the host function passes every call on to the
|
||||
# game's decoder unless zstd_native = 1 is set (ov_zstd.c trusted). The loading threads' stream feed (main+0xf5c80,
|
||||
# called at main+0xf5c2c) decodes most of the data and is not replaced yet.
|
||||
site zstd main e910c 9400089d 9536dfb9 # bl ZSTD_decompressMultiFrame -> page+0xff0
|
||||
site zstd main bf72e0 97d3d028 950aa744 # bl ZSTD_decompressMultiFrame -> page+0xff0
|
||||
site zstd main f50164 97c66c87 94fd43a3 # bl ZSTD_decompressMultiFrame -> page+0xff0
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
// - Inputs of at least AWAY_BYTES give the virtual core up while they decode (other guest threads run on it).
|
||||
// NX2NAVI_ZSTD_NATIVE=0 keeps the guest decoder (the patch set switch); NX2NAVI_ZSTD_CHECK=1 decodes each call both ways,
|
||||
// keeps the guest's result and logs every call where the two differ.
|
||||
//
|
||||
// Ocarina of Time 1.1.1 has the same decoder at other addresses (recomp/patches-v111.txt: three calls of
|
||||
// ZSTD_decompressMultiFrame, main+0xeb380). Its sites have not been through a check run yet, and 1.4.3 has a caller
|
||||
// whose result the game relies on being the game decoder's own, so on that build the host decodes only when
|
||||
// zstd_native = 1 is set outright or the check runs (trusted); an unset key sends every call on to the game's decoder.
|
||||
// Its loading threads decode most data through the game's stream feed (main+0xf5c80), which is not replaced yet.
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -28,8 +34,8 @@
|
||||
|
||||
#ifdef RT_PATCH_PAGE
|
||||
|
||||
#define GUEST_MULTIFRAME 0x700003a1f0ull // 1.4.3 main: ZSTD_decompressMultiFrame (only 1.4.3 has the patch sites)
|
||||
#define GUEST_USING_DDICT 0x700003a1e0ull // ZSTD_decompress_usingDDict
|
||||
#define GUEST_MULTIFRAME (rt_game_version == 111 ? 0x70000eb380ull : 0x700003a1f0ull) // ZSTD_decompressMultiFrame: 1.1.1, 1.4.3
|
||||
#define GUEST_USING_DDICT 0x700003a1e0ull // 1.4.3 main: ZSTD_decompress_usingDDict (1.1.1 has no site for it)
|
||||
#define HOST_MULTIFRAME (RT_PATCH_PAGE + 0xff0)
|
||||
#define HOST_USING_DDICT (RT_PATCH_PAGE + 0xfe0)
|
||||
#define AWAY_BYTES (64u << 10)
|
||||
@@ -165,12 +171,29 @@ static void count(uint64_t in, uint64_t out, uint64_t ns) {
|
||||
(unsigned long long)S.inplace, (unsigned long long)S.away);
|
||||
}
|
||||
|
||||
// Whether this build's sites may decode on the host: always but on 1.1.1, where it takes zstd_native = 1 in the
|
||||
// settings or the check (see the top of the file).
|
||||
static int trusted(void) {
|
||||
static int v = -1;
|
||||
if (v < 0) {
|
||||
const char *e = cfg_get("NX2NAVI_ZSTD_NATIVE");
|
||||
v = rt_game_version != 111 || (e && *e && strcmp(e, "0") != 0) || check_mode();
|
||||
if (!v) rt_log("zstd: the game's own decoder (the host decoder is not checked on this build yet: zstd_native = 1 "
|
||||
"turns it on, zstd_check = 1 compares the two)");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// x0 dctx, x1 dst, x2 capacity, x3 src, x4 size, then (dict, dict size, ddict) as the entry has them. guest: the
|
||||
// guest function with the same arguments, n of them.
|
||||
static void decode(Cpu *c, uint64_t dict, uint64_t dict_size, uint64_t ddict, uint64_t guest, int n) {
|
||||
uint64_t a[8];
|
||||
memcpy(a, c->x, sizeof a);
|
||||
uint64_t dst = a[1], cap = a[2], src = a[3], size = a[4];
|
||||
if (!trusted()) {
|
||||
rt_call(c, guest, n, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
|
||||
return;
|
||||
}
|
||||
// In place (the input inside the output buffer): the result depends on how the decoder's writes overtake its
|
||||
// reads, which libzstd does not promise to do as the game's version does, and a host decode that failed half way
|
||||
// would leave the guest decoder a damaged input. Such calls stay in the guest.
|
||||
|
||||
Reference in New Issue
Block a user