Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/Rendering/Interfaces/IRenderStateAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ RenderState Assemble(
PlayerDiagnostics diagnostics,
SceneNode? hoveredNode,
HoveredPodHud? hoveredPod,
LayoutMode mode);
LayoutMode mode,
bool sceneUnchanged = false);

/// <summary>
/// Clears accumulated internal state.
/// </summary>
void Reset();
}
}
11 changes: 9 additions & 2 deletions src/Rendering/Pipeline/RenderEventBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal sealed class RenderEventBuffer(RenderEventKinds renderEvents) : IDispos
renderEvents);

private RenderEventKinds _renderEvents = renderEvents;
private bool _hasBufferedEvents;

/// <summary>
/// Updates enabled render event kinds and resets aggregation state.
Expand Down Expand Up @@ -46,17 +47,21 @@ public void Add(
{
_aggregation.Process(
evt);
_hasBufferedEvents = true;
}
}

/// <summary>
/// Flushes buffered events into the rendering pipeline.
/// </summary>
public void FlushTo(
public bool FlushTo(
RenderingPipeline pipeline)
{
lock (_sync)
{
if (!_hasBufferedEvents)
return false;

_aggregation.Flush();

foreach (var t in RenderEventDispatchTable.Table)
Expand All @@ -72,6 +77,8 @@ public void FlushTo(
}

_aggregation.Clear();
_hasBufferedEvents = false;
return true;
}
}

Expand All @@ -85,4 +92,4 @@ public void Dispose()
_aggregation.Dispose();
}
}
}
}
8 changes: 5 additions & 3 deletions src/Rendering/Pipeline/RenderFrameAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public void SubmitFrame(
PlayerDiagnostics diagnostics,
SceneNode? hoveredNode,
HoveredPodHud? hoveredPod,
LayoutMode layoutMode)
LayoutMode layoutMode,
bool sceneUnchanged = false)
{
var state =
assembler.Assemble(
Expand All @@ -38,9 +39,10 @@ public void SubmitFrame(
diagnostics,
hoveredNode,
hoveredPod,
layoutMode);
layoutMode,
sceneUnchanged);

output.Submit(
state);
}
}
}
17 changes: 11 additions & 6 deletions src/Rendering/Pipeline/RenderingPipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,23 +146,27 @@ internal void OnProgress(
ClearSceneState();
}

_events.FlushTo(
this);
var hadNewEvents =
_events.FlushTo(
this);

UpdateFrame();
UpdateFrame(
hadNewEvents);
}

/// <summary>
/// Updates simulation, hover state, diagnostics, and frame output.
/// </summary>
private void UpdateFrame()
private void UpdateFrame(
bool hadNewEvents)
{
var diagnostics =
Player.GetDiagnostics();

float dt =
_frameUpdater.Tick(
diagnostics);
diagnostics,
hadNewEvents);

_hover.Tick();

Expand All @@ -183,7 +187,8 @@ private void UpdateFrame()
diagnostics,
_hover.HoveredNode,
_hover.HoveredPod,
_options.Mode);
_options.Mode,
sceneUnchanged: !hadNewEvents && dt == 0f);
}

/// <summary>
Expand Down
20 changes: 15 additions & 5 deletions src/Rendering/Pipeline/SceneFrameUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ internal sealed class SceneFrameUpdater(
/// Ticks all frame-level scene systems and returns clamped delta time.
/// </summary>
public float Tick(
PlayerDiagnostics diagnostics)
PlayerDiagnostics diagnostics,
bool hadNewEvents = false)
{
float dt = CalculateDeltaTime(
diagnostics);

StepLayout(
diagnostics,
dt);
dt,
hadNewEvents);

