feat(render) Campaign FW2: OrderedDrawStream + walk-order submitter

The walk-order submission layer over the existing RHI (plan section FW2):

- OrderedDrawStream: append-only walk-ordered draw commands
  (GroupKey + transform + per-instance data + WalkDrawStage + cell
  provenance), struct-of-arrays with one lockstep Reset (#193 shape).
  The PortalPunch stage exists but has no FW2 submission path - the
  submitter throws on it; punch emission lands with FW3 wiring.
- WbDrawDispatcher.OrderedStream partial: per-instance-first emission
  (the deferred-alpha shape - command i owns instance i, walk order
  survives into the indirect array), each SSBO section written once,
  then one DrawIndirectRangeRhi call per maximal merge run. Runs are
  built by pure-CPU BuildOrderedMergeRuns and may never span a stage,
  pipeline-bucket, or cull boundary; ValidateMergeRun re-checks every
  emitted run and throws (the campaign fail-loud rule). Nothing is
  sorted, reordered, or dropped: N commands in, N indirect commands
  out, covered exactly once.
- WorldDepthContract: retail world depth verified verbatim from the
  decomp - Render::zfuncVal @0x00820e1c = 0x2, SetDepthBufferMode
  @0x005a2d10 writes the enum directly as D3DRS_ZFUNC so the value IS
  D3DCMP_LESS, applied by the surface-state applier @0x0059c80a with
  Z-write toggled by blend; the LESSEQUAL sites are GameSky::Draw-local.
  Seven world pipeline sites now cite the named constant (no value
  changes).
- Plan updated: FW1 status block + gate amendment (the ten pose-stamped
  retail traces supersede re-expressing the old-builder replay
  fixtures; those retire with the old builder at FW4 and their
  scenario classes re-verify at the FW3/FW4 connected gates).

Known FW2 scope notes recorded in the code: the building-detail
overlay replay is production wiring (FW3); the _drawCullModes scratch
may not interleave with a mid-flight RetailAlphaQueue scope (FW3
sequencing constraint). The pixel A/B equivalence proof rides FW3's
cutover toggle where a walk-driven scene first exists.

Suites: full Release build 0 warnings; Walk lane 154/1 skip;
hermetic 6,714/0 (+27 new).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-30 12:31:31 +02:00
parent 77f5342b62
commit e65644cb33
12 changed files with 1461 additions and 31 deletions

View file

@ -0,0 +1,47 @@
using AcDream.App.Rendering.Gpu;
namespace AcDream.App.Rendering;
/// <summary>
/// Campaign FW stage FW2: the one depth-compare operator every world-space
/// pipeline uses, named instead of repeated as a literal at each of the
/// world's own pipeline-creation sites.
///
/// <para><b>Why <see cref="GpuCompareOp.Less"/>, not
/// <see cref="GpuPipelineDescription"/>'s/<c>GpuDepthState</c>'s own
/// <c>LessOrEqual</c> convention default:</b> the GL-era world frame ran under
/// <c>GL_LESS</c> and never called <c>glDepthFunc</c> to change it, so every
/// world-space renderer inherited <c>GL_LESS</c> by omission rather than by
/// design. <c>LessOrEqual</c> would flip which of two exactly-coplanar retail
/// surfaces wins the depth test — visible wherever terrain meets a road or a
/// building footing, or wherever two retail-authored polygons share a plane.
/// FW2's decomp verification (plan §FW2, read 2026-08-30) confirms retail's
/// own world raster state is <c>D3DCMP_LESS</c>: the .data default
/// <c>Render::zfuncVal</c> @0x00820e1c is <c>0x2</c>, and
/// <c>RenderDeviceD3D::SetDepthBufferMode</c> @0x005a2d10 writes that enum
/// value DIRECTLY as <c>D3DRS_ZFUNC</c> (render state 0x17) — the enum IS
/// <c>D3DCMPFUNC</c>, so <c>0x2 = D3DCMP_LESS</c>. The surface-state applier
/// @0x0059c80a0x0059c866 applies it to all world geometry with Z-write
/// toggled by blend state (on for opaque, off for blended), exactly this
/// pipeline set's per-variant <c>depthWrite</c>. The <c>DEPTHTEST_LESSEQUAL</c>
/// sites in the decomp are SKY-local (<c>GameSky::Draw</c> @0x00506ff0, drawn
/// at 4× zfar) — never world state. So <c>Less</c> is not merely "what the
/// port happened to inherit" — it is retail's actual world depth-compare
/// operator, now named as a citable contract instead of a bare literal
/// repeated at each call site.</para>
///
/// <para>Scope: WORLD-SPACE geometry only (terrain, EnvCell shells, entity
/// meshes, particles, portal punches, the directional shadow caster/receiver
/// pair). The two <c>RetailDetail</c> pipelines
/// (<see cref="RetailDetailTextureContract"/>'s <c>Equal</c>/<c>LessOrEqual</c>
/// pair, used by the building-detail overlay replay) are a documented
/// exception with their own citation and are untouched by this contract.</para>
/// </summary>
internal static class WorldDepthContract
{
/// <summary>Retail's world-space depth-compare operator. See the type
/// doc comment for the full citation; every world pipeline site should
/// reference this constant rather than spelling <c>GpuCompareOp.Less</c>
/// again.</summary>
public const GpuCompareOp WorldCompare = GpuCompareOp.Less;
}