acdream/src/AcDream.App/Rendering/BindlessTextureMutationGuard.cs
Erik c87b15303d 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>
2026-07-22 14:42:14 +02:00

68 lines
2 KiB
C#

using System.Runtime.ExceptionServices;
namespace AcDream.App.Rendering;
/// <summary>
/// Temporarily removes bindless residency around texture-state mutation while
/// retaining the obligation to restore the pair across failed mutation or
/// failed reacquisition attempts.
/// </summary>
internal sealed class BindlessTextureMutationGuard(BindlessTexturePair pair)
{
private bool _restoreRequired;
private bool _operationActive;
internal bool RestoreRequired => _restoreRequired;
public void Execute(Action mutation)
{
ArgumentNullException.ThrowIfNull(mutation);
if (_operationActive)
throw new InvalidOperationException("A bindless texture mutation is already active.");
_operationActive = true;
Exception? mutationFailure = null;
Exception? restoreFailure = null;
try
{
_restoreRequired |= pair.HasAnyResident;
if (pair.HasAnyResident)
pair.Release();
mutation();
}
catch (Exception failure)
{
mutationFailure = failure;
}
finally
{
if (_restoreRequired)
{
try
{
_ = pair.Acquire();
_restoreRequired = false;
}
catch (Exception failure)
{
restoreFailure = failure;
}
}
_operationActive = false;
}
if (mutationFailure is not null && restoreFailure is not null)
{
throw new AggregateException(
"Texture-state mutation failed and bindless residency could not be restored.",
mutationFailure,
restoreFailure);
}
if (mutationFailure is not null)
ExceptionDispatchInfo.Capture(mutationFailure).Throw();
if (restoreFailure is not null)
ExceptionDispatchInfo.Capture(restoreFailure).Throw();
}
}