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:
Erik 2026-07-22 14:42:14 +02:00
parent fec0d94148
commit c87b15303d
41 changed files with 3768 additions and 355 deletions

View file

@ -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.");
}
}