acdream/src/AcDream.App/Rendering/WorldDepthContract.cs
Erik e65644cb33 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>
2026-08-30 12:31:31 +02:00

47 lines
2.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}