refactor(rendering): prepare retained particle routing
Derive attached particle owners from the exact retained PView route stream with a zero-allocation warm path. Correct G4 gate provenance, record the current production-only RDP sample, and keep G5 old-route deletion explicitly blocked until the reapplied retained cutover passes its connected visual gate.
This commit is contained in:
parent
20f9fadb12
commit
c730632075
7 changed files with 374 additions and 20 deletions
120
src/AcDream.App/Rendering/Scene/RenderFrameRouteOwnerSelector.cs
Normal file
120
src/AcDream.App/Rendering/Scene/RenderFrameRouteOwnerSelector.cs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
namespace AcDream.App.Rendering.Scene;
|
||||
|
||||
/// <summary>
|
||||
/// Projects the retained PView route stream into particle-owner identities.
|
||||
/// This keeps attached-effect routing on the same visibility decision as mesh
|
||||
/// submission without walking spatial/gameplay entities a second time.
|
||||
/// </summary>
|
||||
internal static class RenderFrameRouteOwnerSelector
|
||||
{
|
||||
public static void Replace(
|
||||
HashSet<uint> destination,
|
||||
in RenderFrameView view,
|
||||
RenderFrameCandidateRoute route,
|
||||
int routeIndex,
|
||||
uint cellId)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
destination.Clear();
|
||||
Union(
|
||||
destination,
|
||||
in view,
|
||||
route,
|
||||
routeIndex,
|
||||
cellId);
|
||||
}
|
||||
|
||||
public static void Union(
|
||||
HashSet<uint> destination,
|
||||
in RenderFrameView view,
|
||||
RenderFrameCandidateRoute route,
|
||||
int routeIndex,
|
||||
uint cellId)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
VisitExact(
|
||||
destination,
|
||||
in view,
|
||||
route,
|
||||
routeIndex,
|
||||
cellId,
|
||||
remove: false);
|
||||
}
|
||||
|
||||
public static void ExceptRoute(
|
||||
HashSet<uint> destination,
|
||||
in RenderFrameView view,
|
||||
RenderFrameCandidateRoute route)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
|
||||
ReadOnlySpan<RenderFrameCandidateRange> ranges =
|
||||
view.RouteRanges;
|
||||
ReadOnlySpan<RenderProjectionRecord> candidates =
|
||||
view.RouteCandidates;
|
||||
for (int index = 0; index < ranges.Length; index++)
|
||||
{
|
||||
RenderFrameCandidateRange range = ranges[index];
|
||||
if (range.Route != route)
|
||||
continue;
|
||||
|
||||
ApplyRange(
|
||||
destination,
|
||||
candidates,
|
||||
in range,
|
||||
remove: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void VisitExact(
|
||||
HashSet<uint> destination,
|
||||
in RenderFrameView view,
|
||||
RenderFrameCandidateRoute route,
|
||||
int routeIndex,
|
||||
uint cellId,
|
||||
bool remove)
|
||||
{
|
||||
ReadOnlySpan<RenderFrameCandidateRange> ranges =
|
||||
view.RouteRanges;
|
||||
ReadOnlySpan<RenderProjectionRecord> candidates =
|
||||
view.RouteCandidates;
|
||||
for (int index = 0; index < ranges.Length; index++)
|
||||
{
|
||||
RenderFrameCandidateRange range = ranges[index];
|
||||
if (range.Route != route
|
||||
|| range.RouteIndex != routeIndex
|
||||
|| range.CellId != cellId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ApplyRange(
|
||||
destination,
|
||||
candidates,
|
||||
in range,
|
||||
remove);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyRange(
|
||||
HashSet<uint> destination,
|
||||
ReadOnlySpan<RenderProjectionRecord> candidates,
|
||||
in RenderFrameCandidateRange range,
|
||||
bool remove)
|
||||
{
|
||||
ReadOnlySpan<RenderProjectionRecord> owners =
|
||||
candidates.Slice(range.Offset, range.Count);
|
||||
for (int index = 0; index < owners.Length; index++)
|
||||
{
|
||||
uint localEntityId = owners[index].Source.LocalEntityId;
|
||||
if (localEntityId == 0)
|
||||
continue;
|
||||
|
||||
if (remove)
|
||||
destination.Remove(localEntityId);
|
||||
else
|
||||
destination.Add(localEntityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue