What one evaluatePerFrame call changed, split by kind because the two
kinds mean different things downstream:
levelChanged — a kind=lod group swapped its active level. That is
a CONTENT change (a different level costs differently to render), so the
app notifies adaptive DPR, whose learned bounds described the old level.
cullChanged — a kind=partition part entered or left the frustum.
That is the same content seen from elsewhere, and it flips constantly
while the camera orbits a partitioned scene: it must redraw, but must NOT
reset adaptive-DPR learning.
The returned objects are shared frozen constants, so the per-frame path
allocates nothing; compare fields, not identity.
What one
evaluatePerFramecall changed, split by kind because the two kinds mean different things downstream:levelChanged— akind=lodgroup swapped its active level. That is a CONTENT change (a different level costs differently to render), so the app notifies adaptive DPR, whose learned bounds described the old level.cullChanged— akind=partitionpart entered or left the frustum. That is the same content seen from elsewhere, and it flips constantly while the camera orbits a partitioned scene: it must redraw, but must NOT reset adaptive-DPR learning.The returned objects are shared frozen constants, so the per-frame path allocates nothing; compare fields, not identity.