refactor(lifetime): own render resource prefixes
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>
This commit is contained in:
parent
fec0d94148
commit
c87b15303d
41 changed files with 3768 additions and 355 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using Silk.NET.OpenGL;
|
||||
using Silk.NET.OpenGL.Extensions.ARB;
|
||||
using AcDream.App.Rendering;
|
||||
|
||||
namespace AcDream.App.Rendering.Wb;
|
||||
|
||||
|
|
@ -10,10 +11,12 @@ namespace AcDream.App.Rendering.Wb;
|
|||
/// </summary>
|
||||
public sealed class BindlessSupport
|
||||
{
|
||||
private readonly GL _gl;
|
||||
private readonly ArbBindlessTexture _ext;
|
||||
|
||||
private BindlessSupport(ArbBindlessTexture extension)
|
||||
private BindlessSupport(GL gl, ArbBindlessTexture extension)
|
||||
{
|
||||
_gl = gl;
|
||||
_ext = extension;
|
||||
}
|
||||
|
||||
|
|
@ -21,7 +24,7 @@ public sealed class BindlessSupport
|
|||
{
|
||||
if (gl.TryGetExtension<ArbBindlessTexture>(out var ext))
|
||||
{
|
||||
support = new BindlessSupport(ext);
|
||||
support = new BindlessSupport(gl, ext);
|
||||
return true;
|
||||
}
|
||||
support = null;
|
||||
|
|
@ -32,17 +35,42 @@ public sealed class BindlessSupport
|
|||
/// 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);
|
||||
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)
|
||||
{
|
||||
if (_ext.IsTextureHandleResident(handle))
|
||||
_ext.MakeTextureHandleNonResident(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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Silk.NET.OpenGL;
|
||||
using AcDream.App.Rendering;
|
||||
using System.Runtime.ExceptionServices;
|
||||
|
||||
namespace AcDream.App.Rendering.Wb;
|
||||
|
||||
|
|
@ -96,41 +97,68 @@ internal static unsafe class TrackedGlResource
|
|||
|
||||
public static uint CreateBuffer(GL gl, string context)
|
||||
{
|
||||
GLHelpers.ThrowOnResourceError(gl, $"{context} (precondition)");
|
||||
uint name = gl.GenBuffer();
|
||||
try
|
||||
{
|
||||
if (name == 0)
|
||||
throw new InvalidOperationException($"OpenGL returned buffer name zero. Context: {context}");
|
||||
GLHelpers.ThrowOnResourceError(gl, context);
|
||||
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.Buffer);
|
||||
return name;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (name != 0)
|
||||
gl.DeleteBuffer(name);
|
||||
throw;
|
||||
}
|
||||
return CreateTrackedName(
|
||||
gl,
|
||||
"buffer",
|
||||
context,
|
||||
gl.GenBuffer,
|
||||
name => GlResourceCommand.DeleteBuffer(
|
||||
gl,
|
||||
name,
|
||||
$"rollback buffer {name} after failed {context}"),
|
||||
() => GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.Buffer));
|
||||
}
|
||||
|
||||
public static uint CreateVertexArray(GL gl, string context)
|
||||
{
|
||||
GLHelpers.ThrowOnResourceError(gl, $"{context} (precondition)");
|
||||
uint name = gl.GenVertexArray();
|
||||
return CreateTrackedName(
|
||||
gl,
|
||||
"vertex-array",
|
||||
context,
|
||||
gl.GenVertexArray,
|
||||
name => GlResourceCommand.DeleteVertexArray(
|
||||
gl,
|
||||
name,
|
||||
$"rollback vertex array {name} after failed {context}"),
|
||||
() => GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.VAO));
|
||||
}
|
||||
|
||||
private static uint CreateTrackedName(
|
||||
GL gl,
|
||||
string resourceName,
|
||||
string context,
|
||||
Func<uint> create,
|
||||
Action<uint> rollback,
|
||||
Action publishAccounting)
|
||||
{
|
||||
uint name = GlResourceCommand.CreateName(
|
||||
gl,
|
||||
$"{resourceName} for {context}",
|
||||
create,
|
||||
rollback);
|
||||
var cleanup = new ResourceCleanupGroup();
|
||||
cleanup.Add($"{resourceName} name {name}", () => rollback(name));
|
||||
try
|
||||
{
|
||||
if (name == 0)
|
||||
throw new InvalidOperationException($"OpenGL returned vertex-array name zero. Context: {context}");
|
||||
GLHelpers.ThrowOnResourceError(gl, context);
|
||||
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.VAO);
|
||||
publishAccounting();
|
||||
return name;
|
||||
}
|
||||
catch
|
||||
catch (Exception publicationFailure)
|
||||
{
|
||||
if (name != 0)
|
||||
gl.DeleteVertexArray(name);
|
||||
throw;
|
||||
try
|
||||
{
|
||||
cleanup.RetryCleanup();
|
||||
}
|
||||
catch (Exception cleanupFailure)
|
||||
{
|
||||
throw new GlResourceConstructionException(
|
||||
$"Publishing {resourceName} accounting failed and GL name {name} could not be released.",
|
||||
cleanup,
|
||||
[publicationFailure, cleanupFailure]);
|
||||
}
|
||||
|
||||
ExceptionDispatchInfo.Capture(publicationFailure).Throw();
|
||||
throw new InvalidOperationException("Unreachable resource-publication path.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue