fix(streaming): preserve portal destination ownership
Detach old-world spatial ownership atomically, prioritize destination retirement dependencies, and reveal the viewport at the retail transition edge. Give private paperdoll views independent mesh ownership and retain dormant ACE entities so portal revisits preserve server objects without extending active GPU lifetimes.
This commit is contained in:
parent
2c848d4167
commit
823936ec31
57 changed files with 2551 additions and 324 deletions
|
|
@ -21,9 +21,12 @@ namespace AcDream.App.Rendering.Wb;
|
|||
/// <c>DefaultDatReaderWriter</c> file-handle set has been removed.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
||||
public sealed class WbMeshAdapter
|
||||
: IDisposable,
|
||||
IWbMeshAdapter
|
||||
{
|
||||
internal const int MaximumUploadsPerFrame = 8;
|
||||
internal const int DestinationRevealMaximumUploadsPerFrame = 64;
|
||||
internal const long MaximumUploadBytesPerFrame = 8L * 1024 * 1024;
|
||||
internal const long MaximumArrayAllocationBytesPerFrame = 8L * 1024 * 1024;
|
||||
internal const long MaximumMipmapBytesPerFrame = 8L * 1024 * 1024;
|
||||
|
|
@ -48,22 +51,12 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
private readonly ObjectMeshManager? _meshManager;
|
||||
private readonly AcDream.App.Rendering.IGpuResourceRetirementQueue? _resourceRetirement;
|
||||
private readonly IPreparedAssetSource? _ownedPreparedAssets;
|
||||
private readonly MeshUploadFrameBudget _uploadBudget = new(new MeshUploadBudgetLimits(
|
||||
MaximumUploadsPerFrame,
|
||||
MaximumUploadBytesPerFrame,
|
||||
MaximumArrayAllocationBytesPerFrame,
|
||||
MaximumMipmapBytesPerFrame,
|
||||
MaximumNewArraysPerFrame,
|
||||
MaximumBufferUploadBytesPerFrame,
|
||||
MaximumBufferAllocationBytesPerFrame,
|
||||
MaximumBufferCopyBytesPerFrame,
|
||||
MaximumNewBuffersPerFrame,
|
||||
MaximumSingleUploadBytes,
|
||||
MaximumSingleArrayAllocationBytes,
|
||||
MaximumSingleMipmapBytes,
|
||||
MaximumSingleNewArrays,
|
||||
MaximumSingleBufferUploadBytes));
|
||||
private readonly MeshUploadFrameBudget _ordinaryUploadBudget =
|
||||
CreateUploadBudget(MaximumUploadsPerFrame);
|
||||
private readonly MeshUploadFrameBudget _destinationRevealUploadBudget =
|
||||
CreateUploadBudget(DestinationRevealMaximumUploadsPerFrame);
|
||||
private readonly HashSet<TextureAtlasManager> _mipmapsBudgeted = new();
|
||||
private bool _destinationRevealUploadPriority;
|
||||
|
||||
/// <summary>
|
||||
/// True when this instance was created via <see cref="CreateUninitialized"/>;
|
||||
|
|
@ -91,6 +84,27 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
internal (int Count, long Bytes) CpuMeshCacheDiagnostics =>
|
||||
_meshManager?.CpuCacheDiagnostics ?? default;
|
||||
|
||||
internal void SetDestinationRevealUploadPriority(bool enabled) =>
|
||||
_destinationRevealUploadPriority = enabled;
|
||||
|
||||
private static MeshUploadFrameBudget CreateUploadBudget(
|
||||
int maximumObjects) =>
|
||||
new(new MeshUploadBudgetLimits(
|
||||
maximumObjects,
|
||||
MaximumUploadBytesPerFrame,
|
||||
MaximumArrayAllocationBytesPerFrame,
|
||||
MaximumMipmapBytesPerFrame,
|
||||
MaximumNewArraysPerFrame,
|
||||
MaximumBufferUploadBytesPerFrame,
|
||||
MaximumBufferAllocationBytesPerFrame,
|
||||
MaximumBufferCopyBytesPerFrame,
|
||||
MaximumNewBuffersPerFrame,
|
||||
MaximumSingleUploadBytes,
|
||||
MaximumSingleArrayAllocationBytes,
|
||||
MaximumSingleMipmapBytes,
|
||||
MaximumSingleNewArrays,
|
||||
MaximumSingleBufferUploadBytes));
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the UI-Studio/tooling WB pipeline. Production composition
|
||||
/// supplies the validated pak source through the internal overload below;
|
||||
|
|
@ -457,7 +471,15 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
// single frame. UploadOrRequeue bounds the retries (MaxUploadRetries) so
|
||||
// a genuine defect surfaces loudly instead of the old silent sticky drop.
|
||||
List<MeshUploadQueueItem>? requeue = null;
|
||||
_uploadBudget.Reset();
|
||||
MeshUploadFrameBudget uploadBudget =
|
||||
_destinationRevealUploadPriority
|
||||
? _destinationRevealUploadBudget
|
||||
: _ordinaryUploadBudget;
|
||||
int maximumUploads =
|
||||
_destinationRevealUploadPriority
|
||||
? DestinationRevealMaximumUploadsPerFrame
|
||||
: MaximumUploadsPerFrame;
|
||||
uploadBudget.Reset();
|
||||
_mipmapsBudgeted.Clear();
|
||||
int staleDiscardCount = 0;
|
||||
bool arenaBackpressured = false;
|
||||
|
|
@ -470,7 +492,7 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
{
|
||||
GlobalMeshMaintenanceStep maintenance =
|
||||
globalBuffer.AdvanceMigration(MaximumBufferCopyBytesPerFrame);
|
||||
_uploadBudget.RecordBufferMaintenance(
|
||||
uploadBudget.RecordBufferMaintenance(
|
||||
maintenance.AllocationBytes,
|
||||
maintenance.CopyBytes,
|
||||
maintenance.NewBufferCount);
|
||||
|
|
@ -478,8 +500,8 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
}
|
||||
|
||||
while (globalBuffer?.IsMigrationInProgress != true
|
||||
&& _uploadBudget.BufferCopyBytes == 0
|
||||
&& _uploadBudget.ObjectCount < MaximumUploadsPerFrame)
|
||||
&& uploadBudget.BufferCopyBytes == 0
|
||||
&& uploadBudget.ObjectCount < maximumUploads)
|
||||
{
|
||||
staleDiscardCount += meshManager.DiscardUnownedStagedPrefix(
|
||||
MaximumStaleDiscardsPerFrame - staleDiscardCount);
|
||||
|
|
@ -501,7 +523,7 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
}
|
||||
if (capacity == GlobalMeshCapacityResult.MigrationStarted)
|
||||
{
|
||||
_uploadBudget.RecordBufferMaintenance(
|
||||
uploadBudget.RecordBufferMaintenance(
|
||||
maintenance.AllocationBytes,
|
||||
maintenance.CopyBytes,
|
||||
maintenance.NewBufferCount);
|
||||
|
|
@ -544,7 +566,7 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
next.Data,
|
||||
_mipmapsBudgeted,
|
||||
next.Generation);
|
||||
if (!_uploadBudget.TryAdmit(cost))
|
||||
if (!uploadBudget.TryAdmit(cost))
|
||||
break;
|
||||
}
|
||||
catch (NotSupportedException error)
|
||||
|
|
@ -597,29 +619,29 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
// frames. It never competes with destination materialization, and the
|
||||
// GlobalMeshBuffer policy retains enough hysteresis that portal-route
|
||||
// revisits do not alternate shrink/grow every frame.
|
||||
if (_uploadBudget.ObjectCount == 0
|
||||
if (uploadBudget.ObjectCount == 0
|
||||
&& LastMipmapArrayCount == 0
|
||||
&& meshManager.StagedMeshCount == 0
|
||||
&& globalBuffer?.IsMigrationInProgress == false
|
||||
&& globalBuffer.TryTrimUnusedTail(out GlobalMeshMaintenanceStep trim))
|
||||
{
|
||||
_uploadBudget.RecordBufferMaintenance(
|
||||
uploadBudget.RecordBufferMaintenance(
|
||||
trim.AllocationBytes,
|
||||
trim.CopyBytes,
|
||||
trim.NewBufferCount);
|
||||
meshManager.SetArenaBackpressure(true);
|
||||
}
|
||||
|
||||
LastUploadCount = _uploadBudget.ObjectCount;
|
||||
LastUploadBytes = _uploadBudget.SourceBytes;
|
||||
LastUploadCount = uploadBudget.ObjectCount;
|
||||
LastUploadBytes = uploadBudget.SourceBytes;
|
||||
LastStaleDiscardCount = staleDiscardCount;
|
||||
LastArrayAllocationBytes = _uploadBudget.ArrayAllocationBytes;
|
||||
LastPlannedMipmapBytes = _uploadBudget.MipmapBytes;
|
||||
LastNewArrayCount = _uploadBudget.NewArrayCount;
|
||||
LastBufferUploadBytes = _uploadBudget.BufferUploadBytes;
|
||||
LastBufferAllocationBytes = _uploadBudget.BufferAllocationBytes;
|
||||
LastBufferCopyBytes = _uploadBudget.BufferCopyBytes;
|
||||
LastNewBufferCount = _uploadBudget.NewBufferCount;
|
||||
LastArrayAllocationBytes = uploadBudget.ArrayAllocationBytes;
|
||||
LastPlannedMipmapBytes = uploadBudget.MipmapBytes;
|
||||
LastNewArrayCount = uploadBudget.NewArrayCount;
|
||||
LastBufferUploadBytes = uploadBudget.BufferUploadBytes;
|
||||
LastBufferAllocationBytes = uploadBudget.BufferAllocationBytes;
|
||||
LastBufferCopyBytes = uploadBudget.BufferCopyBytes;
|
||||
LastNewBufferCount = uploadBudget.NewBufferCount;
|
||||
|
||||
if (texProbe)
|
||||
EmitTexFlushProbe(pendingBefore);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue