Fix WebGLState leak with EquirectangularToCubeGenerator, PMREMGenerator, PMREMCubeUVPacker #15330
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #15288.
Due to the nature of the APIs of EquirectangularToCubeGenerator, PMREMGenerator, and PMREMCubeUVPacker, to generate multiple textures, a new instance is needed for each, where currently, each instance of these generators utilize their own scene/camera, accumulating WebGLStates for each render (see #15288 for details). This only addresses the root of the memory leak, not any of the API changes in #15288.
This change wraps each generator in a closure so that multiple instances of a generator reuse the same scene/camera, eliminating the WebGLState accumulation. The shader is also reused in EquirectangularToCubeGenerator and PMREMGenerator, and cloned in PMREMCubeUVPacker, which while the webgl program should be reused across instances, there was still some accumulation with regard to the instantiation of new materials.
Here's a rather pathological test case of generating a new EquirectangularToCubeGenerator, and passing through a PMREMGenerator and PMREMCubeUVPacker once every second; drop it in
examples/:https://gist.github.com/jsantell/c1e13139cfdd8526ba28a5078d608464
(L155-L194 is the loop of interest)
Before this patch, most memory that is allocated is retained across 3 minutes and things started to slow down:
After this patch, nothing beyond compiled code is generated and retained, or at least, far less over the course of 8 minutes:
Post-patch, the total retained memory hovered around 6MB, taking GC into consideration. Previously, it was hard to tell due to more GC spikes and seemingly larger peaks, but best case several more MBs.
While this could be an extreme scenario, and wasn't my main concern, the amount of allocation size saved after this patch is 98%.
Can confirm with webgl_materials_envmaps_[exr|hdr].html examples for correctness