fix(render): Phase U.3 — scope gl_ClipDistance enable to world-geometry draws

Code review caught a portability hazard: GL_CLIP_DISTANCE0..7 was enabled globally
at init, but sky/particle/ui/debug vertex shaders don't write gl_ClipDistance —
undefined behavior that could clip them away on some drivers (benign on the dev
driver, which is why the offline check passed). Bracket the enable/disable around
only the terrain+entity (mesh_modern/terrain_modern) draws; sky/particles/UI/debug
render with clipping off. U.4's EnvCellRenderer.Render belongs inside the bracket.
Also: ClipFrame is long-lived (??= NoClip()), so Dispose now deletes its GL buffers;
fix the stale per-frame-transient comments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-30 17:42:27 +02:00
parent bf2e559369
commit 864fc5f94e
2 changed files with 54 additions and 20 deletions

View file

@ -85,6 +85,11 @@ public sealed class ClipFrame : IDisposable
private bool _glInitialized;
private bool _disposed;
// GL reference captured on the first UploadShared so Dispose can delete the two
// buffers. ClipFrame is long-lived in U.3 (GameWindow holds one via ??= NoClip()
// and reuses it every frame), so we DO own buffer teardown — see Dispose.
private GL? _gl;
private ClipFrame(byte[] regionBytes, int slotCount)
{
_regionBytes = regionBytes;
@ -197,6 +202,7 @@ public sealed class ClipFrame : IDisposable
if (!_glInitialized)
{
_gl = gl; // captured for Dispose (single context for the frame's lifetime)
_regionSsbo = gl.GenBuffer();
_terrainUbo = gl.GenBuffer();
_glInitialized = true;
@ -224,11 +230,17 @@ public sealed class ClipFrame : IDisposable
{
if (_disposed) return;
_disposed = true;
// GL buffers are deleted by the owner's GL context teardown; ClipFrame
// is a per-frame transient in U.3 (NoClip() each frame). We do not hold a
// GL handle to delete here because UploadShared may not have run. If a
// future phase makes ClipFrame long-lived, add buffer deletion guarded by
// _glInitialized + a captured GL reference.
// ClipFrame is long-lived in U.3 (GameWindow holds one via ??= NoClip() and
// reuses it every frame), so we own the two GL buffers and delete them here.
// _glInitialized guards the case where UploadShared never ran (no buffers to
// delete, and _gl was never captured).
if (_glInitialized && _gl is not null)
{
_gl.DeleteBuffer(_regionSsbo);
_gl.DeleteBuffer(_terrainUbo);
_regionSsbo = 0;
_terrainUbo = 0;
}
}
// ---- byte helpers (little-endian; matches x86/x64 GPU upload) ------------