RenderContext: Refactor context key.#32546
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
|
Claude feedback (in case there's anything of interest) 👀 1. Memory Management Trade-offImportant consideration: The current code uses ChainMap which is built on WeakMap. This means render contexts tied to scene/camera objects are automatically garbage collected when those objects are disposed. The PR switches to a plain object with string keys. This means contexts will accumulate until dispose() is explicitly called. For most apps this is fine (limited attachment state combinations), but worth noting. 2. Simplifications I'd SuggestRemove getForClear entirely: // It becomes just:
getForClear( renderTarget = null ) {
return this.get( renderTarget );
}Could inline this at call sites or keep it for semantic clarity, but it's essentially a pass-through now. Consider making callDepth internal to RenderContexts: Instead of passing callDepth from Renderer, RenderContexts could track it internally: class RenderContexts {
constructor() {
this._renderContexts = {};
this._callDepth = 0;
}
begin() { this._callDepth++; }
end() { this._callDepth--; }
get( renderTarget = null, mrt = null ) {
// uses this._callDepth internally
}
}This encapsulates the depth tracking better. The Renderer would just call begin()/end() around render operations. 3. Minor SimplificationsConsistent separator in key: // PR uses mixed separators (: and -)
`${count}:${format}:${type}:${samples}:${depthBuffer}:${stencilBuffer}-${mrtState}-${callDepth}`
// Could be cleaner with consistent format:
`${attachmentState}|${mrtState}|${callDepth}`Cache attachment state on RenderTarget: The attachment state string is recomputed on every get() call. If render targets had a cached attachmentState getter, this would be slightly more efficient. 4. Question About the DesignDo we actually need different RenderContext objects for different callDepth values with the same attachment state? If the context is just being reconfigured before each use (which it appears to be), the same context could potentially be reused. The call depth might only matter for ensuring we don't have concurrent access to the same context during nested renders. Worth verifying. OverallThe PR is a nice simplification. My main suggestion would be encapsulating the callDepth tracking within RenderContexts rather than exposing it as a parameter - it's an implementation detail that Renderer shouldn't need to manage explicitly. |
|
@sunag I think this is the more correct approach for handling render contexts. There is now no scene and camera involved, only the render target and MRT settings define the context key. The new This change will still lead to less overall render contexts and thus render objects in multi-scene/cam scenarios. In |
8bee9b0 to
d26b5ec
Compare
That's what I imagined when I saw it. It looks interesting. I'm still a little concerned about relying on sharing the |
|
I also have doubts about I think we could implement something closer to what's used in games today, like asynchronous object compilation during the rendering process. It's common to see this happen in games; in fact, it's almost like what happens on an HTML page where elements load asynchronously and individually and it doesn't wait for everything to load before it starts displaying and some additional event functions should replace the current |
Indeed. In the future, we should try to figure out how we can use e.g. native render passes and encoders in nested render calls as well. This will require some refactoring in |
Related issue: #32544
Description
Next attempt to reduce the overall number of render context. This time the scene and camera are removed from the key. A new parameter
callDepthis added that track the number of nested renderings.