anim.Tick(
dt);
Expand Down Expand Up @@ -68,7 +70,8 @@ private float CalculateDeltaTime(
currentWallTime;

if (diagnostics.State == PlayerState.Idle ||
diagnostics.State == PlayerState.Paused)
diagnostics.State == PlayerState.Paused ||
diagnostics.State == PlayerState.Finished)
{
return 0f;
}
Expand All @@ -83,11 +86,18 @@ private float CalculateDeltaTime(
/// </summary>
private void StepLayout(
PlayerDiagnostics diagnostics,
float dt)
float dt,
bool hadNewEvents)
{
if (dt <= 0f)
return;

if (!hadNewEvents &&
layout.Energy <= 0f)
{
return;
}

float speedBoost =
(float)Math.Max(
1.0,
Expand Down Expand Up @@ -126,4 +136,4 @@ private void StepLayout(
/// </summary>
public void ResetTime() =>
_lastWallTime = 0;
}
}
18 changes: 15 additions & 3 deletions src/Rendering/States/Hud/ExtensionStatisticsAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ namespace ChangeTrace.Rendering.States.Hud;
/// </summary>
internal sealed class ExtensionStatisticsAssembler
{
private IReadOnlyList<ExtensionStat> _cached = [];

/// <summary>
/// Collects and ranks the most common file extensions in the scene.
/// </summary>
public IReadOnlyList<ExtensionStat> Assemble(ISceneGraph scene)
public IReadOnlyList<ExtensionStat> Assemble(
ISceneGraph scene,
bool sceneUnchanged)
{
if (sceneUnchanged)
return _cached;

var counts = new Dictionary<string, int>();

foreach (var node in scene.Nodes.Values)
Expand All @@ -28,10 +35,15 @@ public IReadOnlyList<ExtensionStat> Assemble(ISceneGraph scene)
counts.GetValueOrDefault(node.Extension) + 1;
}

return counts
_cached = counts
.OrderByDescending(x => x.Value)
.Take(8)
.Select(x => new ExtensionStat(x.Key, x.Value))
.ToList();

return _cached;
}
}

public void Reset() =>
_cached = [];
}
60 changes: 48 additions & 12 deletions src/Rendering/States/RenderStateAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ internal sealed class RenderStateAssembler : IRenderStateAssembler
private readonly LeaderboardAssembler _leaderboard = new();
private readonly HudStateAssembler _hud = new();

private ISceneSnapshot _cachedSceneSnapshot = SceneSnapshot.Empty;
private bool _hasCachedSceneSnapshot;

/// <summary>
/// Records contributor activity for leaderboard tracking.
/// </summary>
Expand All @@ -39,7 +42,15 @@ public void RecordActorEvent(string actor, string commitSha) =>
/// Clears accumulated render-related state.
/// </summary>
public void Reset() =>
ResetCaches();

private void ResetCaches()
{
_leaderboard.Reset();
_extensions.Reset();
_cachedSceneSnapshot = SceneSnapshot.Empty;
_hasCachedSceneSnapshot = false;
}

private static Dictionary<string, int> BuildNodeIndex(
IReadOnlyList<NodeSnapshot> nodes)
Expand All @@ -65,14 +76,15 @@ public RenderState Assemble(
PlayerDiagnostics diagnostics,
SceneNode? hoveredNode,
HoveredPodHud? hoveredPod,
LayoutMode layoutMode)
LayoutMode layoutMode,
bool sceneUnchanged = false)
{
var nodeSnapshots = _nodes.Assemble(scene.Nodes);
var nodeIndex = BuildNodeIndex(nodeSnapshots);
var avatarSnapshots = _avatars.Assemble(scene.Avatars, out var activeAvatarsCount);
var edgeSnapshots = _edges.Assemble(scene, nodeIndex);
var particleSnapshots = _particles.Assemble(animationSystem);
var extensions = _extensions.Assemble(scene);
int activeAvatarsCount =
scene.Avatars.Count(static avatar => avatar.Value.ActivityLevel > 0.1f);

var extensions = _extensions.Assemble(
scene,
sceneUnchanged);
var leaderboard = _leaderboard.Assemble();

var hudState =
Expand All @@ -88,11 +100,10 @@ public RenderState Assemble(
leaderboard);

var sceneSnapshot =
SceneSnapshotMaterializer.Create(
nodeSnapshots,
avatarSnapshots,
edgeSnapshots,
particleSnapshots);
GetOrCreateSceneSnapshot(
scene,
animationSystem,
sceneUnchanged);

return new RenderState(
virtualTime,
Expand All @@ -103,4 +114,29 @@ public RenderState Assemble(
layoutMode,
diagnostics.ManagedMemoryMb);
}

private ISceneSnapshot GetOrCreateSceneSnapshot(
ISceneGraph scene,
IAnimationSystem animationSystem,
bool sceneUnchanged)
{
if (sceneUnchanged && _hasCachedSceneSnapshot)
return _cachedSceneSnapshot;

var nodeSnapshots = _nodes.Assemble(scene.Nodes);
var nodeIndex = BuildNodeIndex(nodeSnapshots);
var avatarSnapshots = _avatars.Assemble(scene.Avatars, out _);
var edgeSnapshots = _edges.Assemble(scene, nodeIndex);
var particleSnapshots = _particles.Assemble(animationSystem);

_cachedSceneSnapshot =
SceneSnapshotMaterializer.Create(
nodeSnapshots,
avatarSnapshots,
edgeSnapshots,
particleSnapshots);

_hasCachedSceneSnapshot = true;
return _cachedSceneSnapshot;
}
}
Loading