acdream/src/AcDream.App/Rendering/Wb
Erik d365476ebb feat(render): Campaign V slice V2a - mesh path texture-index migration
Moves the mesh/EnvCell draw path's per-batch texture representation from a
64-bit ARB_bindless_texture handle to a small integer table index, entirely
on the still-shipping GL backend, with zero pixel change. This is the CPU-side
half of the eventual Vulkan descriptor-array indexing model: a table index is
the backend-neutral form (Vulkan indexes a descriptor array with it directly),
while a raw bindless handle is GL-only. Landing the data-model change now, on
GL, under a strict self-differential pixel gate, keeps it separate from V4c's
much larger RHI-plumbing change (see docs/plans/2026-07-27-vulkan-campaign.md
section 5.2 for why the table cannot be device-owned yet).

Mechanism: mesh_modern.vert's BatchData struct carries `textureIndex` (a slot)
instead of `textureHandle` (uvec2); the vertex shader looks the slot up in a
new binding=9 storage buffer (GpuBindingModel.StorageTextureTable) and passes
the reconstructed uvec2 handle to the fragment shader exactly as before, so
mesh_modern.frag needed no change at all beyond the UBO-set macro below. The
16-byte std430 stride is unchanged (GpuBindingModel.GpuBatchDataStrideBytes);
textureLayer/flags keep their offsets, so every existing CPU writer's layout
is untouched.

