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:
parent
77f5342b62
commit
e65644cb33
12 changed files with 1461 additions and 31 deletions
|
|
@ -232,12 +232,14 @@ public sealed unsafe partial class ParticleRenderer
|
|||
/// which is the GL arm's bracket verbatim
|
||||
/// (<c>Enable(DepthTest)</c>/<c>DepthMask(false)</c>/<c>Disable(CullFace)</c>).
|
||||
///
|
||||
/// <para>Depth compare is <c>Less</c>, not the contract's <c>LessOrEqual</c>
|
||||
/// default: the world frame runs under <c>GL_LESS</c> and this renderer never
|
||||
/// called <c>glDepthFunc</c>, so it inherited it. Alpha-to-coverage is off
|
||||
/// for the same kind of reason and the opposite way round — the frame-global
|
||||
/// state controller disables it and only <c>WbDrawDispatcher</c>'s opaque
|
||||
/// bracket turns it on, so particles have never drawn with it.</para>
|
||||
/// <para>Depth compare is <see cref="AcDream.App.Rendering.WorldDepthContract.WorldCompare"/>
|
||||
/// (<c>Less</c>), not the contract's <c>LessOrEqual</c> default — see that
|
||||
/// type for the full citation. The world frame runs under <c>GL_LESS</c>
|
||||
/// and this renderer never called <c>glDepthFunc</c>, so it inherited it.
|
||||
/// Alpha-to-coverage is off for the same kind of reason and the opposite
|
||||
/// way round — the frame-global state controller disables it and only
|
||||
/// <c>WbDrawDispatcher</c>'s opaque bracket turns it on, so particles have
|
||||
/// never drawn with it.</para>
|
||||
/// </summary>
|
||||
private static IGpuPipeline CreateBillboardPipeline(
|
||||
IGpuDevice device,
|
||||
|
|
@ -251,7 +253,7 @@ public sealed unsafe partial class ParticleRenderer
|
|||
VertexLayout = BillboardVertexLayout,
|
||||
Topology = GpuPrimitiveTopology.TriangleList,
|
||||
Blend = blend,
|
||||
Depth = new GpuDepthState(Test: true, Write: false, GpuCompareOp.Less),
|
||||
Depth = new GpuDepthState(Test: true, Write: false, WorldDepthContract.WorldCompare),
|
||||
Cull = GpuCullMode.None,
|
||||
FrontFace = GpuFrontFace.CounterClockwise,
|
||||
AlphaToCoverage = false,
|
||||
|
|
@ -260,10 +262,12 @@ public sealed unsafe partial class ParticleRenderer
|
|||
});
|
||||
|
||||
/// <summary>
|
||||
/// One mesh-particle pipeline. Same depth bracket as the billboards; the
|
||||
/// winding is CW because <c>PrepareMeshPipeline</c> sets
|
||||
/// <c>glFrontFace(GL_CW)</c>, and the cull mode stays DYNAMIC because it is
|
||||
/// resolved per sub-batch from the DAT's own <c>CullMode</c>.
|
||||
/// One mesh-particle pipeline. Same depth bracket as the billboards (see
|
||||
/// <see cref="AcDream.App.Rendering.WorldDepthContract"/> for the world
|
||||
/// <c>GL_LESS</c> citation); the winding is CW because
|
||||
/// <c>PrepareMeshPipeline</c> sets <c>glFrontFace(GL_CW)</c>, and the cull
|
||||
/// mode stays DYNAMIC because it is resolved per sub-batch from the DAT's
|
||||
/// own <c>CullMode</c>.
|
||||
/// </summary>
|
||||
private static IGpuPipeline CreateMeshParticlePipeline(
|
||||
IGpuDevice device,
|
||||
|
|
@ -277,7 +281,7 @@ public sealed unsafe partial class ParticleRenderer
|
|||
VertexLayout = MeshVertexLayout,
|
||||
Topology = GpuPrimitiveTopology.TriangleList,
|
||||
Blend = blend,
|
||||
Depth = new GpuDepthState(Test: true, Write: false, GpuCompareOp.Less),
|
||||
Depth = new GpuDepthState(Test: true, Write: false, WorldDepthContract.WorldCompare),
|
||||
Cull = GpuCullMode.None,
|
||||
FrontFace = GpuFrontFace.Clockwise,
|
||||
AlphaToCoverage = false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue