using Silk.NET.OpenGL; using Silk.NET.OpenGL.Extensions.ARB; using AcDream.App.Rendering; namespace AcDream.App.Rendering.Wb; /// /// Thin wrapper around + capability detection /// for the modern rendering path. Constructed once at startup via /// , which returns false if the extension isn't present. /// 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(out var ext)) { support = new BindlessSupport(gl, ext); return true; } support = null; return false; } /// Get a 64-bit bindless handle for the texture and make it resident. /// Idempotent: handle is the same for a given texture name. 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; } /// Release residency for a handle. Call before deleting the underlying texture. 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. /// Detect GL_ARB_shader_draw_parameters in addition to bindless. /// N.5's vertex shader uses gl_BaseInstanceARB and gl_DrawIDARB /// from this extension. public bool HasShaderDrawParameters(GL gl) { return gl.IsExtensionPresent("GL_ARB_shader_draw_parameters"); } }