refactor(sky): replace per-frame wrap-mode mutation with persistent samplers
Ports WorldBuilder's GL sampler-object pattern
(references/WorldBuilder/Chorizite.OpenGLSDLBackend/OpenGLGraphicsDevice.cs:115-132,
SkyboxRenderManager.cs:312). Two persistent samplers (Repeat +
ClampToEdge) are created once at GL init; the sky pass binds the
appropriate one to texture unit 0 per submesh instead of mutating
per-texture GL_TEXTURE_WRAP_S/T state.
Why this is better than the prior M1 track-and-restore hack:
1. Sampler state is decoupled from texture state. Two renderers can
share the same texture handle but sample it with different wrap
modes simultaneously and safely — sampler state at the bind point
overrides the texture's own wrap parameters.
2. No bookkeeping. Drops the HashSet<uint> clamped-textures tracking
and the end-of-pass restore loop. The only restore needed is
BindSampler(0, 0) to release unit 0 back to per-texture state.
3. Constant cost. Sampler objects are created once per GL context,
not per draw. Filter modes match TextureCache's upload defaults
(Linear/Linear, no mipmaps) so the binding is purely a wrap-mode
selection.
Field count: SkyRenderer.cs -28 lines, +14 lines. GameWindow.cs gets
the SamplerCache field + ctor + Dispose. SkyRenderer disposed before
SamplerCache so the sky teardown path doesn't reference a freed
sampler handle.
dotnet build green, dotnet test green: 695 / 393 / 243 = 1331 passed
(unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ec1bbb4f43
commit
3d21c1352a
3 changed files with 90 additions and 40 deletions
|
|
@ -28,6 +28,7 @@ public sealed class GameWindow : IDisposable
|
|||
private InstancedMeshRenderer? _staticMesh;
|
||||
private Shader? _meshShader;
|
||||
private TextureCache? _textureCache;
|
||||
private SamplerCache? _samplerCache;
|
||||
private DebugLineRenderer? _debugLines;
|
||||
// K-fix4 (2026-04-26): default OFF. The orange BSP / green cylinder
|
||||
// wireframes are noisy outdoors and confuse first-time users into
|
||||
|
|
@ -1210,6 +1211,12 @@ public sealed class GameWindow : IDisposable
|
|||
_surfaceCache = new Dictionary<uint, AcDream.Core.Terrain.SurfaceInfo>();
|
||||
|
||||
_textureCache = new TextureCache(_gl, _dats);
|
||||
// Two persistent GL sampler objects (Repeat + ClampToEdge) so
|
||||
// the sky pass can pick wrap mode per submesh without mutating
|
||||
// shared per-texture wrap state. See SamplerCache + the
|
||||
// WorldBuilder reference at
|
||||
// references/WorldBuilder/Chorizite.OpenGLSDLBackend/OpenGLGraphicsDevice.cs:115-132.
|
||||
_samplerCache = new SamplerCache(_gl);
|
||||
_staticMesh = new InstancedMeshRenderer(_gl, _meshShader, _textureCache);
|
||||
|
||||
// Phase G.1 sky renderer — its own shader (sky.vert / sky.frag)
|
||||
|
|
@ -1219,7 +1226,7 @@ public sealed class GameWindow : IDisposable
|
|||
Path.Combine(shadersDir, "sky.vert"),
|
||||
Path.Combine(shadersDir, "sky.frag"));
|
||||
_skyRenderer = new AcDream.App.Rendering.Sky.SkyRenderer(
|
||||
_gl, _dats, skyShader, _textureCache);
|
||||
_gl, _dats, skyShader, _textureCache, _samplerCache);
|
||||
|
||||
// Phase G.1 particle renderer — renders rain / snow / spell auras
|
||||
// spawned into the shared ParticleSystem as billboard quads.
|
||||
|
|
@ -6426,12 +6433,13 @@ public sealed class GameWindow : IDisposable
|
|||
_liveSession?.Dispose();
|
||||
_audioEngine?.Dispose(); // Phase E.2: stop all voices, close AL context
|
||||
_staticMesh?.Dispose();
|
||||
_skyRenderer?.Dispose(); // depends on sampler cache; dispose first
|
||||
_samplerCache?.Dispose();
|
||||
_textureCache?.Dispose();
|
||||
_meshShader?.Dispose();
|
||||
_terrain?.Dispose();
|
||||
_shader?.Dispose();
|
||||
_sceneLightingUbo?.Dispose();
|
||||
_skyRenderer?.Dispose();
|
||||
_particleRenderer?.Dispose();
|
||||
_debugLines?.Dispose();
|
||||
_textRenderer?.Dispose();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue