Skip the sort rerun that follows a new mapping - #460
oscarlorentzon wants to merge 3 commits into
Conversation
A new mapping that appeared after a frame had asked for another sort was only generated once the old mapping had been sorted again. A sort now starts only while the latest frame has the mapping it would sort.
A LoD result written between frames, just before a sort ended, was seen by no frame, so the rerun that followed read the old mapping. A sort now also waits while a mesh's mapping is newer than the one it would read.
| if ( | ||
| this.sorting || | ||
| !this.sortDirty || | ||
| this.frameMapping !== this.current.mappingVersion || |
There was a problem hiding this comment.
With this condition removed, all unit tests still pass. So either this.current.mappingChanged() covers all relevant cases OR none of the unit tests cover the case where the check is needed.
Given that the mappingVersion can increment when generators are removed/added, I believe it is possible to end up in a situation where the this.current.mappingChanged indicates no change, as each generators' mappingVersion is unchanged, yet the accumulators mappingVersion would differ.
There was a problem hiding this comment.
Good catch, no test needed it. The check is still needed, as hiding, adding or removing a mesh changes the mapping without changing any mesh's mappingVersion, which mappingChanged() does not see. Added a commit with a test that hides a mesh during a sort, which fails without this condition.
| sorting = false; | ||
| sortDirty = false; | ||
| // Mapping version the latest frame produced. | ||
| private frameMapping = -1; |
There was a problem hiding this comment.
This mapping isn't necessarily tied to a frame, for example when autoUpdate is set to false. Not sure what a suitable name would be, the update method itself uses the next/current terminology, so nextMappingVersion could work, but IMHO also isn't the clearest.
Maybe something like latestMappingVersion?
There was a problem hiding this comment.
Agreed, it is set by every update, update() with autoUpdate off included. Added a commit that renames it to latestMappingVersion.
|
Looks like a really nice improvement to the latency between the lod updates and the frame they are rendered. One thing I'm wondering about is whether halting the Currently This probably won't cover the |
Hiding a mesh changes the mapping without changing any mesh mapping version, so only the check against the latest mapping catches it. That mapping is now named after the update that sets it, not after a frame.
|
Thanks, good points:
The content of |
|
Thanks for the clarification, the PR looks good in its current state.
Isn't the current condition used in |
Agreed. Changing to |
If a frame requests another sort while one runs and a new mapping then appears,
driveSortsorts the old mapping again when the running sort ends, and the new mapping is shown one sort late.driveSortnow starts a sort only whilecurrent.mappingVersionequals the mapping version of the most recent update.A LoD result can also be written between frames, just before the running sort ends, and then no frame has computed the new mapping when that sort ends.
driveSortnow also does not start a sort while the newSplatAccumulator.mappingChanged()finds a mesh incurrentwhosemappingVersionhas changed sincecurrentwas generated.Verification
test/unit/SparkRenderer.test.ts. Onmain, two tests fail with the old mapping sorted twice: one where a new mapping appears during a sort, and one where it appears between frames, just before the sort ends.mainand this branch, with a rotating 10M splat scene in view andlodSplatCount2.5M.mainnpm run test:browserandnpm run buildpass.Related to #347.