2
0
Michael Herzog 3 жил өмнө
parent
commit
9b86245eaf

+ 7 - 0
src/renderers/WebGLRenderer.js

@@ -573,6 +573,7 @@ function WebGLRenderer( parameters = {} ) {
 		cubeuvmaps.dispose();
 		cubeuvmaps.dispose();
 		objects.dispose();
 		objects.dispose();
 		bindingStates.dispose();
 		bindingStates.dispose();
+		programCache.dispose();
 
 
 		xr.dispose();
 		xr.dispose();
 
 
@@ -657,6 +658,12 @@ function WebGLRenderer( parameters = {} ) {
 
 
 			} );
 			} );
 
 
+			if ( material.isShaderMaterial ) {
+
+				programCache.releaseShaderCache( material );
+
+			}
+
 		}
 		}
 
 
 	}
 	}

+ 28 - 4
src/renderers/webgl/WebGLPrograms.js

@@ -1,13 +1,14 @@
 import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, LinearEncoding, sRGBEncoding, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, RGBAFormat, UnsignedByteType } from '../../constants.js';
 import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, LinearEncoding, sRGBEncoding, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, RGBAFormat, UnsignedByteType } from '../../constants.js';
 import { Layers } from '../../core/Layers.js';
 import { Layers } from '../../core/Layers.js';
 import { WebGLProgram } from './WebGLProgram.js';
 import { WebGLProgram } from './WebGLProgram.js';
+import { WebGLShaderCache } from './WebGLShaderCache.js';
 import { ShaderLib } from '../shaders/ShaderLib.js';
 import { ShaderLib } from '../shaders/ShaderLib.js';
 import { UniformsUtils } from '../shaders/UniformsUtils.js';
 import { UniformsUtils } from '../shaders/UniformsUtils.js';
-import { hashString } from '../../utils.js';
 
 
 function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
 function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
 
 
 	const _programLayers = new Layers();
 	const _programLayers = new Layers();
+	const _customShaders = new WebGLShaderCache();
 	const programs = [];
 	const programs = [];
 
 
 	const isWebGL2 = capabilities.isWebGL2;
 	const isWebGL2 = capabilities.isWebGL2;
@@ -127,6 +128,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 		}
 		}
 
 
 		let vertexShader, fragmentShader;
 		let vertexShader, fragmentShader;
+		let customVertexShaderID, customFragmentShaderID;
 
 
 		if ( shaderID ) {
 		if ( shaderID ) {
 
 
@@ -140,6 +142,11 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			vertexShader = material.vertexShader;
 			vertexShader = material.vertexShader;
 			fragmentShader = material.fragmentShader;
 			fragmentShader = material.fragmentShader;
 
 
+			_customShaders.update( material );
+
+			customVertexShaderID = _customShaders.getVertexShaderID( material );
+			customFragmentShaderID = _customShaders.getFragmentShaderID( material );
+
 		}
 		}
 
 
 		const currentRenderTarget = renderer.getRenderTarget();
 		const currentRenderTarget = renderer.getRenderTarget();
@@ -158,6 +165,9 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			fragmentShader: fragmentShader,
 			fragmentShader: fragmentShader,
 			defines: material.defines,
 			defines: material.defines,
 
 
+			customVertexShaderID: customVertexShaderID,
+			customFragmentShaderID: customFragmentShaderID,
+
 			isRawShaderMaterial: material.isRawShaderMaterial === true,
 			isRawShaderMaterial: material.isRawShaderMaterial === true,
 			glslVersion: material.glslVersion,
 			glslVersion: material.glslVersion,
 
 
@@ -296,8 +306,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 
 		} else {
 		} else {
 
 
-			array.push( hashString( parameters.fragmentShader ) );
-			array.push( hashString( parameters.vertexShader ) );
+			array.push( parameters.customVertexShaderID );
+			array.push( parameters.customFragmentShaderID );
 
 
 		}
 		}
 
 
@@ -549,14 +559,28 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 
 	}
 	}
 
 
+	function releaseShaderCache( material ) {
+
+		_customShaders.remove( material );
+
+	}
+
+	function dispose() {
+
+		_customShaders.dispose();
+
+	}
+
 	return {
 	return {
 		getParameters: getParameters,
 		getParameters: getParameters,
 		getProgramCacheKey: getProgramCacheKey,
 		getProgramCacheKey: getProgramCacheKey,
 		getUniforms: getUniforms,
 		getUniforms: getUniforms,
 		acquireProgram: acquireProgram,
 		acquireProgram: acquireProgram,
 		releaseProgram: releaseProgram,
 		releaseProgram: releaseProgram,
+		releaseShaderCache: releaseShaderCache,
 		// Exposed for resource monitoring & error feedback via renderer.info:
 		// Exposed for resource monitoring & error feedback via renderer.info:
-		programs: programs
+		programs: programs,
+		dispose: dispose
 	};
 	};
 
 
 }
 }

+ 120 - 0
src/renderers/webgl/WebGLShaderCache.js

@@ -0,0 +1,120 @@
+let _id = 0;
+
+class WebGLShaderCache {
+
+	constructor() {
+
+		this.shaderCache = new Map();
+		this.materialCache = new Map();
+
+	}
+
+	update( material ) {
+
+		const vertexShader = material.vertexShader;
+		const fragmentShader = material.fragmentShader;
+
+		const vertexShaderStage = this._getShaderStage( vertexShader );
+		const fragmentShaderStage = this._getShaderStage( fragmentShader );
+
+		const materialShaders = this._getShaderCacheForMaterial( material );
+
+		if ( materialShaders.has( vertexShaderStage ) === false ) {
+
+			materialShaders.add( vertexShaderStage );
+			vertexShaderStage.usedTimes ++;
+
+		}
+
+		if ( materialShaders.has( fragmentShaderStage ) === false ) {
+
+			materialShaders.add( fragmentShaderStage );
+			fragmentShaderStage.usedTimes ++;
+
+		}
+
+		return this;
+
+	}
+
+	remove( material ) {
+
+		const materialShaders = this.materialCache.get( material );
+
+		for ( const shaderStage of materialShaders ) {
+
+			shaderStage.usedTimes --;
+
+			if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage );
+
+		}
+
+		this.materialCache.delete( material );
+
+		return this;
+
+	}
+
+	getVertexShaderID( material ) {
+
+		return this._getShaderStage( material.vertexShader ).id;
+
+	}
+
+	getFragmentShaderID( material ) {
+
+		return this._getShaderStage( material.fragmentShader ).id;
+
+	}
+
+	dispose() {
+
+		this.shaderCache.clear();
+		this.materialCache.clear();
+
+	}
+
+	_getShaderCacheForMaterial( material ) {
+
+		const cache = this.materialCache;
+
+		if ( cache.has( material ) === false ) {
+
+			cache.set( material, new Set() );
+
+		}
+
+		return cache.get( material );
+
+	}
+
+	_getShaderStage( code ) {
+
+		const cache = this.shaderCache;
+
+		if ( cache.has( code ) === false ) {
+
+			const stage = new WebGLShaderStage();
+			cache.set( code, stage );
+
+		}
+
+		return cache.get( code );
+
+	}
+
+}
+
+class WebGLShaderStage {
+
+	constructor() {
+
+		this.id = _id ++;
+
+		this.usedTimes = 0;
+
+	}
+
+}
+
+export { WebGLShaderCache };

+ 1 - 37
src/utils.js

@@ -54,40 +54,4 @@ function createElementNS( name ) {
 
 
 }
 }
 
 
-/**
-  * 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 };
+export { arrayMin, arrayMax, getTypedArray, createElementNS };