Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ Fetched or linked at build time (not in this repository):
| [ALVR](https://github.com/alvr-org/ALVR) client v20.14.0, downloaded (SHA-256 checked) and installed on the headset by `zeldaVR/install_vr.sh` | shows the VR picture on the Meta Quest 3 | MIT |
| [Noto Sans CJK SC](https://github.com/notofonts/noto-cjk) (Source Han Sans) DemiLight at `165c01b`, downloaded and checked by `windows_games/ra2/scripts/languages.py` | the Simplified Chinese glyphs it draws into the player's game font | SIL OFL 1.1 |
| [OpenCC](https://github.com/BYVoid/OpenCC), run (not included) by `windows_games/ra2/scripts/languages.py` | Traditional to Simplified Chinese | Apache-2.0 |

OoT movie diagnostic: command-sequence matching adapted from [nxnative PR #1331](https://github.com/seedds/nxnative/pull/1331), `76c20edba480db753ce7092cd2677f6c4a8daa15`, MIT (`games/totk/third_party/licenses/nxnative.txt`).
6 changes: 5 additions & 1 deletion games/totk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ verify-boot: runtime



GFX_HEADERS := $(wildcard third_party/d2r_gfx/gfx/nvn/*.h third_party/d2r_gfx/gfx/nvn/include/*.h third_party/d2r_gfx/host/*.h zeldaVR/gfx/*.h zeldaVR/runtime/*.h)
GFX_HEADERS := third_party/d2r_gfx/gfx/nvn/oot_movie_direct.inc third_party/d2r_gfx/gfx/nvn/oot_movie_probe.inc $(wildcard third_party/d2r_gfx/gfx/nvn/*.h third_party/d2r_gfx/gfx/nvn/include/*.h third_party/d2r_gfx/host/*.h zeldaVR/gfx/*.h zeldaVR/runtime/*.h)

build/gfx/%.o: % $(GFX_HEADERS) Makefile
@mkdir -p "$(dir $@)"
Expand Down Expand Up @@ -515,6 +515,10 @@ build/totk-native-oot: $(wildcard runtime/*.[ch] runtime/*.m runtime/*.S) $(GFX_
runtime-oot binary-oot: SHADER_LIST ?= ../oot/assets/shader_list.tsv
binary-oot: build/totk-native-oot build/pso_manifest.tsv build/pso_title.tsv
runtime-oot: binary-oot game-data-oot

.PHONY: probe-gpu-oot-movie
probe-gpu-oot-movie: build/totk-native-oot
MTL_DEBUG_LAYER=1 MTL_DEBUG_LAYER_ERROR_MODE=assert TOTK_HEADLESS=1 TOTK_OOT_MOVIE_DIRECT=1 build/totk-native-oot rewritten/oot $@
# Production Opus-wrapper regression checks; no game assets or audio device needed.
OPUS_TEST_WORK ?= /tmp/totk-native-opus-codec
OPUS_PREFIX ?= /opt/homebrew/opt/opus
Expand Down
3 changes: 2 additions & 1 deletion games/totk/runtime/gpu_path_probe.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
#include <string.h>

void runtime_gpu_path_probe(const char *which) {
int checked = !strcmp(which, "probe-gpu-writeback") ? mtl_probe_writeback() : !strcmp(which, "probe-gpu-sampler-border") ? mtl_probe_sampler_border() : !strcmp(which, "probe-gpu-pool-retire") ? mtl_probe_pool_retire() : !strcmp(which, "probe-gpu-tex-slots") ? mtl_probe_tex_slots() : !strcmp(which, "probe-gpu-arg-epoch") ? mtl_probe_arg_epoch() : !strcmp(which, "probe-gpu-anomaly") ? mtl_probe_anomaly() : !strcmp(which, "probe-gpu-vertex-streams") ? mtl_probe_vertex_streams() : !strcmp(which, "probe-gpu-vin") ? mtl_probe_vertex_input_types() : !strcmp(which, "probe-gpu-fout") ? mtl_probe_fragment_output_types() : !strcmp(which, "probe-gpu-pipeline-archive") ? mtl_probe_pipeline_archive() : !strcmp(which, "probe-gpu-layer-merge") ? mtl_probe_layer_merge() : !strcmp(which, "probe-gpu-cube-merge") ? mtl_probe_cube_merge() : !strcmp(which, "probe-gpu-texture-retire") ? mtl_probe_texture_retire() : !strcmp(which, "probe-gpu-texels-region") ? mtl_probe_texels_region() : !strcmp(which, "probe-gpu-linear-rt") ? mtl_probe_linear_rt_upload() : !strcmp(which, "probe-gpu-storage-view") ? mtl_probe_storage_view() : !strcmp(which, "probe-gpu-compressed-alias") ? mtl_probe_compressed_alias() : !strcmp(which, "probe-gpu-upload-batch") ? mtl_probe_upload_batch() : !strcmp(which, "probe-gpu-ds-clear") ? mtl_probe_ds_clear() : !strcmp(which, "probe-gpu-ub-rename") ? mtl_probe_ub_rename() : !strcmp(which, "probe-gpu-ubo-snapshot") ? mtl_probe_ubo_snapshot() : !strcmp(which, "probe-gpu-drv-c0") ? mtl_probe_drv_c0() : !strcmp(which, "probe-gpu-copy-alias") ? mtl_probe_copy_alias() : !strcmp(which, "probe-gpu-dispatch-chain") ? mtl_probe_dispatch_chain() : !strcmp(which, "probe-gpu-srgb-view") ? mtl_probe_srgb_view() : !strcmp(which, "probe-gpu-depth-output") ? mtl_probe_depth_output() : !strcmp(which, "probe-gpu-widen") ? mtl_probe_widen() : !strcmp(which, "probe-gpu-midclear") ? mtl_probe_midclear() : !strcmp(which, "probe-gpu-winding") ? mtl_probe_winding() : !strcmp(which, "probe-gpu-tile") ? mtl_probe_tile() : mtl_probe_blockrt();
int checked = !strcmp(which, "probe-gpu-oot-movie") ? mtl_probe_oot_movie() : !strcmp(which, "probe-gpu-writeback") ? mtl_probe_writeback() : !strcmp(which, "probe-gpu-sampler-border") ? mtl_probe_sampler_border() : !strcmp(which, "probe-gpu-pool-retire") ? mtl_probe_pool_retire() : !strcmp(which, "probe-gpu-tex-slots") ? mtl_probe_tex_slots() : !strcmp(which, "probe-gpu-arg-epoch") ? mtl_probe_arg_epoch() : !strcmp(which, "probe-gpu-anomaly") ? mtl_probe_anomaly() : !strcmp(which, "probe-gpu-vertex-streams") ? mtl_probe_vertex_streams() : !strcmp(which, "probe-gpu-vin") ? mtl_probe_vertex_input_types() : !strcmp(which, "probe-gpu-fout") ? mtl_probe_fragment_output_types() : !strcmp(which, "probe-gpu-pipeline-archive") ? mtl_probe_pipeline_archive() : !strcmp(which, "probe-gpu-layer-merge") ? mtl_probe_layer_merge() : !strcmp(which, "probe-gpu-cube-merge") ? mtl_probe_cube_merge() : !strcmp(which, "probe-gpu-texture-retire") ? mtl_probe_texture_retire() : !strcmp(which, "probe-gpu-texels-region") ? mtl_probe_texels_region() : !strcmp(which, "probe-gpu-linear-rt") ? mtl_probe_linear_rt_upload() : !strcmp(which, "probe-gpu-storage-view") ? mtl_probe_storage_view() : !strcmp(which, "probe-gpu-compressed-alias") ? mtl_probe_compressed_alias() : !strcmp(which, "probe-gpu-upload-batch") ? mtl_probe_upload_batch() : !strcmp(which, "probe-gpu-ds-clear") ? mtl_probe_ds_clear() : !strcmp(which, "probe-gpu-ub-rename") ? mtl_probe_ub_rename() : !strcmp(which, "probe-gpu-ubo-snapshot") ? mtl_probe_ubo_snapshot() : !strcmp(which, "probe-gpu-drv-c0") ? mtl_probe_drv_c0() : !strcmp(which, "probe-gpu-copy-alias") ? mtl_probe_copy_alias() : !strcmp(which, "probe-gpu-dispatch-chain") ? mtl_probe_dispatch_chain() : !strcmp(which, "probe-gpu-srgb-view") ? mtl_probe_srgb_view() : !strcmp(which, "probe-gpu-depth-output") ? mtl_probe_depth_output() : !strcmp(which, "probe-gpu-widen") ? mtl_probe_widen() : !strcmp(which, "probe-gpu-midclear") ? mtl_probe_midclear() : !strcmp(which, "probe-gpu-winding") ? mtl_probe_winding() : !strcmp(which, "probe-gpu-tile") ? mtl_probe_tile() : mtl_probe_blockrt();
printf("{\"status\":\"pass\",\"probe\":\"%s\",\"checked\":%d,\"scope\":\"%s\"}\n", which, checked,
!strcmp(which, "probe-gpu-oot-movie") ? "OoT matched movie reconstruction, fallback, RGBA/sRGB and output ownership" :
!strcmp(which, "probe-gpu-writeback") ? "terrain exact snapshots and BotW tiny GPU render completion write-back, CPU overwrite protection and padding" :
!strcmp(which, "probe-gpu-sampler-border") ? "production VS/FS sampler border colour switching, mixed addressing and GPU readback" :
!strcmp(which, "probe-gpu-texels-region") ? "production texel GPU region read/write, pitch guards, packed/block formats, mip/layer/volume, overlap fallback and CPU/Metal mirror visibility" :
Expand Down
2 changes: 1 addition & 1 deletion games/totk/runtime/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,5 +641,5 @@ int main(int argc,char **argv) {
#endif
verify_identity(!strcmp(argv[2],"probe-identity-negative"));
for(unsigned i=0;i<NM;i++){seal(&modules[i]);check_permissions(&modules[i]);}
if(!strcmp(argv[2],"probe-gpu-writeback")||!strcmp(argv[2],"probe-gpu-sampler-border")||!strcmp(argv[2],"probe-gpu-pool-retire")||!strcmp(argv[2],"probe-gpu-tex-slots")||!strcmp(argv[2],"probe-gpu-arg-epoch")||!strcmp(argv[2],"probe-gpu-anomaly")||!strcmp(argv[2],"probe-gpu-vertex-streams")||!strcmp(argv[2],"probe-gpu-vin")||!strcmp(argv[2],"probe-gpu-fout")||!strcmp(argv[2],"probe-gpu-pipeline-archive")||!strcmp(argv[2],"probe-gpu-layer-merge")||!strcmp(argv[2],"probe-gpu-cube-merge")||!strcmp(argv[2],"probe-gpu-texture-retire")||!strcmp(argv[2],"probe-gpu-texels-region")||!strcmp(argv[2],"probe-gpu-linear-rt")||!strcmp(argv[2],"probe-gpu-storage-view")||!strcmp(argv[2],"probe-gpu-compressed-alias")||!strcmp(argv[2],"probe-gpu-upload-batch")||!strcmp(argv[2],"probe-gpu-ds-clear")||!strcmp(argv[2],"probe-gpu-ub-rename")||!strcmp(argv[2],"probe-gpu-ubo-snapshot")||!strcmp(argv[2],"probe-gpu-drv-c0")||!strcmp(argv[2],"probe-gpu-dispatch-chain")||!strcmp(argv[2],"probe-gpu-copy-alias")||!strcmp(argv[2],"probe-gpu-srgb-view")||!strcmp(argv[2],"probe-gpu-depth-output"))runtime_gpu_path_probe(argv[2]);else if(!strcmp(argv[2],"probe-memory"))runtime_memory_probe();else if(!strcmp(argv[2],"probe-gfx"))runtime_gfx_probe(0);else if(!strcmp(argv[2],"probe-vpool"))runtime_vpool_probe();else if(!strcmp(argv[2],"probe-gpu-widen")||!strcmp(argv[2],"probe-gpu-blockrt")||!strcmp(argv[2],"probe-gpu-midclear")||!strcmp(argv[2],"probe-gpu-winding")||!strcmp(argv[2],"probe-gpu-tile"))runtime_gpu_path_probe(argv[2]);else if(!strcmp(argv[2],"probe-audio"))runtime_audio_probe();else if(!strcmp(argv[2],"probe-gfx-negative"))runtime_gfx_probe(1);else if(!strcmp(argv[2],"probe"))probe();else if(!strcmp(argv[2],"probe-fs"))runtime_fs_probe();else if(!strcmp(argv[2],"seed-shaders")){if(argc<4)runtime_fail("seed-shaders needs the corpus: <modules> seed-shaders <corpus.bin> (scripts/ns2_shader_corpus.py)");runtime_shader_seed(argv[3],argc>4?argv[4]:NULL);}else if(!strcmp(argv[2],"probe-swkbd"))runtime_swkbd_probe();else if(!strcmp(argv[2],"probe-save"))runtime_save_probe();else if(!strcmp(argv[2],"boot")){if(getenv("TOTK_VERIFY_STARTUP")||getenv("TOTK_HEADLESS"))boot();else runtime_front_run(boot);}else runtime_fail("unknown mode");return 0;
if(!strcmp(argv[2],"probe-gpu-oot-movie")||!strcmp(argv[2],"probe-gpu-writeback")||!strcmp(argv[2],"probe-gpu-sampler-border")||!strcmp(argv[2],"probe-gpu-pool-retire")||!strcmp(argv[2],"probe-gpu-tex-slots")||!strcmp(argv[2],"probe-gpu-arg-epoch")||!strcmp(argv[2],"probe-gpu-anomaly")||!strcmp(argv[2],"probe-gpu-vertex-streams")||!strcmp(argv[2],"probe-gpu-vin")||!strcmp(argv[2],"probe-gpu-fout")||!strcmp(argv[2],"probe-gpu-pipeline-archive")||!strcmp(argv[2],"probe-gpu-layer-merge")||!strcmp(argv[2],"probe-gpu-cube-merge")||!strcmp(argv[2],"probe-gpu-texture-retire")||!strcmp(argv[2],"probe-gpu-texels-region")||!strcmp(argv[2],"probe-gpu-linear-rt")||!strcmp(argv[2],"probe-gpu-storage-view")||!strcmp(argv[2],"probe-gpu-compressed-alias")||!strcmp(argv[2],"probe-gpu-upload-batch")||!strcmp(argv[2],"probe-gpu-ds-clear")||!strcmp(argv[2],"probe-gpu-ub-rename")||!strcmp(argv[2],"probe-gpu-ubo-snapshot")||!strcmp(argv[2],"probe-gpu-drv-c0")||!strcmp(argv[2],"probe-gpu-dispatch-chain")||!strcmp(argv[2],"probe-gpu-copy-alias")||!strcmp(argv[2],"probe-gpu-srgb-view")||!strcmp(argv[2],"probe-gpu-depth-output"))runtime_gpu_path_probe(argv[2]);else if(!strcmp(argv[2],"probe-memory"))runtime_memory_probe();else if(!strcmp(argv[2],"probe-gfx"))runtime_gfx_probe(0);else if(!strcmp(argv[2],"probe-vpool"))runtime_vpool_probe();else if(!strcmp(argv[2],"probe-gpu-widen")||!strcmp(argv[2],"probe-gpu-blockrt")||!strcmp(argv[2],"probe-gpu-midclear")||!strcmp(argv[2],"probe-gpu-winding")||!strcmp(argv[2],"probe-gpu-tile"))runtime_gpu_path_probe(argv[2]);else if(!strcmp(argv[2],"probe-audio"))runtime_audio_probe();else if(!strcmp(argv[2],"probe-gfx-negative"))runtime_gfx_probe(1);else if(!strcmp(argv[2],"probe"))probe();else if(!strcmp(argv[2],"probe-fs"))runtime_fs_probe();else if(!strcmp(argv[2],"seed-shaders")){if(argc<4)runtime_fail("seed-shaders needs the corpus: <modules> seed-shaders <corpus.bin> (scripts/ns2_shader_corpus.py)");runtime_shader_seed(argv[3],argc>4?argv[4]:NULL);}else if(!strcmp(argv[2],"probe-swkbd"))runtime_swkbd_probe();else if(!strcmp(argv[2],"probe-save"))runtime_save_probe();else if(!strcmp(argv[2],"boot")){if(getenv("TOTK_VERIFY_STARTUP")||getenv("TOTK_HEADLESS"))boot();else runtime_front_run(boot);}else runtime_fail("unknown mode");return 0;
}
1 change: 1 addition & 0 deletions games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ int mtl_probe_srgb_view(void);
int mtl_probe_storage_view(void);
int mtl_probe_compressed_alias(void);
int mtl_probe_linear_rt_upload(void);
int mtl_probe_oot_movie(void);
int mtl_probe_texels_region(void);
int mtl_probe_texture_retire(void);
int mtl_probe_ds_clear(void);
Expand Down
24 changes: 22 additions & 2 deletions games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,12 @@ static void b2_scene_shot(int eye) { // diagnostic: the eye's own last pass ta
else MLOG("[vr] b2shot: this eye pass drew no presented texture"); }
}
void mtl_eye_capture(int eye) { g_b2_capture = eye; }
static id<MTLTexture> g_oot_movie_decoded;
static uint64_t g_oot_movie_sub;
static const uint8_t *g_oot_movie_skip_end;
void mtl_sub_begin(void) {
g_oot_movie_decoded = nil;
g_oot_movie_skip_end = NULL;
g_eye_region = 3; // stereo B2: a submission starts outside eye marks
g_fc_begin0 = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
/* The submission's autorelease pool, drained in mtl_sub_commit, opens before anything else: the guest's submit
Expand Down Expand Up @@ -14934,7 +14939,8 @@ stages with device visibility (blit()), as the end / start barriers of two encod
if (g_disp_n % 20000 == 0) MLOG("[nvn] 计算派发 至 %llu 次:其中 %llu 次(%.0f%%)接在已开的计算编码器里,没有另开编码器", (unsigned long long)g_disp_n, (unsigned long long)g_disp_shared, 100.0 * (double)g_disp_shared / (double)g_disp_n);
return g_blit;
}
static void dispatch(const p_dispatch *dp) {
#include "oot_movie_direct.inc"
static void dispatch_at(const p_dispatch *dp, const uint8_t *next) {
zskip_clear();
const prog_t *cp = S.cprog ? S.cprog : S.prog; // the compute program (S.cprog); a probe that sets S.prog only, as before
if (!cp) { RED_ONCE(27, "派发前没有绑定程序"); return; }
Expand All @@ -14945,6 +14951,9 @@ static void dispatch(const p_dispatch *dp) {
if (cpr->missing) { static uint64_t n; if (!n++) MLOG("[shader-miss] 计算着色器还没翻译:跳过这个派发(以后同类不再提示)"); return; }
NvShader *cs = cpr->sh[5];
if (!cs) { RED_ONCE(28, "派发的程序没有计算着色器(或未映射)"); return; }
int movie = oot_movie_enabled() && dp->x > 0 && dp->y > 0 && dp->z == 1 ? oot_movie_role(cs->key) : 0;
if (movie == 1) g_oot_movie_decoded = nil;
if (movie == 2 && oot_movie_replace(cs)) return;
/* TOTK_SKIP_CS=all | <key prefix>[,<key prefix>...] (diagnostic): those compute dispatches are not run (bisecting a
GPU hang to its shader); TOTK_SKIP_CS_LOG=1 names each compute shader once as it is first dispatched. */
{ static char list[16][17]; static int nl = -1, all, logk; static NSMutableSet *seen;
Expand Down Expand Up @@ -15028,6 +15037,10 @@ first waits for the encode stage to finish that pass (rs_sync, ~5% of the replay
if (atomic_load(&g_draw_log) > 0) MLOG("[uw] F%llu pass %llu dispatch cs %.16s grid %dx%dx%d", (unsigned long long)atomic_load(&g_cur_frame), g_stat_pass, cs->key, dp->x, dp->y, dp->z);
enc_c_dispatch(ce, MTLSizeMake(dp->x, dp->y, dp->z), MTLSizeMake(tg[0], tg[1], tg[2]));
if (!reuse) enc_c_end(ce);
if (movie == 1) {
oot_movie_remember(cs);
g_oot_movie_skip_end = oot_movie_try_network(next);
}
bright_lut(cs); // 3D 画面加亮:游戏算完调色表之后重写 | 3D picture brightening: rewrite after the game finishes computing the color lookup table
/* TOTK_EXPO_LOG=<file> (diagnostic): after each dispatch of the exposure kernel (ae725063), copy floats 96..127 of its
storage buffer 0 (statistics; exposure at 108..111) into a shared ring and write them with the frame number once
Expand All @@ -15045,6 +15058,7 @@ first waits for the encode stage to finish that pass (rs_sync, ~5% of the replay
}
// GPU:贴图 → 缓冲(行距取 SetCopyRowStride,0 = 紧排)
// GPU: texture -> buffer (row stride taken from SetCopyRowStride, 0 = tightly packed)
static void dispatch(const p_dispatch *dp) { dispatch_at(dp, NULL); }
static void copy_t2b(const p_copy_b2t *c) {
{ static long on = -1; static int left = 24; if (on < 0) { const char *e = getenv("TOTK_T2T_LOG"); on = e ? atol(e) : 0; if (e && !on) on = 1; } // with TOTK_T2T_LOG: buffer <-> texture copies too
if (on > 0 && (long)atomic_load(&g_cur_frame) >= on && left > 0 && c->tex) { left--;
Expand Down Expand Up @@ -15766,7 +15780,11 @@ void mtl_exec(const uint8_t *p) {
case OP_COPY_T2B: copy_t2b(a); break;
case OP_COPY_T2T: copy_t2t(a); break;
case OP_CLEAR_TEX: clear_tex(a); break;
case OP_DISPATCH: dispatch(a); break;
case OP_DISPATCH:
if (g_oot_movie_skip_end) {
if (p == g_oot_movie_skip_end) g_oot_movie_skip_end = NULL;
} else dispatch_at(a, p + h.size);
break;
case OP_SET_TEX_POOL: { const dpool_t *tp = ((const p_set_pool *)a)->pool; extern int nvn_tex_pool_base(const void *pool); // hle_nvn.c: IDs past this pool's part of the table read 0
S.tex_pool_n = tp ? nvn_tex_pool_base(tp) + tp->n : 0; break; }
case OP_BARRIER: case OP_SET_SAMP_POOL: break;
Expand Down Expand Up @@ -18171,6 +18189,8 @@ int mtl_probe_compressed_alias(void) {

/* CPU-visible linear-render-target textures contain ordinary pool data until the GPU writes them.
Exercise both water-height formats, cold sampling, a CPU texel update, and subsequent GPU rendering. */
#include "oot_movie_probe.inc"

int mtl_probe_linear_rt_upload(void) {
mtl_init();int checked=0;
for(int mode=0;mode<2;mode++) {
Expand Down
Loading