phase(N.5): retirement amendment — InstancedMeshRenderer + StaticMeshRenderer + WbFoundationFlag deleted

Final cross-cutting review of N.5 found that Task 15's deletion of
mesh_instanced.vert/.frag left InstancedMeshRenderer orphaned —
ACDREAM_USE_WB_FOUNDATION=0 silently rendered terrain+sky only with
no entities. The SHIP commit's "[x] ACDREAM_USE_WB_FOUNDATION=0 still
works" claim was inaccurate.

Resolution: formal retirement of the legacy renderer path within N.5
instead of deferring to N.6.

Deleted:
- src/AcDream.App/Rendering/InstancedMeshRenderer.cs
- src/AcDream.App/Rendering/StaticMeshRenderer.cs
- src/AcDream.App/Rendering/Wb/WbFoundationFlag.cs

GameWindow simplified — capability detection is unconditional, missing
bindless throws NotSupportedException with a clear message at startup.
WbDrawDispatcher + mesh_modern shader load are mandatory after init.
No escape hatch.

GpuWorldState simplified — WbFoundationFlag.IsEnabled guards on
AddLandblock/RemoveLandblock removed; adapter calls are unconditional
when the adapter is non-null.

PendingSpawnIntegrationTests updated — WbFoundationFlag.ForTestsOnly_ForceEnable
static ctor removed (flag is gone; adapter calls are unconditional).

The ApplyLoadedTerrain physics-data loop was also simplified: the
EnsureUploaded sub-loop that fed InstancedMeshRenderer is gone;
_pendingCellMeshes is now explicitly cleared to prevent unbounded
accumulation (the worker thread still populates it, but WB handles
EnvCell geometry through its own pipeline).

Spec §2 Decision 5 + §10 Out-of-Scope updated. Plan ship-amendment
section added. Roadmap updated (N.5 ships with retirement; N.6 scope
narrowed to perf-only). CLAUDE.md "WB integration cribs" updated.
Perf baseline doc updated. WbDrawDispatcher class summary docstring
corrected to describe the as-shipped SSBO + multi-draw-indirect path.
ISSUES.md #51 updated (terrain not in N.5 scope; deferred to N.7).

Bindless support is now a hard requirement. Modern desktop GPUs
universally expose GL_ARB_bindless_texture + GL_ARB_shader_draw_parameters;
if a user hits the NotSupportedException, that's a real bug report
worth investigating, not a silent fallback.

Build: 0 errors, 0 warnings. Tests: 71/71 (Wb+MatrixComposition+TextureCacheBindless filter).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 22:01:36 +02:00
parent 55ecec683f
commit dcae2b6b94
13 changed files with 211 additions and 1140 deletions

View file

