File size: 1,818 Bytes
2b7aae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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 };