-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathshader-cache.js
136 lines (119 loc) Β· 3.45 KB
/
shader-cache.js
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
'use strict'
exports.shader = getShaderReference
exports.program = createProgram
var GLError = require("./GLError")
var formatCompilerError = require('gl-format-compiler-error');
var weakMap = typeof WeakMap === 'undefined' ? require('weakmap-shim') : WeakMap
var CACHE = new weakMap()
var SHADER_COUNTER = 0
function ShaderReference(id, src, type, shader, programs, count, cache) {
this.id = id
this.src = src
this.type = type
this.shader = shader
this.count = count
this.programs = []
this.cache = cache
}
ShaderReference.prototype.dispose = function() {
if(--this.count === 0) {
var cache = this.cache
var gl = cache.gl
//Remove program references
var programs = this.programs
for(var i=0, n=programs.length; i<n; ++i) {
var p = cache.programs[programs[i]]
if(p) {
delete cache.programs[i]
gl.deleteProgram(p)
}
}
//Remove shader reference
gl.deleteShader(this.shader)
delete cache.shaders[(this.type === gl.FRAGMENT_SHADER)|0][this.src]
}
}
function ContextCache(gl) {
this.gl = gl
this.shaders = [{}, {}]
this.programs = {}
}
var proto = ContextCache.prototype
function compileShader(gl, type, src) {
var shader = gl.createShader(type)
gl.shaderSource(shader, src)
gl.compileShader(shader)
if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
var errLog = gl.getShaderInfoLog(shader)
try {
var fmt = formatCompilerError(errLog, src, type);
} catch (e){
console.warn('Failed to format compiler error: ' + e);
throw new GLError(errLog, 'Error compiling shader:\n' + errLog)
}
throw new GLError(errLog, fmt.short, fmt.long)
}
return shader
}
proto.getShaderReference = function(type, src) {
var gl = this.gl
var shaders = this.shaders[(type === gl.FRAGMENT_SHADER)|0]
var shader = shaders[src]
if(!shader || !gl.isShader(shader.shader)) {
var shaderObj = compileShader(gl, type, src)
shader = shaders[src] = new ShaderReference(
SHADER_COUNTER++,
src,
type,
shaderObj,
[],
1,
this)
} else {
shader.count += 1
}
return shader
}
function linkProgram(gl, vshader, fshader, attribs, locations) {
var program = gl.createProgram()
gl.attachShader(program, vshader)
gl.attachShader(program, fshader)
for(var i=0; i<attribs.length; ++i) {
gl.bindAttribLocation(program, locations[i], attribs[i])
}
gl.linkProgram(program)
if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
var errLog = gl.getProgramInfoLog(program)
throw new GLError(errLog, 'Error linking program: ' + errLog)
}
return program
}
proto.getProgram = function(vref, fref, attribs, locations) {
var token = [vref.id, fref.id, attribs.join(':'), locations.join(':')].join('@')
var prog = this.programs[token]
if(!prog || !this.gl.isProgram(prog)) {
this.programs[token] = prog = linkProgram(
this.gl,
vref.shader,
fref.shader,
attribs,
locations)
vref.programs.push(token)
fref.programs.push(token)
}
return prog
}
function getCache(gl) {
var ctxCache = CACHE.get(gl)
if(!ctxCache) {
ctxCache = new ContextCache(gl)
CACHE.set(gl, ctxCache)
}
return ctxCache
}
function getShaderReference(gl, type, src) {
return getCache(gl).getShaderReference(type, src)
}
function createProgram(gl, vref, fref, attribs, locations) {
return getCache(gl).getProgram(vref, fref, attribs, locations)
}