Move Region/environment, mandatory modern rendering, terrain, WB, texture, and sampler construction behind the typed Phase-4 composition boundary. Give every fallible GL constructor prefix retryable ownership so partial startup failure cannot leak or replay resource deletion while preserving the accepted render path and DAT inputs. Co-authored-by: Codex <codex@openai.com>
103 lines
3.9 KiB
C#
103 lines
3.9 KiB
C#
using System;
|
|
using Silk.NET.OpenGL;
|
|
|
|
namespace AcDream.App.Rendering;
|
|
|
|
/// <summary>
|
|
/// Two persistent GL sampler objects (Repeat + ClampToEdge) created once
|
|
/// per GL context. Renderers <see cref="GL.BindSampler"/> the appropriate
|
|
/// one to a texture unit instead of mutating per-texture
|
|
/// <c>GL_TEXTURE_WRAP_S/T</c> state — sampler state overrides the
|
|
/// texture's own wrap parameters, so two renderers can share the same
|
|
/// texture handle but sample it with different wrap modes safely.
|
|
///
|
|
/// <para>
|
|
/// Ported from
|
|
/// <c>references/WorldBuilder/Chorizite.OpenGLSDLBackend/OpenGLGraphicsDevice.cs:115-132</c>.
|
|
/// Filter modes match <see cref="TextureCache"/>'s upload defaults
|
|
/// (Linear / Linear, no mipmaps) so binding either sampler doesn't
|
|
/// change the visual filtering behavior — only the wrap behavior at
|
|
/// UVs outside [0, 1].
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// Lifetime: created once at GL init, disposed with the GL context.
|
|
/// Anything that binds a sampler MUST unbind it (<c>BindSampler(unit, 0)</c>)
|
|
/// before yielding to a renderer that doesn't use samplers, otherwise
|
|
/// the bound sampler's wrap mode will silently override that renderer's
|
|
/// per-texture wrap state.
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed class SamplerCache : IDisposable
|
|
{
|
|
private readonly GL _gl;
|
|
private readonly ResourceCleanupGroup _resources;
|
|
|
|
/// <summary>Sampler with WrapS = WrapT = Repeat. The default for textures uploaded by <see cref="TextureCache"/>.</summary>
|
|
public uint Wrap { get; }
|
|
|
|
/// <summary>Sampler with WrapS = WrapT = ClampToEdge. Used by sky meshes whose authored UVs are strictly in [0, 1] to avoid bilinear-filter bleed at seam edges.</summary>
|
|
public uint Clamp { get; }
|
|
|
|
public SamplerCache(GL gl)
|
|
{
|
|
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
|
|
var resources = new ResourceCleanupGroup();
|
|
uint wrap = 0;
|
|
uint clamp = 0;
|
|
try
|
|
{
|
|
wrap = GlResourceCommand.CreateName(
|
|
_gl,
|
|
"repeat sampler",
|
|
_gl.GenSampler,
|
|
_gl.DeleteSampler);
|
|
uint ownedWrap = wrap;
|
|
resources.Add(
|
|
"repeat sampler",
|
|
() => GlResourceCommand.Execute(
|
|
_gl,
|
|
$"delete repeat sampler {ownedWrap}",
|
|
() => _gl.DeleteSampler(ownedWrap)));
|
|
Configure(wrap, TextureWrapMode.Repeat, "repeat sampler");
|
|
|
|
clamp = GlResourceCommand.CreateName(
|
|
_gl,
|
|
"clamp sampler",
|
|
_gl.GenSampler,
|
|
_gl.DeleteSampler);
|
|
uint ownedClamp = clamp;
|
|
resources.Add(
|
|
"clamp sampler",
|
|
() => GlResourceCommand.Execute(
|
|
_gl,
|
|
$"delete clamp sampler {ownedClamp}",
|
|
() => _gl.DeleteSampler(ownedClamp)));
|
|
Configure(clamp, TextureWrapMode.ClampToEdge, "clamp sampler");
|
|
}
|
|
catch (Exception constructionFailure)
|
|
{
|
|
resources.RollbackConstructionAndThrow(
|
|
"SamplerCache construction failed and its sampler prefix did not cleanly roll back.",
|
|
constructionFailure);
|
|
}
|
|
|
|
Wrap = wrap;
|
|
Clamp = clamp;
|
|
_resources = resources;
|
|
}
|
|
|
|
private void Configure(uint sampler, TextureWrapMode wrap, string name) =>
|
|
GlResourceCommand.Execute(_gl, $"configure {name}", () =>
|
|
{
|
|
_gl.SamplerParameter(sampler, SamplerParameterI.WrapS, (int)wrap);
|
|
_gl.SamplerParameter(sampler, SamplerParameterI.WrapT, (int)wrap);
|
|
_gl.SamplerParameter(sampler, SamplerParameterI.MinFilter, (int)TextureMinFilter.Linear);
|
|
_gl.SamplerParameter(sampler, SamplerParameterI.MagFilter, (int)TextureMagFilter.Linear);
|
|
});
|
|
|
|
public void Dispose()
|
|
{
|
|
_resources.RetryCleanup();
|
|
}
|
|
}
|