Give terrain, sky, retained UI, portal preparation, and the update/render frame pair explicit single owners. Make shader, texture, text, bindless, and GL construction prefixes checked and retryable so partial failure cannot lose or replay resource ownership. Co-authored-by: Codex <codex@openai.com>
92 lines
3.3 KiB
C#
92 lines
3.3 KiB
C#
using Silk.NET.OpenGL;
|
|
using Silk.NET.OpenGL.Extensions.ARB;
|
|
using AcDream.App.Rendering;
|
|
|
|
namespace AcDream.App.Rendering.Wb;
|
|
|
|
/// <summary>
|
|
/// Thin wrapper around <see cref="ArbBindlessTexture"/> + capability detection
|
|
/// for the modern rendering path. Constructed once at startup via
|
|
/// <see cref="TryCreate"/>, which returns false if the extension isn't present.
|
|
/// </summary>
|
|
public sealed class BindlessSupport
|
|
{
|
|
private readonly GL _gl;
|
|
private readonly ArbBindlessTexture _ext;
|
|
|
|
private BindlessSupport(GL gl, ArbBindlessTexture extension)
|
|
{
|
|
_gl = gl;
|
|
_ext = extension;
|
|
}
|
|
|
|
public static bool TryCreate(GL gl, out BindlessSupport? support)
|
|
{
|
|
if (gl.TryGetExtension<ArbBindlessTexture>(out var ext))
|
|
{
|
|
support = new BindlessSupport(gl, ext);
|
|
return true;
|
|
}
|
|
support = null;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Get a 64-bit bindless handle for the texture and make it resident.
|
|
/// Idempotent: handle is the same for a given texture name.</summary>
|
|
public ulong GetResidentHandle(uint textureName)
|
|
{
|
|
ulong h = GlResourceCommand.Execute(
|
|
_gl,
|
|
$"get bindless handle for texture {textureName}",
|
|
() => _ext.GetTextureHandle(textureName));
|
|
if (h == 0)
|
|
throw new InvalidOperationException(
|
|
$"OpenGL returned no bindless handle for texture {textureName}.");
|
|
|
|
bool resident = GlResourceCommand.Execute(
|
|
_gl,
|
|
$"query bindless handle {h} residency",
|
|
() => _ext.IsTextureHandleResident(h));
|
|
if (!resident)
|
|
{
|
|
GlResourceCommand.Execute(
|
|
_gl,
|
|
$"make bindless handle {h} resident",
|
|
() => _ext.MakeTextureHandleResident(h));
|
|
}
|
|
return h;
|
|
}
|
|
|
|
/// <summary>Release residency for a handle. Call before deleting the underlying texture.</summary>
|
|
public void MakeNonResident(ulong handle)
|
|
{
|
|
bool resident = GlResourceCommand.Execute(
|
|
_gl,
|
|
$"query bindless handle {handle} residency before release",
|
|
() => _ext.IsTextureHandleResident(handle));
|
|
if (!resident)
|
|
return;
|
|
|
|
GlResourceCommand.Execute(
|
|
_gl,
|
|
$"make bindless handle {handle} non-resident",
|
|
() => _ext.MakeTextureHandleNonResident(handle));
|
|
}
|
|
|
|
// Phase N.5b note: a `SetSamplerHandleUniform` wrapper was added in T6
|
|
// and removed when terrain rendering surfaced GL_INVALID_OPERATION on
|
|
// NVIDIA Windows for the `uniform sampler2DArray` + glProgramUniformHandleARB
|
|
// combination. The replacement pattern (uvec2 handle uniform + GLSL
|
|
// sampler-from-handle constructor — see terrain_modern.frag) lives at the
|
|
// call site via plain `_gl.ProgramUniform2(program, loc, low, high)`. If
|
|
// you re-introduce a sampler-handle helper, restrict it to drivers known
|
|
// to accept the direct sampler-uniform path.
|
|
|
|
/// <summary>Detect <c>GL_ARB_shader_draw_parameters</c> in addition to bindless.
|
|
/// N.5's vertex shader uses <c>gl_BaseInstanceARB</c> and <c>gl_DrawIDARB</c>
|
|
/// from this extension.</summary>
|
|
public bool HasShaderDrawParameters(GL gl)
|
|
{
|
|
return gl.IsExtensionPresent("GL_ARB_shader_draw_parameters");
|
|
}
|
|
}
|