refactor(A.5 T9): _surfaceCache -> ConcurrentDictionary for off-thread mesh build
Widens LandblockMesh.Build's surfaceCache parameter from Dictionary to IDictionary so any IDictionary implementation compiles at call sites. Switches GameWindow._surfaceCache from Dictionary to ConcurrentDictionary so T11's streaming worker can call Build off the render thread without a lock. The TryGetValue+assign lookup inside Build is not atomic, but BuildSurface is deterministic (same palCode -> same SurfaceInfo), making last-write-wins under concurrent access benign. Comment added at the pattern site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a0741bd13a
commit
4be392b361
2 changed files with 9 additions and 3 deletions
|
|
@ -111,7 +111,9 @@ public sealed class GameWindow : IDisposable
|
|||
// LandblockMesh.Build without re-deriving these each time.
|
||||
private float[]? _heightTable;
|
||||
private AcDream.Core.Terrain.TerrainBlendingContext? _blendCtx;
|
||||
private Dictionary<uint, AcDream.Core.Terrain.SurfaceInfo>? _surfaceCache;
|
||||
// Was: Dictionary<uint, SurfaceInfo>. ConcurrentDictionary so the off-thread
|
||||
// mesh builder (A.5 T11+) can call LandblockMesh.Build without a lock.
|
||||
private System.Collections.Concurrent.ConcurrentDictionary<uint, AcDream.Core.Terrain.SurfaceInfo>? _surfaceCache;
|
||||
|
||||
// Phase A.1 Task 8: worker thread pre-builds EnvCell room-mesh sub-meshes
|
||||
// (CPU only) and stores them here. ApplyLoadedTerrain (render thread) drains
|
||||
|
|
@ -1465,7 +1467,7 @@ public sealed class GameWindow : IDisposable
|
|||
RoadAlphaRCodes: terrainAtlas.RoadAlphaRCodes);
|
||||
|
||||
_heightTable = heightTable;
|
||||
_surfaceCache = new Dictionary<uint, AcDream.Core.Terrain.SurfaceInfo>();
|
||||
_surfaceCache = new System.Collections.Concurrent.ConcurrentDictionary<uint, AcDream.Core.Terrain.SurfaceInfo>();
|
||||
|
||||
// (Bindless detection moved above — must precede TerrainAtlas.Build /
|
||||
// TerrainModernRenderer ctor so they can consume BindlessSupport.)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public static class LandblockMesh
|
|||
uint landblockY,
|
||||
float[] heightTable,
|
||||
TerrainBlendingContext ctx,
|
||||
Dictionary<uint, SurfaceInfo> surfaceCache)
|
||||
System.Collections.Generic.IDictionary<uint, SurfaceInfo> surfaceCache)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(block);
|
||||
ArgumentNullException.ThrowIfNull(heightTable);
|
||||
|
|
@ -105,6 +105,10 @@ public static class LandblockMesh
|
|||
uint palCode = TerrainBlending.GetPalCode(
|
||||
rBL, rBR, rTR, rTL, ttBL, ttBR, ttTR, ttTL);
|
||||
|
||||
// Lookup-or-build pattern. Not atomic under concurrent access
|
||||
// (TryGetValue then assign), but BuildSurface is deterministic —
|
||||
// two workers building the same palCode produce equal SurfaceInfo,
|
||||
// last-write-wins is benign.
|
||||
if (!surfaceCache.TryGetValue(palCode, out var surf))
|
||||
{
|
||||
surf = TerrainBlending.BuildSurface(palCode, ctx);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue