Skip to content

perf(sortingrenderer): Skip z-sorting for nodes without bounding info in SortingRenderer#2854

Open
stephanmeesters wants to merge 3 commits into
TheSuperHackers:mainfrom
stephanmeesters:perf/sorting-skip-object-sorting
Open

perf(sortingrenderer): Skip z-sorting for nodes without bounding info in SortingRenderer#2854
stephanmeesters wants to merge 3 commits into
TheSuperHackers:mainfrom
stephanmeesters:perf/sorting-skip-object-sorting

Conversation

@stephanmeesters

@stephanmeesters stephanmeesters commented Jul 4, 2026

Copy link
Copy Markdown

In the sorting renderer there are two stages in sorting:

  • Per object or "node" (using a SphereClass as bounding information) using a transformed Z coordinate
  • Per triangle

Mesh nodes that require sorting usually are inserted with the bounding information, while particles nodes are inserted without the bounding information (a zero sphere).

Because all of the particles nodes have no bounding info, they have a transformed object coordinate of Z=0.0, which means they can't be sorted among themselves, and slow down the insertion sort of objects.

The change in this PR is to keep a separate list of these unsortable nodes, and splice them in later at the correct position of the sorted list. Also state->bounding_sphere went unused and was cleaned up.

Observed a FPS gain of about 4-5% in a busy scene.

Todo

  • Test scene with mixed alpha-sorted meshes and particles

@stephanmeesters stephanmeesters force-pushed the perf/sorting-skip-object-sorting branch from 32f4bd8 to 29a4c0b Compare July 4, 2026 21:41
@stephanmeesters stephanmeesters added Performance Is a performance concern ZH Relates to Zero Hour Gen Relates to Generals Rendering Is Rendering related labels Jul 4, 2026
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR optimises the sorting renderer by diverting mesh nodes that have no bounding sphere (zero-radius) — typically particle nodes — away from the O(n) insertion sort and into a separate unsorted_list. At flush time the unsorted nodes are spliced into the sorted list at the Z=0 boundary (between all positive-Z and all non-positive-Z objects), yielding a reported 4–5 % FPS improvement in busy scenes.

  • SortingNodeStruct::bounding_sphere is removed since it was written but never read after the transform; nodes with Radius ≤ 0 skip the matrix transform and go straight to unsorted_list.
  • In Flush(), the splice iterator advances past all Z > 0 elements in the descending-order sorted_list, placing particle nodes correctly between far and near geometry.
  • Deinit() now deletes any nodes still in unsorted_list, matching the existing cleanup pattern for sorted_list and clean_list.

Confidence Score: 5/5

Safe to merge; the splice position logic is correct for the descending-Z list, memory cleanup is handled in both Flush() and Deinit(), and the behavioral trade-off (particles fixed at Z=0 rather than sorted by their actual camera-space depth) is intentional and documented.

The change is well-scoped: the new list is correctly populated, correctly consumed in Flush(), and correctly freed in Deinit(). The splice insertion point (first element with Z <= 0) is the right position in a descending-Z list. The only open item noted in the PR's own TODO — mixed alpha-sorted meshes and particles — is an edge-case the author intends to test separately.

No files require special attention beyond the single changed file.

Important Files Changed

Filename Overview
Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp Introduces a separate unsorted_list for nodes with no bounding sphere (radius <= 0), bypassing insertion sort and splicing them into the sorted list at the Z=0 boundary in Flush(). Also removes the now-unused bounding_sphere member from SortingNodeStruct. Deinit() correctly cleans up the new list. One minor style nit: radius check uses 0.0 (double) instead of 0.0f (float).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Insert_Triangles(bounding_sphere, ...)"] --> B{"Radius <= 0?"}
    B -- Yes --> C["transformed_center = (0,0,0)\nunsorted_list.push_back(state)"]
    B -- No --> D["Compute world*view\ntransform center"]
    D --> E["Insert_To_Sorted_List(state)\n(descending Z order)"]

    F["Flush()"] --> G["Advance iterator past\nZ > 0 elements in sorted_list"]
    G --> H["sorted_list.splice(node, unsorted_list)\n(particles land at Z=0 boundary)"]
    H --> I["Process sorted_list front-to-back\n(painter's algorithm)"]

    J["Deinit()"] --> K["Delete all nodes in sorted_list"]
    K --> L["Delete all nodes in unsorted_list"]
    L --> M["Delete all nodes in clean_list"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Insert_Triangles(bounding_sphere, ...)"] --> B{"Radius <= 0?"}
    B -- Yes --> C["transformed_center = (0,0,0)\nunsorted_list.push_back(state)"]
    B -- No --> D["Compute world*view\ntransform center"]
    D --> E["Insert_To_Sorted_List(state)\n(descending Z order)"]

    F["Flush()"] --> G["Advance iterator past\nZ > 0 elements in sorted_list"]
    G --> H["sorted_list.splice(node, unsorted_list)\n(particles land at Z=0 boundary)"]
    H --> I["Process sorted_list front-to-back\n(painter's algorithm)"]

    J["Deinit()"] --> K["Delete all nodes in sorted_list"]
    K --> L["Delete all nodes in unsorted_list"]
    L --> M["Delete all nodes in clean_list"]
Loading

Reviews (3): Last reviewed commit: "Check for <=0 sphere radius, rename list..." | Re-trigger Greptile

Comment thread Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp Outdated

@xezon xezon 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.

Cool

Comment thread Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp Outdated
Comment thread Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp Outdated
@xezon xezon changed the title perf: Skip z-sorting for nodes without bounding info in SortingRenderer perf(sortingrenderer): Skip z-sorting for nodes without bounding info in SortingRenderer Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gen Relates to Generals Performance Is a performance concern Rendering Is Rendering related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants