perf(streaming): cursor publication across frame budgets
This commit is contained in:
parent
bb16f74fd4
commit
98f1ac8934
32 changed files with 2215 additions and 823 deletions
|
|
@ -24,7 +24,9 @@ public sealed class LandblockRenderPublication
|
|||
Vector3 origin,
|
||||
Dictionary<uint, LoadedCell> visibilityCells,
|
||||
Vector3 aabbMin,
|
||||
Vector3 aabbMax)
|
||||
Vector3 aabbMax,
|
||||
BuildingRegistryPublication? buildingPublication,
|
||||
EnvCellLandblockPublication? envCellPublication)
|
||||
{
|
||||
Owner = owner;
|
||||
Build = build;
|
||||
|
|
@ -33,6 +35,8 @@ public sealed class LandblockRenderPublication
|
|||
_visibilityCells = new ReadOnlyDictionary<uint, LoadedCell>(visibilityCells);
|
||||
AabbMin = aabbMin;
|
||||
AabbMax = aabbMax;
|
||||
BuildingPublication = buildingPublication;
|
||||
EnvCellPublication = envCellPublication;
|
||||
}
|
||||
|
||||
internal object Owner { get; }
|
||||
|
|
@ -40,6 +44,8 @@ public sealed class LandblockRenderPublication
|
|||
internal LandblockMeshData MeshData { get; }
|
||||
internal Vector3 AabbMin { get; }
|
||||
internal Vector3 AabbMax { get; }
|
||||
internal BuildingRegistryPublication? BuildingPublication { get; }
|
||||
internal EnvCellLandblockPublication? EnvCellPublication { get; }
|
||||
internal bool TerrainCommitted { get; set; }
|
||||
internal bool VisibilityCommitted { get; set; }
|
||||
internal bool AabbCommitted { get; set; }
|
||||
|
|
@ -92,6 +98,7 @@ public sealed class LandblockRenderPublisher
|
|||
private readonly CellVisibility _cellVisibility;
|
||||
private readonly GpuWorldState _worldState;
|
||||
private readonly Action<EnvCellLandblockBuild>? _commitEnvCells;
|
||||
private readonly IEnvCellLandblockPublisher? _envCellPublisher;
|
||||
private readonly Action<EnvCellLandblockBuild>? _prepareEnvCells;
|
||||
private readonly Action<uint>? _removeEnvCells;
|
||||
private readonly Dictionary<uint, BuildingRegistry> _buildingRegistries = new();
|
||||
|
|
@ -114,7 +121,8 @@ public sealed class LandblockRenderPublisher
|
|||
GpuWorldState worldState,
|
||||
Action<EnvCellLandblockBuild>? commitEnvCells = null,
|
||||
Action<EnvCellLandblockBuild>? prepareEnvCells = null,
|
||||
Action<uint>? removeEnvCells = null)
|
||||
Action<uint>? removeEnvCells = null,
|
||||
IEnvCellLandblockPublisher? envCellPublisher = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(publishTerrain);
|
||||
ArgumentNullException.ThrowIfNull(removeTerrain);
|
||||
|
|
@ -126,6 +134,13 @@ public sealed class LandblockRenderPublisher
|
|||
_cellVisibility = cellVisibility;
|
||||
_worldState = worldState;
|
||||
_commitEnvCells = commitEnvCells;
|
||||
_envCellPublisher = envCellPublisher;
|
||||
if (_commitEnvCells is not null && _envCellPublisher is not null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Supply either the retained EnvCell publisher or the compatibility callback, not both.",
|
||||
nameof(envCellPublisher));
|
||||
}
|
||||
_prepareEnvCells = prepareEnvCells;
|
||||
_removeEnvCells = removeEnvCells;
|
||||
}
|
||||
|
|
@ -197,6 +212,17 @@ public sealed class LandblockRenderPublisher
|
|||
visibilityCells[cell.CellId] = cell;
|
||||
}
|
||||
(Vector3 aabbMin, Vector3 aabbMax) = ComputeAabb(meshData, origin);
|
||||
BuildingRegistryPublication? buildingPublication =
|
||||
build.Landblock.PhysicsDats?.Info is { } info
|
||||
? BuildingLoader.PreparePublication(
|
||||
info,
|
||||
landblockId,
|
||||
visibilityCells)
|
||||
: null;
|
||||
EnvCellLandblockPublication? envCellPublication =
|
||||
build.EnvCells is { } retainedEnvCells
|
||||
? _envCellPublisher?.PreparePublication(retainedEnvCells)
|
||||
: null;
|
||||
return new LandblockRenderPublication(
|
||||
_receiptOwner,
|
||||
build,
|
||||
|
|
@ -204,7 +230,9 @@ public sealed class LandblockRenderPublisher
|
|||
origin,
|
||||
visibilityCells,
|
||||
aabbMin,
|
||||
aabbMax);
|
||||
aabbMax,
|
||||
buildingPublication,
|
||||
envCellPublication);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -214,13 +242,25 @@ public sealed class LandblockRenderPublisher
|
|||
public void BeginPublication(LandblockRenderPublication publication)
|
||||
{
|
||||
ValidateReceipt(publication);
|
||||
if (publication.BeginCommitted)
|
||||
return;
|
||||
while (!AdvanceBeginOne(publication))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
long beginStarted = Stopwatch.GetTimestamp();
|
||||
/// <summary>
|
||||
/// Advances one exact render-prefix mutation from the retained receipt.
|
||||
/// Terrain, visibility, and AABB publication remain ordered and retries do
|
||||
/// not replay an already committed prefix.
|
||||
/// </summary>
|
||||
internal bool AdvanceBeginOne(LandblockRenderPublication publication)
|
||||
{
|
||||
ValidateReceipt(publication);
|
||||
if (publication.BeginCommitted)
|
||||
return true;
|
||||
|
||||
long started = Stopwatch.GetTimestamp();
|
||||
LandblockBuild build = publication.Build;
|
||||
uint landblockId = publication.LandblockId;
|
||||
|
||||
if (!publication.TerrainCommitted)
|
||||
{
|
||||
long terrainStarted = Stopwatch.GetTimestamp();
|
||||
|
|
@ -228,15 +268,13 @@ public sealed class LandblockRenderPublisher
|
|||
_terrainPublishTicks += Stopwatch.GetTimestamp() - terrainStarted;
|
||||
publication.TerrainCommitted = true;
|
||||
}
|
||||
|
||||
if (!publication.VisibilityCommitted)
|
||||
else if (!publication.VisibilityCommitted)
|
||||
{
|
||||
if (build.EnvCells is { } envCells)
|
||||
_cellVisibility.CommitLandblock(landblockId, envCells.VisibilityCells);
|
||||
publication.VisibilityCommitted = true;
|
||||
}
|
||||
|
||||
if (!publication.AabbCommitted)
|
||||
else if (!publication.AabbCommitted)
|
||||
{
|
||||
_worldState.SetLandblockAabb(
|
||||
landblockId,
|
||||
|
|
@ -244,10 +282,14 @@ public sealed class LandblockRenderPublisher
|
|||
publication.AabbMax);
|
||||
publication.AabbCommitted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
publication.BeginCommitted = true;
|
||||
_beginCount++;
|
||||
}
|
||||
|
||||
publication.BeginCommitted = true;
|
||||
_beginCount++;
|
||||
_beginPublishTicks += Stopwatch.GetTimestamp() - beginStarted;
|
||||
_beginPublishTicks += Stopwatch.GetTimestamp() - started;
|
||||
return publication.BeginCommitted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -256,40 +298,77 @@ public sealed class LandblockRenderPublisher
|
|||
/// receives the complete immutable transaction.
|
||||
/// </summary>
|
||||
public void CompletePublication(LandblockRenderPublication publication)
|
||||
{
|
||||
ValidateReceipt(publication);
|
||||
if (!publication.BeginCommitted)
|
||||
throw new InvalidOperationException(
|
||||
"Render publication cannot complete before its prefix commits.");
|
||||
while (!AdvanceCompleteOne(publication))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances one exact render-suffix mutation. The building registry is
|
||||
/// visible before the EnvCell renderer snapshot, matching the existing
|
||||
/// retail-rooted ordering.
|
||||
/// </summary>
|
||||
internal bool AdvanceCompleteOne(LandblockRenderPublication publication)
|
||||
{
|
||||
ValidateReceipt(publication);
|
||||
if (!publication.BeginCommitted)
|
||||
throw new InvalidOperationException(
|
||||
"Render publication cannot complete before its prefix commits.");
|
||||
if (publication.CompletionCommitted)
|
||||
return;
|
||||
return true;
|
||||
|
||||
long started = Stopwatch.GetTimestamp();
|
||||
LandblockBuild build = publication.Build;
|
||||
uint landblockId = publication.LandblockId;
|
||||
if (!publication.BuildingRegistryCommitted)
|
||||
if (publication.BuildingPublication is { PreparationCommitted: false }
|
||||
buildingPublication)
|
||||
{
|
||||
if (build.Landblock.PhysicsDats?.Info is { } info)
|
||||
BuildingLoader.AdvancePreparationOne(buildingPublication);
|
||||
}
|
||||
else if (!publication.BuildingRegistryCommitted)
|
||||
{
|
||||
if (publication.BuildingPublication is { } completedBuildings)
|
||||
{
|
||||
BuildingLoader.CommitPublication(completedBuildings);
|
||||
uint registryKey = landblockId & 0xFFFF0000u;
|
||||
_buildingRegistries[registryKey] = BuildingLoader.Build(
|
||||
info,
|
||||
landblockId,
|
||||
publication.VisibilityCells);
|
||||
_buildingRegistries[registryKey] =
|
||||
completedBuildings.Registry;
|
||||
}
|
||||
publication.BuildingRegistryCommitted = true;
|
||||
}
|
||||
|
||||
if (!publication.EnvCellsCommitted)
|
||||
else if (publication.EnvCellPublication is { } envCellPublication
|
||||
&& !envCellPublication.PreparationCommitted)
|
||||
{
|
||||
if (build.EnvCells is { } envCells)
|
||||
_envCellPublisher?.AdvancePreparationOne(envCellPublication);
|
||||
}
|
||||
else if (!publication.EnvCellsCommitted)
|
||||
{
|
||||
if (publication.EnvCellPublication is { } retained)
|
||||
{
|
||||
(_envCellPublisher
|
||||
?? throw new InvalidOperationException(
|
||||
"A retained EnvCell receipt has no owning publisher."))
|
||||
.CommitPublication(retained);
|
||||
}
|
||||
else if (build.EnvCells is { } envCells)
|
||||
{
|
||||
_commitEnvCells?.Invoke(envCells);
|
||||
}
|
||||
publication.EnvCellsCommitted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
publication.CompletionCommitted = true;
|
||||
_completeCount++;
|
||||
}
|
||||
|
||||
publication.CompletionCommitted = true;
|
||||
_completeCount++;
|
||||
_completePublishTicks += Stopwatch.GetTimestamp() - started;
|
||||
return publication.CompletionCommitted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue