fix(rendering): decouple portal warmup discovery
Scan published destination candidates under a separate bounded budget from expensive mesh and composite preparation so large retained worlds cannot exhaust the reveal window before candidate discovery completes.
The correction is valid on both the retained and pre-cutover draw paths, so the G4 visual rollback remains the single commit ef1d263337.
Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
a7cddc65d7
commit
129dd77ddd
2 changed files with 44 additions and 5 deletions
|
|
@ -114,7 +114,13 @@ public sealed unsafe partial class WbDrawDispatcher : IDisposable
|
|||
public DrawStats LastDrawStats { get; private set; }
|
||||
public bool CompositeTexturesReady { get; private set; } = true;
|
||||
internal int LastCompositeWarmupPendingCount { get; private set; }
|
||||
internal const int MaximumCompositeWarmupEntitiesPerFrame = 128;
|
||||
// Candidate discovery only reads already-published entity facts. Keep it
|
||||
// independently bounded from the materially more expensive mesh/texture
|
||||
// preparation below so a large retained Far-tier world cannot consume the
|
||||
// entire portal reveal window merely proving that most entities are
|
||||
// outside the destination neighborhood.
|
||||
internal const int MaximumCompositeWarmupScanEntitiesPerFrame = 4096;
|
||||
internal const int MaximumCompositeWarmupPrepareEntitiesPerFrame = 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
|
||||
|
|
@ -188,9 +194,9 @@ public sealed unsafe partial class WbDrawDispatcher : IDisposable
|
|||
|
||||
_compositeWarmupScanIndex =
|
||||
Math.Min(_compositeWarmupScanIndex, entities.Count);
|
||||
int scanEnd = Math.Min(
|
||||
entities.Count,
|
||||
_compositeWarmupScanIndex + MaximumCompositeWarmupEntitiesPerFrame);
|
||||
int scanEnd = CompositeWarmupScanEnd(
|
||||
_compositeWarmupScanIndex,
|
||||
entities.Count);
|
||||
for (; _compositeWarmupScanIndex < scanEnd; _compositeWarmupScanIndex++)
|
||||
{
|
||||
WorldEntity entity = entities[_compositeWarmupScanIndex];
|
||||
|
|
@ -211,7 +217,7 @@ public sealed unsafe partial class WbDrawDispatcher : IDisposable
|
|||
|
||||
int candidatesThisPass = Math.Min(
|
||||
_compositeWarmupQueue.Count,
|
||||
MaximumCompositeWarmupEntitiesPerFrame);
|
||||
MaximumCompositeWarmupPrepareEntitiesPerFrame);
|
||||
for (int i = 0; i < candidatesThisPass; i++)
|
||||
{
|
||||
WorldEntity entity = _compositeWarmupQueue.Dequeue();
|
||||
|
|
@ -245,6 +251,17 @@ public sealed unsafe partial class WbDrawDispatcher : IDisposable
|
|||
ulong entityGeneration) =>
|
||||
scanComplete && scanGeneration != entityGeneration;
|
||||
|
||||
internal static int CompositeWarmupScanEnd(
|
||||
int scanIndex,
|
||||
int entityCount)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(scanIndex);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(entityCount);
|
||||
return Math.Min(
|
||||
entityCount,
|
||||
scanIndex + MaximumCompositeWarmupScanEntitiesPerFrame);
|
||||
}
|
||||
|
||||
private void RebuildCompositeWarmupQueue(
|
||||
IReadOnlyList<WorldEntity> entities,
|
||||
ulong entityGeneration,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue