Merge upstream/main into openxr-work (reverse-Z fix adapted for VR)

Brings in patchzyy/Wiicompiled main: os_sleep parked-thread fix (#195),
HTTPS Retro WFC payload (#198), macOS build guide (#177), and the
reverse-Z depth fix (#134).

Conflicts were in aurora-main/lib/gfx/common.cpp and lib/gx/shader.cpp,
both from #134, which lands squarely on the VR stereo replay path.

#134 makes UseReversedZ genuinely reversed: the near/far correction now
applies exactly once, inside effective_projection(), instead of being
applied there AND per-vertex in the shader (the double application had
been cancelling out, so "reversed" Z silently behaved like forward Z).
Three pieces of the VR path were built against that old behaviour and
would have broken silently, so they are adapted here:

- shader.cpp exact-screen-depth parked the virtual screen at -0.5*w
  specifically so the shader's following negation would land it at
  +0.5*w. With that negation gone it now writes +0.5*w directly; keeping
  the minus sign would park the screen at NDC -0.5, outside the clip
  volume, discarding every 2D/HUD draw.

- stereo_replay.hpp backend_ndc_depth_row re-applied the correction to
  the projection it was handed. That projection is effective_projection()
  output, which now already carries it, so the function is a pass-through
  of the Z row and no longer depends on the reversed-Z setting; the dead
  bool parameter is dropped. Re-applying it would invert the virtual
  screen's depth ordering, so 2D layers meant to sit on top would lose
  the depth test to the ones behind them.

- shader_info.cpp stages the host depth window for that exact-depth path.
  It now uses the same reversed-Z remap as upstream's new SetViewport
  code, since frag_depth is written directly and has to reproduce the
  window the fixed viewport transform would have applied. Restricted
  depth windows (how the game forces an element in front of everything)
  are exactly the 2D draws the virtual screen carries.

The SetViewport resolution keeps upstream's remap but retains the
ordering/clamp guard our version had: for any ordered guest range the
result is identical to upstream, and it avoids handing WebGPU
minDepth > maxDepth for the swapped pair MKW is known to emit. The VR eye
replay reuses these recorded values, so the guard covers that path too.

Test updates:
- stereo_replay_test now asserts the composed Z row against the staged
  projection's own Z row rather than against the helper's output, so it
  actually catches a re-introduced double correction (verified: it fails
  when the old negation is put back; the previous self-consistent form
  passed).
- gx_fifo_test's clearDepthValue expectation followed #134's deliberate
  clear_depth_value() inversion, expressed through UseReversedZ rather
  than hardcoded. Upstream changed the behaviour without updating this
  test, so it fails on upstream/main as-is.

Verified: aurora suite 247 passed with the same 2 failures that already
fail on the pre-merge branch (IndexedPaletteHistoryKeepsAbsoluteVertexSlots,
PacksOneUniformWhenBothHalvesNeedInitialValue - both pre-existing, unrelated
to depth); shader.cpp and common.cpp compile clean; translator suite 577
passed. Not yet validated on-device in VR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iChris4andClaude Opus 5 committed 2026-09-10 04:19:51 +02:00
commit c8eaa52727
22 files changed
+635 -71

No files matched your search

+20 -13
View File
@@ -107,17 +107,24 @@ inline bool is_orthographic_projection(const Mat4x4<float>& projection) noexcept
return projection.m3[0] == 0.0f && projection.m3[1] == 0.0f && projection.m3[2] == 0.0f && projection.m3[3] == 1.0f;
}
// The stored GX projection has not yet passed through Aurora's final clip-depth
// conversion. Turn its Z row into the 0..1 backend NDC value that the original
// orthographic draw would have produced. The virtual-screen shader captures
// this row before replacing raster depth with a stable midrange value.
inline Vec4<float> backend_ndc_depth_row(const Mat4x4<float>& projection, bool reversedDepth) noexcept {
Vec4<float> row{};
for (size_t i = 0; i < 4; ++i) {
row[i] = reversedDepth ? -projection.m2[i] : projection.m2[i] + projection.m3[i];
}
return row;
}
// The Z row that reproduces the backend NDC depth the original orthographic draw
// would have produced. The virtual-screen shader captures it before replacing
// raster depth with a stable midrange value.
//
// This is a straight pass-through of the stored Z row, and deliberately does not
// depend on the reversed-Z setting. The projection reaching here is the one staged
// into the draw's own uniform, i.e. effective_projection()'s output, which since
// the reverse-Z fix carries the near/far depth correction already applied - exactly
// once, in the matrix - and the vertex shader now adds nothing on top of it. So
// dot(v, projection.m2) IS the depth the unmodified draw would have written.
//
// It previously re-applied a correction here (negating the row under reversed Z, or
// folding m3 in under forward Z). That was correct only while the vertex shader
// still applied its own redundant per-vertex correction for this one to cancel
// against. With that per-vertex step gone, any correction here is a double
// application: it would invert the virtual screen's depth ordering, so the 2D
// layers meant to sit on top would lose the depth test to the ones behind them.
inline Vec4<float> backend_ndc_depth_row(const Mat4x4<float>& projection) noexcept { return projection.m2; }
// Replaces an orthographic draw's projection so its 2D output lands on the
// fixed virtual screen instead of being stretched across the whole eye.
@@ -142,7 +149,7 @@ inline Vec4<float> backend_ndc_depth_row(const Mat4x4<float>& projection, bool r
// equal-depth 2D layers deterministic under head rotation and translation.
inline Mat4x4<float> compose_hud_screen_projection(const Mat4x4<float>& eyeFrustum, const Mat3x4<float>& viewFromCenter,
const HudScreen& screen, const Mat4x4<float>& gameProjection,
bool reversedDepth, const HudNdcRemap& ndcRemap = {}) noexcept {
const HudNdcRemap& ndcRemap = {}) noexcept {
const Mat4x4<float> frameProjection = remap_hud_ndc(gameProjection, ndcRemap);
// The screen point's three coordinates, each as a functional of (mv_pos, 1).
Mat3x4<float> screenPoint{};
@@ -166,7 +173,7 @@ inline Mat4x4<float> compose_hud_screen_projection(const Mat4x4<float>& eyeFrust
dst[3] += view[3];
}
const Vec4<float> exactDepthRow = backend_ndc_depth_row(gameProjection, reversedDepth);
const Vec4<float> exactDepthRow = backend_ndc_depth_row(gameProjection);
Mat4x4<float> out{};
for (size_t i = 0; i < 4; ++i) {
out.m0[i] = eyeFrustum.m0[0] * eyePoint.m0[i] + eyeFrustum.m0[2] * eyePoint.m2[i];