The handle->slot table (GlBindlessHandleTable, new, pure C#) is owned
separately by WbDrawDispatcher and EnvCellRenderer rather than shared through
a single TextureCache-owned instance: EnvCellRenderer never had a TextureCache
dependency, and nothing requires index agreement between renderers since each
rebinds its own binding=9 buffer immediately before its own draw call. This
avoided threading a new constructor parameter through EnvCellRenderer (and its
six test call sites) for no behavioral benefit. TextureCache and
CompositeTextureArrayCache turned out to need no changes at all: they only
ever produce raw ulong handles, and that production path is unaffected -
the new indirection is entirely a WbDrawDispatcher/EnvCellRenderer-side
concern, added exactly where each already assembles its per-batch GPU struct
(ToInput, the copy-back loop, PrepareDeferredAlphaDraws for the
RetailAlphaQueue path, and EnvCellRenderer's ModernBatchData construction).
The table itself is a single non-ring buffer (unlike the per-frame
triple-buffered SSBOs) because a genuinely new handle is rare - new dat
surfaces/composite overrides, not every frame - so it flushes only when
GlBindlessHandleTable.Dirty is set, mirroring how the existing texture caches
already upload infrequently.

Shader-side, introduced Rendering/Shaders/common.glsl as the shared preamble
GL has no #include for: Shader.cs gained an `includeCommonPreamble` overload
that splices the file's text in after the leading #version/#extension block
(GLSL requires #version first). It declares the binding=9 table plus the
ACDREAM_TEXTURE_HANDLE(idx) lookup macro, and a scaffolding ACDREAM_UBO_SET
macro (a no-op under GL today, redefined to `set = 1,` when the Vulkan
toolchain compiles this same source at V6+, per the campaign doc's set-1 UBO
note) applied to both SceneLighting UBO declarations now so no later slice
needs to touch them again.

Tests: WbDrawDispatcherIndirectBuilderTests updated for the renamed
IndirectGroupInput/BatchDataPublic fields; new ModernBatchDataLayoutTests
(mirrors ClipFrameLayoutTests' role, but for EnvCellRenderer's GPU struct) and
GlBindlessHandleTableTests (pure-CPU allocator behavior, including the
zero-handle case, which is registered like any other handle rather than
special-cased, since that's what reproduces the pre-V2 sampling result
bit-for-bit).

Gate: dotnet build -c Release green, dotnet test
tests/AcDream.App.Tests -c Release green (3843 passed / 3 skipped, +9 over
the 3834/3 baseline), and tools/run-offline-pixel-gate.ps1 passed with a
2.84e-05 differing-pixel fraction against the parent commit - within the
documented ~33x same-commit noise margin. No divergence-register row: this
introduces no retail behavior deviation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 15:51:26 +02:00
..
AnimatedEntityState.cs phase(N.4) Tasks 16+18+19: AnimatedEntityState + AnimPartChange + HiddenParts 2026-05-08 14:37:09 +02:00
BindlessSupport.cs feat(render): Campaign V slice V1 - OpenGL RHI backend (dark) 2026-07-27 15:11:04 +02:00
BufferUsageExtensions.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
Building.cs feat(render): Phase A8 — indoor visibility + streaming fixes batch 2026-05-29 10:14:50 +02:00
BuildingLoader.cs perf(streaming): cursor publication across frame budgets 2026-07-24 19:10:18 +02:00
BuildingRegistry.cs feat(render): Phase A8 RR3 — Building + BuildingRegistry + BuildingLoader 2026-05-27 11:08:43 +02:00
CachedBatch.cs fix #225: stabilize render pacing and frame CPU 2026-07-19 06:29:30 +02:00
CompositeWarmupEntitySource.cs perf(streaming): scope reveal warmup spatially 2026-07-25 04:39:48 +02:00
ContiguousRangeAllocator.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
DebugRenderSettings.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
DrawElementsIndirectCommand.cs phase(N.5) Task 7: dispatcher SSBO + indirect buffer infrastructure 2026-05-08 20:25:29 +02:00
EntityClassificationCache.cs fix #225: stabilize render pacing and frame CPU 2026-07-19 06:29:30 +02:00
EntitySpawnAdapter.cs refactor(app): key live projections by runtime identity 2026-07-25 21:50:58 +02:00
EnvCellLandblockBuild.cs fix(render): eliminate EnvCell identity collisions 2026-07-24 13:44:56 +02:00
EnvCellLandblockPublication.cs perf(streaming): cursor publication across frame budgets 2026-07-24 19:10:18 +02:00
EnvCellMeshPreparationScheduler.cs perf(render): consume prepared mesh package at runtime 2026-07-24 15:07:25 +02:00
EnvCellRenderer.cs feat(render): Campaign V slice V2a - mesh path texture-index migration 2026-07-27 15:51:26 +02:00
EnvCellSceneryInstance.cs fix(streaming): commit EnvCell landblocks atomically (#214) 2026-07-13 18:45:24 +02:00
EnvCellVisibilitySnapshot.cs fix(render): Phase A8 — pool aliasing in EnvCellRenderer (visual chaos root cause) 2026-05-27 19:08:49 +02:00
GeometryUtils.cs feat(O-T7): drop WB project references; complete extraction 2026-05-21 17:17:33 +02:00
GLHelpers.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
GlobalMeshBuffer.cs feat(render): unify physical residency accounting 2026-07-24 16:20:48 +02:00
GLSLShader.cs refactor(app): compose world rendering startup 2026-07-22 16:46:05 +02:00
GLStateScope.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
GpuMemoryTracker.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
GpuRetiredRangeAllocator.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
GroupKey.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
IEntityTextureLifetime.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
InstanceData.cs fix(O-T4): address spec-review findings — InstanceData + using cleanups 2026-05-21 16:50:05 +02:00
IWbMeshAdapter.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
LandblockSpawnAdapter.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
ManagedGLFrameBuffer.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
ManagedGLIndexBuffer.cs feat(O-T7): drop WB project references; complete extraction 2026-05-21 17:17:33 +02:00
ManagedGLTexture.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
ManagedGLTextureArray.cs feat(render): unify physical residency accounting 2026-07-24 16:20:48 +02:00
ManagedGLUniformBuffer.cs refactor(app): compose world rendering startup 2026-07-22 16:46:05 +02:00
ManagedGLVertexArray.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
ManagedGLVertexBuffer.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
MeshUploadCaches.cs fix(streaming): prepare quiesced destination entities 2026-07-24 20:21:57 +02:00
MeshUploadFrameBudget.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
ModernRenderData.cs feat(render): Campaign V slice V2a - mesh path texture-index migration 2026-07-27 15:51:26 +02:00
ObjectMeshManager.cs fix(streaming): prepare quiesced destination entities 2026-07-24 20:21:57 +02:00
OpenGLGraphicsDevice.cs chore(render): delete dead ParticleBatcher chain (2026-07-24 audit review) 2026-07-24 11:49:46 +02:00
PackedProjectionClassificationCache.cs perf(rendering): retain packed classification 2026-07-25 02:46:40 +02:00
RenderStateCache.cs chore(O-T7): code-review housekeeping after WB extraction 2026-05-21 17:29:06 +02:00
RetryableResourceReleaseLedger.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
SceneData.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
TextureAtlasManager.cs feat(render): unify physical residency accounting 2026-07-24 16:20:48 +02:00
TextureAtlasSlotAllocator.cs feat(render): unify physical residency accounting 2026-07-24 16:20:48 +02:00
TextureFormatExtensions.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
TextureParameters.cs feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
TrackedGlResource.cs refactor(app): compose world rendering startup 2026-07-22 16:46:05 +02:00
WbDrawDispatcher.cs feat(render): Campaign V slice V2a - mesh path texture-index migration 2026-07-27 15:51:26 +02:00
WbDrawDispatcher.PackedOracle.cs Reapply "perf(rendering): draw retained frame product" 2026-07-25 08:36:11 +02:00
WbFrustum.cs feat(render): Phase A8 Wave 1 — WB scaffolding extraction + stencil low-level method 2026-05-27 14:46:07 +02:00
WbMeshAdapter.cs fix(streaming): preserve portal destination ownership 2026-07-25 08:35:12 +02:00
WbRenderPass.cs feat(render): Phase A8 Wave 1 — WB scaffolding extraction + stencil low-level method 2026-05-27 14:46:07 +02:00
WbTextureResolutionPolicy.cs fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00