WebGLRenderer: Reuse programs when only output color space or tone mapping differ (#34654) - #34738
Closed
rubenmarcus wants to merge 1 commit into
Closed
rubenmarcus wants to merge 1 commit into
rubenmarcus wants to merge 1 commit into
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
Author
|
The red CI was mine: the two new unit tests call The unit suite never creates a real context; the existing renderer tests work against a mock GL object (see |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 #34654.
When a transmissive object is in view,
renderTransmissionPass()draws every opaque object into a render target (working color space,NoToneMapping) before the main pass draws it onto the canvas (renderer.outputColorSpace,renderer.toneMapping). At each switch,setProgram()hit thematerialProperties.outputColorSpace !== colorSpacelink of itselse ifchain, sogetProgram()ran twice per material per frame. Nothing compiles on those lookups, butgetParameters()runs on each one and callscustomProgramCacheKey(), which isonBeforeCompile.toString(). The reporter measured 600 lookups per frame and 36% of page JS time with 300 materials; this happens with default renderer settings because sRGB output alone differs from the render target.The two output checks are now taken out of the chain and compared only when the rest of the chain found no difference. When only the output color space or the tone mapping differs, a small per-material map from
colorSpace + ':' + toneMappingto the program switches to the program found earlier instead of callinggetProgram(). The uniform list is rebuilt for the switched program whilematerialProperties.uniformsstays the object it was built from. The map is cleared whenevergetProgram()runs for any other reason (material version, lights state, object features, environment, fog, clipping), so a remembered program always matches the rest of the current state. Node materials keep the existing path.This is the small fix for the case where the opaque pass is still rendered twice; #28423 would remove the second draw altogether.
Verification (macOS, arm64, headless Chrome WebGL2):
Per-frame program lookups with the change (60 unique materials, one transmissive sphere, ACES; light added after frame 4), counted via a
customProgramCacheKeyspy as in the issue:Steady frames are lookup-free; a real state change re-runs one lookup per output variant, then settles.
Pixel comparison of patched vs pristine dev on the issue scenario plus the three edge cases from the discussion (material in two scenes with different lights, normal-mapped material shared by meshes with and without tangents, instance colors added after the first frames), FNV-1a hash of the canvas after 6 renders each:
Tradeoff: after any real program change (lights, version bump, features), each output variant re-runs one full lookup once because the map is cleared with the chain; the frames after that are lookup-free again. Materials that alternate between more than two output settings (e.g. multiple render targets with different texture color spaces) keep one map entry per variant, mirroring what
materialProperties.programsalready holds.Prepared with AI assistance (GLM 5.3 via Oh My Pi) and reviewed before submission.