perf(mesh-layer): memoize per-Device GLSL shader assembly#541
Draft
kylebarron wants to merge 1 commit into
Draft
perf(mesh-layer): memoize per-Device GLSL shader assembly#541kylebarron wants to merge 1 commit into
kylebarron wants to merge 1 commit into
Conversation
Wrap `ShaderAssembler.getDefaultShaderAssembler()` in a `Proxy` that memoizes `assembleGLSLShaderPair` results by `(modules-by-name, defines, vs, fs)` and inject it into `MeshTextureLayer`'s Model via `getShaders()`. All other methods (hook registration, default modules, WGSL assembly) delegate to the inner assembler, so deck.gl's globally-registered hook functions remain visible. Cache lives in a `WeakMap<Device, ShaderAssembler>`: two Deck instances on the same page get independent caches, and the entries die with the device. Within a `RasterTileLayer`, every tile sublayer passes identical inputs to the assembler, so the per-Device cache collapses N regex-heavy assembly passes into one. Also exposes diagnostic accessors `getMemoShaderAssemblerStats(device)` and `getMemoShaderAssemblerMissLog(device)` from the package entry point so apps can confirm cache effectiveness from devtools (and identify which inputs are varying when the cache underperforms). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
Member
Author
|
Status note (drafted by Claude Code): With #540's mesh-ref stabilization + module-aware Model rebuild in place, the steady-state per-frame #541 still has residual benefit at one-shot moments:
Blocker: the Suggested path:
|
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.
Summary
Wrap
ShaderAssembler.getDefaultShaderAssembler()in aProxythat memoizesassembleGLSLShaderPairresults by(modules-by-name, defines, vs, fs)and inject it intoMeshTextureLayer's Model viagetShaders(). All other methods (hook registration, default modules, WGSL assembly) delegate to the inner assembler, so deck.gl's globally-registered hook functions remain visible.The cache lives in a
WeakMap<Device, ShaderAssembler>— two Deck instances on the same page get independent caches, and the entries die with the device.Why
Inside
@luma.gl/shadertools'sassembleGLSLShaderPair, every shader-module's source is regex-parsed byvalidateShaderModuleUniformLayoutand the fully-assembled source is regex-parsed bywarnIfGLSLUniformBlocksAreNotStd140. There is no result cache anywhere in the luma stack — everyModelconstructor re-runs the full assembly + validation work.Within a
RasterTileLayer, every tile sublayer passes identical inputs to the assembler (same modules, same vs/fs source). With many tile sublayers active (e.g. a usgs-topo mosaic), this work runs hundreds of times per assembly burst even though the inputs are byte-identical.Diagnostics
The package now exports two accessors so apps can verify cache effectiveness from devtools:
```js
import {
getMemoShaderAssemblerStats,
getMemoShaderAssemblerMissLog,
} from "@developmentseed/deck.gl-raster";
getMemoShaderAssemblerStats(deckInstance.deck.device);
// → { hits: 410, misses: 1, entries: 1 }
getMemoShaderAssemblerMissLog(deckInstance.deck.device);
// → ["createTexture|cutlineBbox::...::vs::fs"] (first 20 miss keys)
```
Status
Draft — opened for review later. In initial testing in usgs-topo this change appeared to cause a shader compile error (`'DECKGL_FILTER_COLOR' : no matching overloaded function found`). The error was bisected against #540 but the result was inconclusive — it persists with or without this change wired in. Needs further investigation before this PR moves forward.
Suspected mechanism for the assembler-memo-related risk: deck.gl's `getShaderAssembler` does `_hookFunctions.length = 0` and re-adds hooks on every device init. If our cache populates during a window where hooks aren't yet registered (or were just reset), the cached assembled source would lack the hook function declarations. The cache key doesn't include `hookFunctions` content, so it can't recover from this. A real fix likely needs to either invalidate the cache on hook changes or include a hooks-version into the cache key.
Test plan
🤖 Generated with Claude Code