perf(rendering): draw retained frame product

Make the incremental render scene the production entity source at the existing retail PView stages while retaining the accepted dispatcher upload and draw executor. Keep diagnostics consumer-gated, retain ordered indices across unchanged frames, refresh only dirty records, and preserve exact mesh-load, selection, alpha, lighting, and route lifecycle semantics.
This commit is contained in:
Erik 2026-07-25 04:12:23 +02:00
parent c7d7848dd2
commit ef1d263337
13 changed files with 1333 additions and 267 deletions

View file

@ -133,6 +133,142 @@ public sealed class RenderScenePViewFrameProductTests
}
}
[Fact]
public void Builder_ReusesOrderedIndicesWhileRefreshingDirtyRecords()
{
using var scene = new ArchRenderScene(Generation);
RenderProjectionRecord later = Record(
0x0100_0000_0000_0012,
RenderProjectionClass.OutdoorStatic);
RenderProjectionRecord earlier = Record(
0x0100_0000_0000_0011,
RenderProjectionClass.OutdoorStatic);
scene.Apply(
[
RenderProjectionDelta.Register(Generation, 1, later),
RenderProjectionDelta.Register(Generation, 2, earlier),
]);
PortalVisibilityFrame portal = Portal(Cell);
ClipFrameAssembly clip = FullScreenClip(Cell);
ViewconeCuller viewcone =
ViewconeCuller.Build(clip, Matrix4x4.Identity);
var exchange = new RenderFrameExchange();
var builder = new RenderScenePViewFrameBuilder();
Build(frameSequence: 1);
RenderFrameView first = exchange.BorrowLatest(Generation, 1);
try
{
Assert.Equal(
[earlier.Id, later.Id],
first.OutdoorStaticCandidates.ToArray()
.Select(static record => record.Id));
}
finally
{
exchange.Release(in first);
}
scene.ClearDirty();
ulong retainedRevision = scene.OpenQuery().IndexRevision;
Matrix4x4 movedTransform =
Matrix4x4.CreateTranslation(0.25f, 0, 0);
RenderProjectionRecord moved = later with
{
Transform = new RenderTransform(movedTransform),
PreviousTransform =
new PreviousRenderTransform(
later.Transform.LocalToWorld),
Bounds = new RenderWorldBounds(
new Vector3(-0.75f, -1, -1),
new Vector3(1.25f, 1, 1)),
};
scene.Apply(
[
RenderProjectionDelta.Update(
RenderProjectionDeltaKind.UpdateTransform,
Generation,
3,
moved),
]);
Assert.Equal(
retainedRevision,
scene.OpenQuery().IndexRevision);
Build(frameSequence: 2);
RenderFrameView second = exchange.BorrowLatest(Generation, 2);
try
{
RenderProjectionRecord projected =
second.EntityCandidates.ToArray()
.Single(candidate =>
candidate.Projection.Id == later.Id)
.Projection;
Assert.Equal(
movedTransform,
projected.Transform.LocalToWorld);
Assert.Equal(
[earlier.Id, later.Id],
second.OutdoorStaticCandidates.ToArray()
.Select(static record => record.Id));
}
finally
{
exchange.Release(in second);
}
scene.ClearDirty();
RenderProjectionRecord reordered = moved with
{
SortKey = new RenderSortKey(0),
};
scene.Apply(
[
RenderProjectionDelta.Update(
RenderProjectionDeltaKind.UpdateTransform,
Generation,
4,
reordered),
]);
Assert.True(
scene.OpenQuery().IndexRevision > retainedRevision);
Build(frameSequence: 3);
RenderFrameView third = exchange.BorrowLatest(Generation, 3);
try
{
Assert.Equal(
[later.Id, earlier.Id],
third.OutdoorStaticCandidates.ToArray()
.Select(static record => record.Id));
}
finally
{
exchange.Release(in third);
}
void Build(ulong frameSequence)
{
RenderSceneQuery query = scene.OpenQuery();
var input = new RenderScenePViewBuildInput(
query,
new RenderSceneDigest(
query.Generation,
query.Counts,
default),
portal,
clip,
viewcone,
[],
[Cell],
EmptyCellSource.Instance,
[],
RootIsOutdoor: true);
builder.Build(exchange, frameSequence, in input);
}
}
[Fact]
public void Controller_MatchesCurrentPViewThenNamesAWithdrawnCandidate()
{