Skip to content

Gather per-object data in parallel with chunked loops - #124

Open
JohnGreenFC wants to merge 1 commit into
mainfrom
optimization-scene-parallel-gather
Open

JohnGreenFC wants to merge 1 commit into
mainfrom
optimization-scene-parallel-gather

Conversation

@JohnGreenFC

Copy link
Copy Markdown

Summary

Goal: take the per-object loops in EveSpaceScene that still run serially on the main thread, and whose cost grows linearly with the number of objects in the scene, and spread them across worker threads. The supporting pieces make that pay off: the pool allocator used during the gather becomes safe to call from workers without a lock on the hot path, and the existing parallel loops hand out objects in blocks rather than one task per object, so task overhead no longer dominates the small amount of work done per object. The effect is less main-thread time per frame in object-heavy scenes, in both shadow modes.

Three changes are included:

1. Per-object data gathered in parallel (GetBatchesFromRenderables, TriPoolAllocator).
The main-pass batch gather walked every renderable on the main thread, calling GetPerObjectData and HasTransparentBatches for each before the per-thread batch collection ran. Both calls only touch the object's own state for the common object types, so the walk now runs as a Tr2ParallelFor over blocks of 64 renderables. ITr2Renderable gains SupportsParallelPerObjectData(), false by default; EveChildMesh and EveSpaceObject2 override it to true. Renderables that do not opt in are flagged during the parallel pass and handled serially afterwards, and the list of objects with transparencies is rebuilt from the per-renderable flags in the original order, so batch ordering is unchanged. The per-object data is carved from a TriPoolAllocator, which was a single bump pointer with a list of spilled pools and could not be called from two threads. It is now a chain of chunks with an atomic bump pointer: an allocation does a compare-and-swap on the current chunk and only takes a mutex when the chunk is exhausted and a new one has to be added. Clear remains main-thread only. Toggle: gatherPerObjectDataParallel.

2. Outdated RT animation marking in parallel (MarkOutdatedRtAnimations).
Every frame, each shadow caster is tested against the camera frustum, the sun shadow frustum, the local-light volumes and the spot-light frustums to decide whether its raytraced animation state is stale. This walk was a serial ProcessComponents over all IEveShadowCaster components. The frustums it tests against were also being constructed inside the loop; they are now built once before it, and the per-caster test runs as a Tr2ParallelDo over the component list, with the serial walk kept behind the toggle. Toggle: rtOutdatedAnimationsParallel.

3. Chunked parallel loops (UpdateAsyncronous, UpdateVisibility, PushRtGeometry).
These three loops were already parallel, but as Tr2ParallelDo with one task per object. In scenes with thousands of objects the per-task scheduling cost was comparable to the work done per object. They now use Tr2ParallelFor over a Tr2BlockedRange with a grain of 32 objects, so each task handles a block and the task count drops by that factor. PushRtGeometry also gets its own stats zone.

Linked issue (optional)

Testing

Windows, DX12, release build. Measured in the EVE Frontier client on the QA Megastructure route (1080p, low preset) against origin/main: about -0.7 ms frame mean with raytraced shadows and -0.5 ms with cascaded shadows (single flights, ~0.5 ms noise band). Smoke test of this branch alone: full route flown with raytraced shadows, no frames over 100 ms, no crash dumps. Not built on Mac.

AI assistance

AI testing, investigation and CL explanation

Checklist

  • Read CONTRIBUTING.md.
    • Commits follow the commit-message style described there.
    • Added or updated tests where it made sense.
    • Updated doc

…unked loops

Walk shadow casters in parallel when marking outdated RT animations.
Gather per-object data in parallel with a thread-safe pool allocator.
Chunk the per-object parallel loops in EveSpaceScene.
Copilot AI balanced review requested due to automatic review settings October 16, 2026 12:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JohnGreenFC
JohnGreenFC marked this pull request as ready for review October 16, 2026 13:10
@filipppavlov
filipppavlov requested a balanced review from Copilot October 20, 2026 13:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The allocator rewrite and expanded worker execution require human validation, with unresolved bounds and concurrency issues.

3 open issues

Review effort: Balanced

flags[i] = PER_OBJECT_DEFERRED;
continue;
}
perObjectData[i] = r->GetPerObjectData( opaqueBatches );
}

for( const auto& shadowFrustum : spotLightFrustums )
for( const auto& shadowFrustum : spotShadowFrustums )
Comment on lines +75 to +79
uint8_t* p = chunk->current.fetch_add( size, std::memory_order_relaxed );
if( p + size <= chunk->end )
{
return p;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants