Skip to content

Commit

Permalink
perf(troika-three-utils): increase chance of program reuse in createD…
Browse files Browse the repository at this point in the history
…erivedMaterial

Related to #59. Different instances of the same Material class can
easily give identical shader output; however we were injecting a unique
id into the rewritten shader code for every instance, preventing the
resulting shader code from ever being the same and causing separate
compiled webgl programs for each instance. This change chooses a
consistent id based on incoming derived material options, allowing the
result to match when the input shader code is the same.
  • Loading branch information
lojjic committed Jun 17, 2020
1 parent 3d88475 commit 56daf65
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions packages/troika-three-utils/src/DerivedMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const assign = Object.assign || function(/*target, ...sources*/) {
}


let idCtr = 0
const epoch = Date.now()
const CACHE = new WeakMap() //threejs requires WeakMap internally so should be safe to assume support

Expand Down Expand Up @@ -93,7 +92,11 @@ export function createDerivedMaterial(baseMaterial, options) {
return cached[optionsHash].clone()
}

const id = ++idCtr
// Even if baseMaterial is changing, use a consistent id in shader rewrites based on the
// optionsHash. This makes it more likely that deriving from base materials of the same
// type/class, e.g. multiple instances of MeshStandardMaterial, will produce identical
// rewritten shader code so they can share a single WebGLProgram behind the scenes.
const id = getIdForOptionsHash(optionsHash)
const privateDerivedShadersProp = `_derivedShaders${id}`
const privateBeforeCompileProp = `_onBeforeCompile${id}`
let distanceMaterialTpl, depthMaterialTpl
Expand Down Expand Up @@ -347,3 +350,13 @@ function getOptionsHash(options) {
function optionsJsonReplacer(key, value) {
return key === 'uniforms' ? undefined : typeof value === 'function' ? value.toString() : value
}

let _idCtr = 0
const optionsHashesToIds = new Map()
function getIdForOptionsHash(optionsHash) {
let id = optionsHashesToIds.get(optionsHash)
if (id == null) {
optionsHashesToIds.set(optionsHash, (id = ++_idCtr))
}
return id
}

0 comments on commit 56daf65

Please sign in to comment.