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>
94 lines
2.5 KiB
C#
94 lines
2.5 KiB
C#
namespace AcDream.App.Rendering;
|
|
|
|
/// <summary>
|
|
/// Owns the two independent residency edges used by TerrainAtlas. Acquisition
|
|
/// and release publish each successful edge immediately, so a partial failure
|
|
/// retries only work that is still pending.
|
|
/// </summary>
|
|
internal sealed class BindlessTexturePair(
|
|
uint firstTexture,
|
|
uint secondTexture,
|
|
Func<uint, ulong> acquire,
|
|
Action<ulong> release)
|
|
{
|
|
private ulong _firstHandle;
|
|
private ulong _secondHandle;
|
|
private bool _firstResident;
|
|
private bool _secondResident;
|
|
|
|
public bool IsFullyResident => _firstResident && _secondResident;
|
|
public bool HasAnyResident => _firstResident || _secondResident;
|
|
|
|
public (ulong First, ulong Second) Acquire()
|
|
{
|
|
if (!_firstResident)
|
|
{
|
|
_firstHandle = acquire(firstTexture);
|
|
_firstResident = true;
|
|
}
|
|
|
|
if (!_secondResident)
|
|
{
|
|
try
|
|
{
|
|
_secondHandle = acquire(secondTexture);
|
|
_secondResident = true;
|
|
}
|
|
catch (Exception acquisitionFailure)
|
|
{
|
|
try
|
|
{
|
|
Release();
|
|
}
|
|
catch (Exception cleanupFailure)
|
|
{
|
|
throw new AggregateException(
|
|
"Second bindless texture acquisition failed and the resident prefix did not cleanly roll back.",
|
|
acquisitionFailure,
|
|
cleanupFailure);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return (_firstHandle, _secondHandle);
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
List<Exception>? failures = null;
|
|
if (_firstResident)
|
|
{
|
|
try
|
|
{
|
|
release(_firstHandle);
|
|
_firstResident = false;
|
|
_firstHandle = 0;
|
|
}
|
|
catch (Exception failure)
|
|
{
|
|
(failures ??= []).Add(failure);
|
|
}
|
|
}
|
|
|
|
if (_secondResident)
|
|
{
|
|
try
|
|
{
|
|
release(_secondHandle);
|
|
_secondResident = false;
|
|
_secondHandle = 0;
|
|
}
|
|
catch (Exception failure)
|
|
{
|
|
(failures ??= []).Add(failure);
|
|
}
|
|
}
|
|
|
|
if (failures is not null)
|
|
throw new AggregateException(
|
|
"One or more bindless texture handles could not be made non-resident.",
|
|
failures);
|
|
}
|
|
}
|