Symptom: terrain renders pure black in modern path (legacy renderer correct). Diagnostic at TerrainModernRenderer.Draw showed: glProgramUniformHandle(prog=4, loc=5, handle=0x100251xxx) → GL_INVALID_OPERATION (0x0502) on both terrain and alpha sampler uniforms. Root cause: the `uniform sampler2DArray` + glProgramUniformHandleARB combination is rejected by the NVIDIA Windows driver in this configuration. The handle is valid and resident; the uniform location is valid; the program is valid; but the driver refuses to bind a 64-bit handle to a sampler uniform via the program-uniform path. Fix: switch to N.5's mesh_modern pattern — pass each 64-bit handle as a `uniform uvec2` (low + high 32-bit halves) and construct the sampler at the use site via the GLSL `sampler2DArray(handle)` constructor. This form is what ARB_bindless_texture documents as universally supported and is what N.5 already uses successfully. Files: - terrain_modern.frag: replace `uniform sampler2DArray uTerrain/uAlpha` with `uniform uvec2 uTerrainHandle/uAlphaHandle` + `#define`s - TerrainModernRenderer.cs: cache uvec2 uniform locations; set via `glProgramUniform2(program, loc, low32, high32)` per frame - BindlessSupport.cs: remove now-unused `SetSamplerHandleUniform`, leave a comment noting why the helper was retired - GameWindow.cs: also strip the temporary [TERRAIN-DBG] cursor-wrap print added during the perf-baseline investigation Build green; 114/114 tests in N.5+N.5b filter still pass; user-verified terrain renders correctly in modern path post-fix. Captured fresh perf baseline: - Legacy: cpu_us median 1.5 / p95 3.0 (1 chunk = 1 glDrawElements) - Modern: cpu_us median 6.4-7.0 / p95 9-14 (51 visible LBs, 1 MDI call) Modern is ~4× slower on CPU at radius=5 because the chunked legacy path already collapsed the scene to one draw call. The architectural wins (zero glBindTexture/frame; constant-cost dispatch as A.5 raises radius) will be documented in T10's perf baseline doc; the spec's "≥10% lower CPU" acceptance criterion is invalid at radius=5 and needs revision. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
64 lines
2.4 KiB
C#
64 lines
2.4 KiB
C#
using Silk.NET.OpenGL;
|
|
using Silk.NET.OpenGL.Extensions.ARB;
|
|
|
|
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 ArbBindlessTexture _ext;
|
|
|
|
private BindlessSupport(ArbBindlessTexture extension)
|
|
{
|
|
_ext = extension;
|
|
}
|
|
|
|
public static bool TryCreate(GL gl, out BindlessSupport? support)
|
|
{
|
|
if (gl.TryGetExtension<ArbBindlessTexture>(out var ext))
|
|
{
|
|
support = new BindlessSupport(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 = _ext.GetTextureHandle(textureName);
|
|
if (!_ext.IsTextureHandleResident(h))
|
|
_ext.MakeTextureHandleResident(h);
|
|
return h;
|
|
}
|
|
|
|
/// <summary>Release residency for a handle. Call before deleting the underlying texture.</summary>
|
|
public void MakeNonResident(ulong handle)
|
|
{
|
|
if (_ext.IsTextureHandleResident(handle))
|
|
_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");
|
|
}
|
|
}
|