@ -13,26 +13,29 @@ namespace AcDream.App.Rendering.Wb;
/// <summary>
/// Draws entities using WB's <see cref="ObjectRenderData"/> (a single global
/// VAO/VBO/IBO under modern rendering) with acdream's <see cref="TextureCache"/>
/// for texture resolution and <see cref="AcSurfaceMetadataTable"/> for
/// for bindless texture resolution and <see cref="AcSurfaceMetadataTable"/> for
/// translucency classification.
///
/// <para>
/// <b>Atlas-tier</b> entities (<c>ServerGuid == 0</c>): mesh data comes from WB's
/// <see cref="ObjectMeshManager"/> via <see cref="WbMeshAdapter.TryGetRenderData"/>.
/// Textures resolve through <see cref="TextureCache.GetOrUpload"/> using the batch's
/// <c>SurfaceId</c>.
/// Textures resolve through the bindless-suffixed
/// <see cref="TextureCache.GetOrUploadBindless"/> variants, returning 64-bit
/// resident handles stored in the per-group SSBO.
/// </para>
///
/// <para>
/// <b>Per-instance-tier</b> entities (<c>ServerGuid != 0</c>): mesh data also from
/// WB, but textures resolve through <see cref="TextureCache"/> with palette and
/// surface overrides applied. <see cref="AnimatedEntityState"/> is currently
/// WB, but textures resolve through
/// <see cref="TextureCache.GetOrUploadWithPaletteOverrideBindless"/> with palette
/// and surface overrides applied. <see cref="AnimatedEntityState"/> is currently
/// unused at draw time — GameWindow's spawn path already bakes AnimPartChanges +
/// GfxObjDegradeResolver (Issue #47 close-detail mesh) into <c>MeshRefs</c>.
/// </para>
///
/// <para>
/// <b>GL strategy (N.5):</b> <c>glMultiDrawElementsIndirect</c> with SSBOs.
/// <b>GL strategy (N.5 — mandatory):</b> <c>glMultiDrawElementsIndirect</c> with SSBOs
/// and <c>GL_ARB_bindless_texture</c> + <c>GL_ARB_shader_draw_parameters</c>.
/// All visible (entity, batch) pairs are bucketed by <see cref="GroupKey"/>;
/// each group becomes one <c>DrawElementsIndirectCommand</c>. Three GPU buffers
/// are uploaded per frame: instance matrices (SSBO binding 0), per-group batch
@ -42,17 +45,17 @@ namespace AcDream.App.Rendering.Wb;
/// </para>
///
/// <para>
/// <b>Shader:</b> <c>mesh_modern</c> when bindless + ARB_shader_draw_parameters
/// are available (N.5 path). Falls back to <c>mesh_instanced</c> when the GPU
/// lacks those extensions.
/// <b>Shader:</b> <c>mesh_modern</c> (bindless + <c>gl_DrawIDARB</c> /
/// <c>gl_BaseInstanceARB</c>). Missing bindless/draw-parameters throws
/// <see cref="NotSupportedException"/> at startup — there is no legacy fallback.
/// </para>
///
/// <para>
/// <b>Modern rendering assumption:</b> WB's <c>_useModernRendering</c> path (GL
/// 4.3 + bindless) puts every mesh in a single shared VAO/VBO/IBO and uses
/// <c>FirstIndex</c> + <c>BaseVertex</c> per batch. The dispatcher honors those
/// offsets via <c>DrawElementsInstancedBaseVertex(BaseInstance)</c>. The legacy
/// per-mesh-VAO path also works since FirstIndex/BaseVertex are zero there.
/// offsets inside each <c>DrawElementsIndirectCommand</c> via
/// <c>glMultiDrawElementsIndirect</c>.
/// </para>
/// </summary>
public sealed unsafe class WbDrawDispatcher : IDisposable

View file

@ -1,39 +0,0 @@
namespace AcDream.App.Rendering.Wb;
/// <summary>
/// Process-lifetime cache of <c>ACDREAM_USE_WB_FOUNDATION</c> env var.
/// Read once at static-init time; all consumers import this rather than
/// re-reading the env var per call (env-var lookups on Windows are not
/// free at hot-path cadence).
///
/// <para>
/// <b>Default-on as of Phase N.4 ship (2026-05-08).</b> The WB foundation
/// (<c>WbMeshAdapter</c> + <c>WbDrawDispatcher</c>) is the production
/// rendering path. Set <c>ACDREAM_USE_WB_FOUNDATION=0</c> to fall back
/// to the legacy <c>InstancedMeshRenderer</c> path — kept as an escape
/// hatch until N.6 fully replaces it.
/// </para>
///
/// <para>
/// Per-instance customized content (server <c>CreateObject</c> entities
/// with palette / texture overrides) routes through
/// <see cref="TextureCache.GetOrUploadWithPaletteOverride"/> regardless
/// of the flag — the flag controls which DRAW path consumes those
/// textures.
/// </para>
/// </summary>
public static class WbFoundationFlag
{
private static bool _isEnabled =
System.Environment.GetEnvironmentVariable("ACDREAM_USE_WB_FOUNDATION") != "0";
public static bool IsEnabled => _isEnabled;
/// <summary>
/// FOR TESTS ONLY. Forces <see cref="IsEnabled"/> to <c>true</c> so
/// integration tests can exercise the WB adapter path without having to
/// set the env var before static initialisation. Never call from
/// production code.
/// </summary>
internal static void ForTestsOnly_ForceEnable() => _isEnabled = true;
}