From 606d6eaa9682fdacb499e390464c944aaf91c3c6 Mon Sep 17 00:00:00 2001 From: baromas Date: Sat, 7 Nov 2026 22:59:50 +0300 Subject: [PATCH] fix: invalidate stale texture IDs when the base is missing When the base and the cached view parent are both nil, pointer equality cannot revalidate the cached resource ID. Verify the missing-base case with the production Metal texture retirement probe. --- games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m b/games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m index 7ebd0348f..d70484d27 100644 --- a/games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m +++ b/games/totk/third_party/d2r_gfx/gfx/nvn/nvn_mtl.m @@ -6723,7 +6723,8 @@ static void life_use(int tid, const tex_t *t, const char *how) { if (rp->view) { // 序号表或客体内存有过变动:核基贴图是否被重传换新,换了则视图作废 | The serial table or guest memory has changed: check whether the base texture was re-uploaded and replaced; if so the view is invalidated __unsafe_unretained id cur = tex_mtl(&rp->t); // held by the serial table / its NvPkg if (g_tex_prepare_split) return NULL; - if ((__bridge void *)cur == rp->view || (__bridge void *)cur == rp->view_parent) { rp->view_ser = sg; rp->view_pkg = treg_kind(&rp->t); rp->view_dirty = rp->view_pkg == 2 || (rp->view_pkg == 1 && tex_check_once()) ? g_sub_serial : dg; return rp->view; } + /* A missing base must not validate a cached view with no parent. */ + if (cur && ((__bridge void *)cur == rp->view || (__bridge void *)cur == rp->view_parent)) { rp->view_ser = sg; rp->view_pkg = treg_kind(&rp->t); rp->view_dirty = rp->view_pkg == 2 || (rp->view_pkg == 1 && tex_check_once()) ? g_sub_serial : dg; return rp->view; } treg_clear_view_locked(tid); } id v = nil; @@ -18244,6 +18245,13 @@ int mtl_probe_texture_retire(void) { mtl_sub_commit();mtl_finish();for(unsigned i=0;i<128;i++){if(((uint8_t *)rb.contents)[i]!=expected[i])MDIE("texture retire rebuilt view pixel%u",i);checked++;} mtl_sub_begin();mtl_exec((const uint8_t *)&end);mtl_sub_commit();mtl_finish(); if(replaced_type)MDIE("texture retire: replaced type view retained after GPU completion");checked++; + registry_lock(); + if(!g_treg[1].view||g_treg[1].view_parent)MDIE("texture retire: missing-base fixture needs a standalone cached texture"); + g_treg[1].t.serial=0; + g_treg[1].dead_pending=1; + if(tex_by_id_p(1)||g_treg[1].view_rid)MDIE("texture retire: missing base revalidated a stale resource ID"); + g_treg[1].t.serial=t.serial; + registry_unlock();checked++; mtl_tex_release(&t); registry_lock(); for(unsigned i=1;i<=N*2;i++) { if(g_treg[i].view||g_treg[i].indexed_serial)MDIE("texture retire: finalized serial kept descriptor %u",i);checked++; }