[iterate-3V] Fix logo texture: map texture-fetch physical base onto backing window

The publisher-logo texture (K8888 1280x768 linear, `E59B2B3D`'s tfetch
surface) rendered flat/transparent because the GPU texture decode read
the wrong host bytes — NOT because the asset was never decompressed.

First-divergence (vs canary, measured both engines):
- Ours DOES read game:\hidden\Resource3D\*.xpr in full, builds a
  byte-identical cache, decompresses the logo, and CPU-writes the real
  artwork (~839K nonzero bytes) into the texture buffer — at the guest
  physical-aperture VA 0x4dbee000 (writer sub_823C3E70 @ 0x823c3f8c).
  This REFUTES the iterate-3U verdict that the texture was never filled.
- BUT the GPU decode used the raw fetch-constant base 0x0dbee000 as a
  virtual address. In ours' flat 4GB memory, virtual 0x0dbee000 and the
  physical alias 0x4dbee000 are DIFFERENT host bytes (no aliasing in the
  read/write path), so the decode read all-zeros.

The Xenos texture fetch constant carries a guest *physical* base; the
CPU writes texels through its cached-physical aperture, which ours backs
at the committed 0x4000_0000 window. Map the base via the existing
`physical_to_backing` helper before reading — exactly as the vertex
fetch path (draw_capture.rs, iterate-3Q) and as canary reads textures
through its GPU shared memory (= physical).

Measured after fix (env-gated probe, removed): the logo decode reads
base=0x4dbee000 and produces 839068/3932160 nonzero bytes (21.3%) — a
centered logo on a transparent field, matching canary's ~21% exactly.

Determinism: GPU-side pure read; no CPU/guest-memory state changes. The
n50m --gpu-inline --stable-digest golden is byte-identical (verified 2x,
texture_cache_entries unchanged). cargo test --workspace green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-18 18:07:00 +02:00
parent 1b9918450f
commit da7c29b6d2

View File

@@ -1385,9 +1385,24 @@ impl GpuSystem {
.register_file
.read(CONST_BASE_FETCH + slot as u32 * 6 + k as u32);
}
let Some(key) = crate::texture_cache::decode_fetch_constant(fetch6) else {
let Some(mut key) = crate::texture_cache::decode_fetch_constant(fetch6) else {
continue;
};
// The Xenos texture fetch constant carries a guest
// *physical* base address (`base >> 12`). On the Xbox
// 360 the GPU reads the unified physical memory; the
// CPU writes the (decompressed) texels through its
// cached-physical aperture, which ours backs at the
// committed `0x4000_0000` window. Map the physical
// base onto that backing window so the GPU samples the
// bytes the guest actually wrote — exactly as the
// vertex-fetch path does (`draw_capture.rs`) and as
// canary reads textures through its GPU shared memory
// (= physical). Without this the decode reads the
// low VA `0x0dbee000` (always zero) instead of the
// filled `0x4dbee000`, flattening every disk-asset
// texture (e.g. the publisher logo `E59B2B3D`).
key.base_address = physical_to_backing(key.base_address);
let bi = key.format.block_info();
let span_bytes = (key.pitch_texels as u32)
* (key.height as u32)