Commit graph

5 commits

Author SHA1 Message Date
Erik
28d2c6018e feat(A.5 T22.5): wire QualityPreset into renderer + streaming (commit 2/2)
GameWindow.OnLoad resolves QualitySettings.From(_persistedDisplay.Quality)
+ WithEnvOverrides() immediately after LoadAndApplyPersistedSettings, stores
result in _resolvedQuality field. All six quality dimensions applied:

- NearRadius / FarRadius: replace old T16 env-var-only block; preset drives
  the radii, legacy ACDREAM_STREAM_RADIUS override still honoured.
- MsaaSamples: WindowOptions.Samples reads from startup quality resolution
  in Run() (pre-window-create read from SettingsStore). MSAA cannot change
  at runtime; ReapplyQualityPreset logs a restart-required warning if the
  new preset would change it.
- AnisotropicLevel: TerrainAtlas.SetAnisotropic() called after Build() and
  again in ReapplyQualityPreset. Temporarily removes bindless residency
  before the GL TexParameter call, re-makes resident after.
- AlphaToCoverage: WbDrawDispatcher.AlphaToCoverage property gates the
  glEnable/glDisable(SampleAlphaToCoverage) pair around the opaque pass.
- MaxCompletionsPerFrame: set on StreamingController after construction
  and after each mid-session restart.

ReapplyQualityPreset(QualityPreset) method handles mid-session changes
(Settings panel Quality dropdown Save): rebuilds streamer + controller for
radius changes, toggles A2C and aniso immediately, logs MSAA restart caveat.
onSaveDisplay callback updated to call ReapplyQualityPreset when Quality
field changes.

TerrainModernRenderer.Atlas property added to expose the atlas for
mid-session aniso updates.

991 tests passing, 8 pre-existing failures unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 08:43:06 +02:00
Erik
aff35d2a76 refactor(A.5 T15): TerrainModernRenderer.AddLandblockWithMesh entry point
T13 routes worker-built meshes from LandblockStreamResult.Loaded.MeshData
into the renderer. AddLandblockWithMesh accepts a prebuilt mesh + origin
and delegates to the existing AddLandblock(uint, LandblockMeshData, Vector3)
so both paths share one upload path (Approach B -- AddLandblock already
takes a prebuilt mesh; no inline build to extract).

GameWindow's T16 lambda captures liveCenterX/Y and passes the derived
origin; the renderer stays origin-agnostic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 07:54:40 +02:00
Erik
da56063be5 fix(N.5b): black terrain — switch to uvec2 handle + sampler constructor
Symptom: terrain renders pure black in modern path (legacy renderer
correct). Diagnostic at TerrainModernRenderer.Draw showed:
  glProgramUniformHandle(prog=4, loc=5, handle=0x100251xxx) → GL_INVALID_OPERATION (0x0502)
on both terrain and alpha sampler uniforms.

Root cause: the `uniform sampler2DArray` + glProgramUniformHandleARB
combination is rejected by the NVIDIA Windows driver in this configuration.
The handle is valid and resident; the uniform location is valid; the
program is valid; but the driver refuses to bind a 64-bit handle to a
sampler uniform via the program-uniform path.

Fix: switch to N.5's mesh_modern pattern — pass each 64-bit handle as a
`uniform uvec2` (low + high 32-bit halves) and construct the sampler at
the use site via the GLSL `sampler2DArray(handle)` constructor. This
form is what ARB_bindless_texture documents as universally supported and
is what N.5 already uses successfully.

Files:
- terrain_modern.frag: replace `uniform sampler2DArray uTerrain/uAlpha`
  with `uniform uvec2 uTerrainHandle/uAlphaHandle` + `#define`s
- TerrainModernRenderer.cs: cache uvec2 uniform locations; set via
  `glProgramUniform2(program, loc, low32, high32)` per frame
- BindlessSupport.cs: remove now-unused `SetSamplerHandleUniform`,
  leave a comment noting why the helper was retired
- GameWindow.cs: also strip the temporary [TERRAIN-DBG] cursor-wrap
  print added during the perf-baseline investigation

Build green; 114/114 tests in N.5+N.5b filter still pass; user-verified
terrain renders correctly in modern path post-fix. Captured fresh perf
baseline:
- Legacy:  cpu_us median  1.5  / p95  3.0  (1 chunk = 1 glDrawElements)
- Modern:  cpu_us median  6.4-7.0 / p95  9-14 (51 visible LBs, 1 MDI call)

Modern is ~4× slower on CPU at radius=5 because the chunked legacy path
already collapsed the scene to one draw call. The architectural wins
(zero glBindTexture/frame; constant-cost dispatch as A.5 raises radius)
will be documented in T10's perf baseline doc; the spec's
"≥10% lower CPU" acceptance criterion is invalid at radius=5 and needs
revision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:53:21 +02:00
Erik
3418f65462 fix(N.5b T6): index-length validation + document VertsPerLandblock %6 invariant
Code review (Important #1): AddLandblock validated Vertices.Length but
not Indices.Length. The indices loop indexes meshData.Indices[0..383]
unconditionally — out-of-range input would throw IndexOutOfRangeException
instead of the clearer ArgumentException the vertex check raises. Today
LandblockMesh.Build always produces 384/384, so this is defensive
forward-compat for future mesh sources.

Code review (Important #2): The shader (terrain_modern.vert:gl_VertexID
% 6) only correctly picks the cell-corner index because we bake
`slot * VertsPerLandblock` into indices and 384 is a multiple of 6.
That invariant is now documented in a comment near the constant — anyone
changing it must audit the shader.

Build green: 0 errors / 0 warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:15:51 +02:00
Erik
0a77bd1fd7 phase(N.5b) Task 6: TerrainModernRenderer
The new terrain dispatcher. Single global VBO/EBO with a slot
allocator (one slot per landblock, 384 verts × 40 bytes per slot).
Per-frame: build DEIC array from visible slots, upload, dispatch
via glMultiDrawElementsIndirect. Atlas textures bound via bindless
handles set per-frame as sampler uniforms.

Total ~6-8 GL calls per frame for terrain regardless of visible
landblock count (vs today's per-LB binds at radius=2 → ~25 calls,
radius=5 → ~121 calls).

API mirrors TerrainChunkRenderer so GameWindow integration in T8 is
a drop-in field+ctor swap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:05:28 +02:00