fix(render): make reveal warmup mutation-resumable
Retain composite candidate progress across live membership generations and run a stable follow-up pass after churn, preventing ACE object-stream updates from resetting portal readiness forever. Co-authored-by: Erik Nilsson <erikn@users.noreply.github.com>
This commit is contained in:
parent
a77ba06722
commit
e991eeca34
2 changed files with 63 additions and 12 deletions
|
|
@ -114,6 +114,10 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
internal int LastCompositeWarmupPendingCount { get; private set; }
|
||||
internal const int MaximumCompositeWarmupEntitiesPerFrame = 128;
|
||||
private readonly Queue<WorldEntity> _compositeWarmupQueue = new();
|
||||
// Membership may change while ACE is streaming the destination object set.
|
||||
// Retain exact candidate progress and schedule a follow-up pass instead of
|
||||
// restarting at index zero on every generation edge.
|
||||
private readonly HashSet<WorldEntity> _compositeWarmupTracked = [];
|
||||
private IReadOnlyList<WorldEntity>? _compositeWarmupSource;
|
||||
private ulong _compositeWarmupSourceGeneration;
|
||||
private uint _compositeWarmupDestinationCell;
|
||||
|
|
@ -133,6 +137,7 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
CompositeTexturesReady = false;
|
||||
LastCompositeWarmupPendingCount = 1;
|
||||
_compositeWarmupQueue.Clear();
|
||||
_compositeWarmupTracked.Clear();
|
||||
_compositeWarmupSource = null;
|
||||
_compositeWarmupSourceGeneration = 0;
|
||||
_compositeWarmupDestinationCell = 0;
|
||||
|
|
@ -159,9 +164,7 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
_compositeWarmupSource,
|
||||
_compositeWarmupDestinationCell,
|
||||
_compositeWarmupRadius,
|
||||
_compositeWarmupSourceGeneration,
|
||||
entities,
|
||||
entityGeneration,
|
||||
destinationCell,
|
||||
radius))
|
||||
{
|
||||
|
|
@ -171,19 +174,38 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
destinationCell,
|
||||
radius);
|
||||
}
|
||||
else if (ShouldBeginCompositeWarmupRescan(
|
||||
_compositeWarmupScanComplete,
|
||||
_compositeWarmupSourceGeneration,
|
||||
entityGeneration))
|
||||
{
|
||||
BeginCompositeWarmupRescan(entities.Count, entityGeneration);
|
||||
}
|
||||
if (CompositeTexturesReady)
|
||||
return;
|
||||
|
||||
_compositeWarmupScanIndex =
|
||||
Math.Min(_compositeWarmupScanIndex, entities.Count);
|
||||
int scanEnd = Math.Min(
|
||||
entities.Count,
|
||||
_compositeWarmupScanIndex + MaximumCompositeWarmupEntitiesPerFrame);
|
||||
for (; _compositeWarmupScanIndex < scanEnd; _compositeWarmupScanIndex++)
|
||||
{
|
||||
WorldEntity entity = entities[_compositeWarmupScanIndex];
|
||||
if (IsCompositeWarmupCandidate(entity, destinationCell, radius))
|
||||
if (IsCompositeWarmupCandidate(entity, destinationCell, radius)
|
||||
&& _compositeWarmupTracked.Add(entity))
|
||||
{
|
||||
_compositeWarmupQueue.Enqueue(entity);
|
||||
}
|
||||
}
|
||||
_compositeWarmupScanComplete = _compositeWarmupScanIndex == entities.Count;
|
||||
if (ShouldBeginCompositeWarmupRescan(
|
||||
_compositeWarmupScanComplete,
|
||||
_compositeWarmupSourceGeneration,
|
||||
entityGeneration))
|
||||
{
|
||||
BeginCompositeWarmupRescan(entities.Count, entityGeneration);
|
||||
}
|
||||
|
||||
int candidatesThisPass = Math.Min(
|
||||
_compositeWarmupQueue.Count,
|
||||
|
|
@ -208,16 +230,19 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
IReadOnlyList<WorldEntity>? currentSource,
|
||||
uint currentDestinationCell,
|
||||
int currentRadius,
|
||||
ulong currentGeneration,
|
||||
IReadOnlyList<WorldEntity> nextSource,
|
||||
ulong nextGeneration,
|
||||
uint nextDestinationCell,
|
||||
int nextRadius) =>
|
||||
!ReferenceEquals(currentSource, nextSource)
|
||||
|| currentGeneration != nextGeneration
|
||||
|| currentDestinationCell != nextDestinationCell
|
||||
|| currentRadius != nextRadius;
|
||||
|
||||
internal static bool ShouldBeginCompositeWarmupRescan(
|
||||
bool scanComplete,
|
||||
ulong scanGeneration,
|
||||
ulong entityGeneration) =>
|
||||
scanComplete && scanGeneration != entityGeneration;
|
||||
|
||||
private void RebuildCompositeWarmupQueue(
|
||||
IReadOnlyList<WorldEntity> entities,
|
||||
ulong entityGeneration,
|
||||
|
|
@ -225,6 +250,7 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
int radius)
|
||||
{
|
||||
_compositeWarmupQueue.Clear();
|
||||
_compositeWarmupTracked.Clear();
|
||||
_compositeWarmupSource = entities;
|
||||
_compositeWarmupSourceGeneration = entityGeneration;
|
||||
_compositeWarmupDestinationCell = destinationCell;
|
||||
|
|
@ -235,6 +261,17 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
CompositeTexturesReady = _compositeWarmupScanComplete;
|
||||
}
|
||||
|
||||
private void BeginCompositeWarmupRescan(
|
||||
int entityCount,
|
||||
ulong entityGeneration)
|
||||
{
|
||||
_compositeWarmupSourceGeneration = entityGeneration;
|
||||
_compositeWarmupScanIndex = 0;
|
||||
_compositeWarmupScanComplete = entityCount == 0;
|
||||
CompositeTexturesReady =
|
||||
_compositeWarmupScanComplete && _compositeWarmupQueue.Count == 0;
|
||||
}
|
||||
|
||||
internal static bool IsCompositeWarmupCandidate(
|
||||
WorldEntity entity,
|
||||
uint destinationCell,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue