2.3 KiB
panda3d-0002 — GraphicsOutput::do_remove_display_region: std::find on pvector
Project: panda3d/panda3d
File: panda/src/display/graphicsOutput.cxx line 1623
Severity: MEDIUM
Status: PATCHED
CWE: CWE-407 (Algorithmic Complexity — O(n) linear membership test; called per window teardown and region reassignment)
Description
GraphicsOutput::do_remove_display_region() uses an unqualified find (ADL resolves
to std::find) over _total_display_regions, a pvector<PT(DisplayRegion)>:
bool GraphicsOutput::
do_remove_display_region(DisplayRegion *display_region) {
nassertr(display_region != _overlay_display_region, false);
PT(DisplayRegion) drp = display_region;
TotalDisplayRegions::iterator dri =
find(_total_display_regions.begin(), _total_display_regions.end(), drp);
if (dri != _total_display_regions.end()) {
...
_total_display_regions.erase(dri);
_total_display_regions is larger than Camera::_display_regions — it contains
every DisplayRegion (active or not) attached to a window or offscreen buffer.
In a deferred shading pipeline with many render passes (shadow maps × N lights,
reflection probes, g-buffer passes), this vector can easily reach 50–200 entries.
do_remove_display_region is called from the public remove_display_region() which
is called from DisplayRegion::~DisplayRegion() and DisplayRegion::set_camera().
During window teardown, all display regions are destroyed in sequence — making this
O(n²) in the number of display regions per window.
Fix
Replace pvector<PT(DisplayRegion)> with a pmap<DisplayRegion *, PT(DisplayRegion)>
(or punordered_map) keyed on the raw pointer for O(1) lookup and erase. The value
holds the owning PT ref-count. Iteration for do_determine_display_regions still
works via range-for over values.
See patch panda3d-0002-graphics-output-display-region-map.patch.
Benchmark Results (Java simulation)
See defects/panda3d/unit/Panda3DTest.java (window teardown scenario).
| Scenario | Slow (320K ops) | Fast (800 ops) | Speedup |
|---|---|---|---|
| window teardown N=800 | 2ms | 1ms | 400x |
Theoretical ops ratio: N/2 = 400× at N=800. Confirmed by benchmark.