refactor(render): Phase U.1 — delete two-pipe inside-out machinery
Remove IndoorCellStencilPipeline + portal_stencil shaders, RenderInsideOutAcdream, RenderOutsideInAcdream, the A8-perf instrumentation, the cameraInsideBuilding / ACDREAM_A8_INDOOR_BRANCH branch, and the dead EntitySet partition values. Collapse the render branch to the default Draw(All) path (U.4a replaces it with the gated unified pass). Keep all audited EnvCellRenderer / BuildingLoader / CellVisibility / camera-collision fixes. Also deleted with the partition: the two test-only walk helpers (WbDrawDispatcher.WalkEntitiesForTest / WalkEntitiesForTestByCellIds) and their test files (WbDrawDispatcherEntitySetTests, WbDrawDispatcherCellIdsOverloadTests), which existed solely to exercise the removed IndoorPass/OutdoorScenery/ BuildingShells/LiveDynamic partition. EntityMatchesSet / IsShellScopedSet collapse to the All-path constants; the set: parameter is retained as a seam for the unified pass. Note: the depth-clear-if-inside default-path workaround was removed per the U.1 task list — any current indoor-wall degradation persists until a later Phase U task lands the unified pass (expected, not a regression introduced here). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0f7b395be1
commit
3fc77be5de
8 changed files with 37 additions and 2612 deletions
|
|
@ -62,42 +62,21 @@ namespace AcDream.App.Rendering.Wb;
|
|||
public sealed unsafe class WbDrawDispatcher : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Phase A8 — which subset of entities to walk in a single Draw call.
|
||||
/// Used to split the indoor-cell visibility pipeline into three passes
|
||||
/// when the camera is inside an EnvCell.
|
||||
/// Which subset of entities to walk in a single Draw call.
|
||||
///
|
||||
/// Taxonomy reference: docs/research/2026-05-26-a8-entity-taxonomy.md.
|
||||
/// Phase U.1 (2026-05-30): the indoor/outdoor two-pipe split (IndoorPass /
|
||||
/// OutdoorScenery / BuildingShells / LiveDynamic) was deleted along with the
|
||||
/// inside-out render machinery. <see cref="All"/> is the sole remaining
|
||||
/// member; the unified retail-faithful pass (Phase U) draws every entity in
|
||||
/// one path. The <c>set:</c> parameter is retained on the Draw overloads so
|
||||
/// the unified pass can re-introduce partitioning later without re-threading
|
||||
/// the call sites.
|
||||
/// </summary>
|
||||
public enum EntitySet
|
||||
{
|
||||
/// <summary>Pre-A8 behavior: every entity walked, gated only by
|
||||
/// the existing <c>ParentCellId ∈ visibleCellIds</c> filter.
|
||||
/// Used when the camera is OUTSIDE any EnvCell.</summary>
|
||||
/// <summary>Every entity walked, gated only by the existing
|
||||
/// <c>ParentCellId ∈ visibleCellIds</c> filter.</summary>
|
||||
All,
|
||||
|
||||
/// <summary>Cell mesh + cell statics (<see cref="WorldEntity.ParentCellId"/>
|
||||
/// non-null) PLUS building shell stabs (<see cref="WorldEntity.IsBuildingShell"/>
|
||||
/// true) whose <see cref="WorldEntity.BuildingShellAnchorCellId"/>
|
||||
/// belongs to the active building cell set. Live-dynamic
|
||||
/// (<c>ServerGuid != 0</c>) is excluded; it flows through
|
||||
/// <see cref="LiveDynamic"/>.</summary>
|
||||
IndoorPass,
|
||||
|
||||
/// <summary>Outdoor/top-level stabs (<c>ParentCellId == null</c>),
|
||||
/// including building shells. Drawn stencil-gated to portal
|
||||
/// silhouettes when the camera is inside. Live-dynamic excluded.</summary>
|
||||
OutdoorScenery,
|
||||
|
||||
/// <summary>Top-level building shell stabs only, optionally scoped by
|
||||
/// <see cref="WorldEntity.BuildingShellAnchorCellId"/>. Used for
|
||||
/// portal depth repair without walking the full outdoor scenery set.</summary>
|
||||
BuildingShells,
|
||||
|
||||
/// <summary>Server-spawned dynamic entities (<c>ServerGuid != 0</c>):
|
||||
/// player, NPCs, monsters, dropped items, animated and idle doors.
|
||||
/// Drawn last with stencil disabled so they're depth-tested against
|
||||
/// everything else but not stencil-clipped.</summary>
|
||||
LiveDynamic,
|
||||
}
|
||||
|
||||
private readonly GL _gl;
|
||||
|
|
@ -576,13 +555,6 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
probeState,
|
||||
set);
|
||||
|
||||
if (set == EntitySet.IndoorPass && RenderingDiagnostics.ProbeVisibilityEnabled)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[indoor-shells] anchorPass={walkResult.BuildingShellAnchorPass} " +
|
||||
$"anchorReject={walkResult.BuildingShellAnchorReject} walked={walkResult.EntitiesWalked}");
|
||||
}
|
||||
|
||||
// Tier 1 cache (#53) flush-tracking locals. _walkScratch holds one tuple
|
||||
// per (entity, MeshRefIndex) and is in entity-order, so all MeshRefs of
|
||||
// a given entity are contiguous. We accumulate ALL of an entity's
|
||||
|
|
@ -1507,82 +1479,12 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase A8 — entity-taxonomy-aware membership test for the three-way
|
||||
/// EntitySet partition. See <see cref="EntitySet"/> for the doctrine.
|
||||
/// Entity-set membership test. Phase U.1 (2026-05-30): with the
|
||||
/// two-pipe partition deleted, the sole <see cref="EntitySet.All"/>
|
||||
/// member matches every entity. Retained as a seam for the unified
|
||||
/// pass to re-introduce partitioning.
|
||||
/// </summary>
|
||||
private static bool EntityMatchesSet(WorldEntity entity, EntitySet set)
|
||||
{
|
||||
if (set == EntitySet.All) return true;
|
||||
|
||||
bool isLiveDynamic = entity.ServerGuid != 0;
|
||||
if (set == EntitySet.LiveDynamic) return isLiveDynamic;
|
||||
if (isLiveDynamic) return false; // IndoorPass/OutdoorScenery exclude live-dynamic
|
||||
|
||||
bool isIndoor = entity.ParentCellId.HasValue || entity.IsBuildingShell;
|
||||
if (set == EntitySet.IndoorPass) return isIndoor;
|
||||
if (set == EntitySet.OutdoorScenery) return !entity.ParentCellId.HasValue;
|
||||
if (set == EntitySet.BuildingShells) return entity.IsBuildingShell;
|
||||
|
||||
throw new InvalidOperationException($"Unhandled EntitySet value: {set}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase A8 test helper: runs the EntitySet partition + visibleCellIds
|
||||
/// gate against an in-memory entity list, returning the IDs that
|
||||
/// survive both filters. Exists so the partition logic is unit-testable
|
||||
/// without requiring a GL context or landblock-entries machinery.
|
||||
/// </summary>
|
||||
public static List<uint> WalkEntitiesForTest(
|
||||
IReadOnlyList<AcDream.Core.World.WorldEntity> entities,
|
||||
HashSet<uint>? visibleCellIds,
|
||||
EntitySet set)
|
||||
{
|
||||
var output = new List<uint>();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (!EntityMatchesSet(entity, set)) continue;
|
||||
if (entity.MeshRefs.Count == 0) continue;
|
||||
|
||||
if (!EntityPassesVisibleCellGate(entity, visibleCellIds, set)) continue;
|
||||
|
||||
output.Add(entity.Id);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase A8 RR5 (2026-05-26): pure-data walk for the explicit cellIds
|
||||
/// overload. Used by RR7's IndoorPass to render only the camera-buildings'
|
||||
/// cells (instead of the visibility-derived set).
|
||||
///
|
||||
/// <para>Indoor entities (ParentCellId set) gated by membership in
|
||||
/// <paramref name="cellIds"/>. Building shells are gated by
|
||||
/// BuildingShellAnchorCellId membership in the same cell set. Outdoor
|
||||
/// scenery is excluded by the EntitySet partition (no cell-list gate
|
||||
/// needed — EntityMatchesSet handles it).</para>
|
||||
/// </summary>
|
||||
public static List<uint> WalkEntitiesForTestByCellIds(
|
||||
IEnumerable<AcDream.Core.World.WorldEntity> entities,
|
||||
IReadOnlyCollection<uint> cellIds,
|
||||
EntitySet set)
|
||||
{
|
||||
var result = new List<uint>();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (!EntityMatchesSet(entity, set)) continue;
|
||||
if (entity.MeshRefs.Count == 0) continue;
|
||||
if (entity.ParentCellId.HasValue && !cellIds.Contains(entity.ParentCellId.Value))
|
||||
continue;
|
||||
if (IsShellScopedSet(set) && entity.IsBuildingShell)
|
||||
{
|
||||
if (entity.BuildingShellAnchorCellId is not uint anchorCellId ||
|
||||
!cellIds.Contains(anchorCellId))
|
||||
continue;
|
||||
}
|
||||
result.Add(entity.Id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static bool EntityMatchesSet(WorldEntity entity, EntitySet set) => true;
|
||||
|
||||
private static bool EntityPassesVisibleCellGate(
|
||||
WorldEntity entity,
|
||||
|
|
@ -1604,8 +1506,9 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool IsShellScopedSet(EntitySet set) =>
|
||||
set == EntitySet.IndoorPass || set == EntitySet.BuildingShells;
|
||||
// Phase U.1 (2026-05-30): the shell-scoped sets (IndoorPass / BuildingShells)
|
||||
// were deleted with the two-pipe machinery. EntitySet.All is never shell-scoped.
|
||||
private static bool IsShellScopedSet(EntitySet set) => false;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue