Преглед на файлове

lighter getProgramCacheKey when using RawShaderMaterials (#22650)

* lighter getProgramCacheKey when using RawShaderMaterials

The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.

* lighter getProgramCacheKey when using RawShaderMaterials

The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.

* lighter getProgramCacheKey when using RawShaderMaterials

The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.

Co-authored-by: Dave Buchhofer <[email protected]>
Dave Buchhofer преди 3 години
родител
ревизия
20e2e54f7c
променени са 2 файла, в които са добавени 40 реда и са изтрити 3 реда
  1. 3 2
      src/renderers/webgl/WebGLPrograms.js
  2. 37 1
      src/utils.js

+ 3 - 2
src/renderers/webgl/WebGLPrograms.js

@@ -2,6 +2,7 @@ import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping,
 import { WebGLProgram } from './WebGLProgram.js';
 import { ShaderLib } from '../shaders/ShaderLib.js';
 import { UniformsUtils } from '../shaders/UniformsUtils.js';
+import { hashString } from '../../utils.js';
 
 function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
 
@@ -309,8 +310,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 		} else {
 
-			array.push( parameters.fragmentShader );
-			array.push( parameters.vertexShader );
+			array.push( hashString( parameters.fragmentShader ) );
+			array.push( hashString( parameters.vertexShader ) );
 
 		}
 

+ 37 - 1
src/utils.js

@@ -54,4 +54,40 @@ function createElementNS( name ) {
 
 }
 
-export { arrayMin, arrayMax, getTypedArray, createElementNS };
+/**
+  * cyrb53 hash for string from: https://stackoverflow.com/a/52171480
+  *
+  * Public Domain, @bryc - https://stackoverflow.com/users/815680/bryc
+  *
+  * It is roughly similar to the well-known MurmurHash/xxHash algorithms. It uses a combination
+  * of multiplication and Xorshift to generate the hash, but not as thorough. As a result it's
+  * faster than either would be in JavaScript and significantly simpler to implement. Keep in
+  * mind this is not a secure algorithm, if privacy/security is a concern, this is not for you.
+  *
+  * @param {string} str
+  * @param {number} seed, default 0
+  * @returns number
+  */
+function hashString( str, seed = 0 ) {
+
+	let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
+
+	for ( let i = 0, ch; i < str.length; i ++ ) {
+
+		ch = str.charCodeAt( i );
+
+		h1 = Math.imul( h1 ^ ch, 2654435761 );
+
+		h2 = Math.imul( h2 ^ ch, 1597334677 );
+
+	}
+
+	h1 = Math.imul( h1 ^ ( h1 >>> 16 ), 2246822507 ) ^ Math.imul( h2 ^ ( h2 >>> 13 ), 3266489909 );
+
+	h2 = Math.imul( h2 ^ ( h2 >>> 16 ), 2246822507 ) ^ Math.imul( h1 ^ ( h1 >>> 13 ), 3266489909 );
+
+	return 4294967296 * ( 2097151 & h2 ) + ( h1 >>> 0 );
+
+}
+
+export { arrayMin, arrayMax, getTypedArray, createElementNS, hashString };