From a65a241981fd93aef0a0b46fc1c444117f6afa72 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 10 May 2026 18:05:03 +0200 Subject: [PATCH] feat(render #53): inject EntityClassificationCache into WbDrawDispatcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the cache as a constructor parameter on WbDrawDispatcher and a private field on GameWindow. The cache is passed through but not yet consumed by Draw — that wires up in Task 9 (cache miss / populate) and Task 10 (cache hit / fast path). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.App/Rendering/GameWindow.cs | 14 +++++++++++++- .../Rendering/Wb/WbDrawDispatcher.cs | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 149084d..b401553 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -159,6 +159,17 @@ public sealed class GameWindow : IDisposable /// private readonly Dictionary _animatedEntities = new(); + /// + /// Tier 1 cache (#53): per-entity classification results for static + /// entities (those NOT in ). Conceptually + /// paired with — that dictionary is the + /// gating predicate, this cache is the lookup that depends on it. + /// Passed to at + /// construction time. Tasks 9-10 of the cache plan wire the per-entity + /// miss-populate / hit-fast-path through the dispatcher's loop. + /// + private readonly AcDream.App.Rendering.Wb.EntityClassificationCache _classificationCache = new(); + private sealed class AnimatedEntity { public required AcDream.Core.World.WorldEntity Entity; @@ -1604,7 +1615,8 @@ public sealed class GameWindow : IDisposable _worldState = new AcDream.App.Streaming.GpuWorldState(wbSpawnAdapter, wbEntitySpawnAdapter); _wbDrawDispatcher = new AcDream.App.Rendering.Wb.WbDrawDispatcher( - _gl, _meshShader!, _textureCache!, _wbMeshAdapter!, _wbEntitySpawnAdapter, _bindlessSupport!); + _gl, _meshShader!, _textureCache!, _wbMeshAdapter!, _wbEntitySpawnAdapter, _bindlessSupport!, + _classificationCache); // A.5 T22.5: apply A2C gate from quality preset. _wbDrawDispatcher.AlphaToCoverage = _resolvedQuality.AlphaToCoverage; } diff --git a/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs b/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs index 33bb863..9196bab 100644 --- a/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs +++ b/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs @@ -68,6 +68,12 @@ public sealed unsafe class WbDrawDispatcher : IDisposable private readonly BindlessSupport _bindless; + // Tier 1 cache (#53): per-entity classification results for static + // entities (those NOT in GameWindow._animatedEntities). Wired here in + // Task 7 for plumbing only — Tasks 9-10 wire the per-entity + // miss-populate / hit-fast-path through the loop. + private readonly EntityClassificationCache _cache; + /// /// A.5 T22.5: gate for GL_SAMPLE_ALPHA_TO_COVERAGE around the opaque pass. /// Default true matches T20 behavior. Set false for Low/Medium presets that @@ -139,25 +145,32 @@ public sealed unsafe class WbDrawDispatcher : IDisposable private int _gpuSampleCursor; private bool _gpuQueriesInitialized; - public WbDrawDispatcher( + // Constructor accessibility is internal because EntityClassificationCache + // is internal — a public ctor with an internal-typed parameter would be + // an inconsistent-accessibility error. The dispatcher is constructed + // exclusively from GameWindow (same assembly), so internal is fine. + internal WbDrawDispatcher( GL gl, Shader shader, TextureCache textures, WbMeshAdapter meshAdapter, EntitySpawnAdapter entitySpawnAdapter, - BindlessSupport bindless) + BindlessSupport bindless, + EntityClassificationCache classificationCache) { ArgumentNullException.ThrowIfNull(gl); ArgumentNullException.ThrowIfNull(shader); ArgumentNullException.ThrowIfNull(textures); ArgumentNullException.ThrowIfNull(meshAdapter); ArgumentNullException.ThrowIfNull(entitySpawnAdapter); + ArgumentNullException.ThrowIfNull(classificationCache); _gl = gl; _shader = shader; _textures = textures; _meshAdapter = meshAdapter; _entitySpawnAdapter = entitySpawnAdapter; + _cache = classificationCache; _bindless = bindless ?? throw new ArgumentNullException(nameof(bindless)); _instanceSsbo = _gl.GenBuffer();