using System.Runtime.ExceptionServices; namespace AcDream.App.Rendering; /// /// Temporarily removes bindless residency around texture-state mutation while /// retaining the obligation to restore the pair across failed mutation or /// failed reacquisition attempts. /// 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(); } }