UNPKG

3.6 kBJavaScriptView Raw
1'use strict'
2
3exports.shader = getShaderReference
4exports.program = createProgram
5
6var formatCompilerError = require('gl-format-compiler-error');
7
8var weakMap = typeof WeakMap === 'undefined' ? require('weakmap-shim') : WeakMap
9var CACHE = new weakMap()
10
11var SHADER_COUNTER = 0
12
13function ShaderReference(id, src, type, shader, programs, count, cache) {
14 this.id = id
15 this.src = src
16 this.type = type
17 this.shader = shader
18 this.count = count
19 this.programs = []
20 this.cache = cache
21}
22
23ShaderReference.prototype.dispose = function() {
24 if(--this.count === 0) {
25 var cache = this.cache
26 var gl = cache.gl
27
28 //Remove program references
29 var programs = this.programs
30 for(var i=0, n=programs.length; i<n; ++i) {
31 var p = cache.programs[programs[i]]
32 if(p) {
33 delete cache.programs[i]
34 gl.deleteProgram(p)
35 }
36 }
37
38 //Remove shader reference
39 gl.deleteShader(this.shader)
40 delete cache.shaders[(this.type === gl.FRAGMENT_SHADER)|0][this.src]
41 }
42}
43
44function ContextCache(gl) {
45 this.gl = gl
46 this.shaders = [{}, {}]
47 this.programs = {}
48}
49
50var proto = ContextCache.prototype
51
52function compileShader(gl, type, src) {
53 var shader = gl.createShader(type)
54 gl.shaderSource(shader, src)
55 gl.compileShader(shader)
56 if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
57 var errLog = gl.getShaderInfoLog(shader)
58 try {
59 var fmt = formatCompilerError(errLog, src, type);
60 } catch (e){
61 console.warn('Failed to format compiler error: ' + e);
62 throw new Error('gl-shader: Error compiling shader:\n' + errLog)
63 }
64 console.warn('gl-shader: ' + fmt.long);
65 throw new Error('gl-shader: ' + fmt.short)
66 }
67 return shader
68}
69
70proto.getShaderReference = function(type, src) {
71 var gl = this.gl
72 var shaders = this.shaders[(type === gl.FRAGMENT_SHADER)|0]
73 var shader = shaders[src]
74 if(!shader || !gl.isShader(shader.shader)) {
75 var shaderObj = compileShader(gl, type, src)
76 shader = shaders[src] = new ShaderReference(
77 SHADER_COUNTER++,
78 src,
79 type,
80 shaderObj,
81 [],
82 1,
83 this)
84 } else {
85 shader.count += 1
86 }
87 return shader
88}
89
90function linkProgram(gl, vshader, fshader, attribs, locations) {
91 var program = gl.createProgram()
92 gl.attachShader(program, vshader)
93 gl.attachShader(program, fshader)
94 for(var i=0; i<attribs.length; ++i) {
95 gl.bindAttribLocation(program, locations[i], attribs[i])
96 }
97 gl.linkProgram(program)
98 if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
99 var errLog = gl.getProgramInfoLog(program)
100 console.error('gl-shader: Error linking program:', errLog)
101 throw new Error('gl-shader: Error linking program:' + errLog)
102 }
103 return program
104}
105
106proto.getProgram = function(vref, fref, attribs, locations) {
107 var token = [vref.id, fref.id, attribs.join(':'), locations.join(':')].join('@')
108 var prog = this.programs[token]
109 if(!prog || !this.gl.isProgram(prog)) {
110 this.programs[token] = prog = linkProgram(
111 this.gl,
112 vref.shader,
113 fref.shader,
114 attribs,
115 locations)
116 vref.programs.push(token)
117 fref.programs.push(token)
118 }
119 return prog
120}
121
122function getCache(gl) {
123 var ctxCache = CACHE.get(gl)
124 if(!ctxCache) {
125 ctxCache = new ContextCache(gl)
126 CACHE.set(gl, ctxCache)
127 }
128 return ctxCache
129}
130
131function getShaderReference(gl, type, src) {
132 return getCache(gl).getShaderReference(type, src)
133}
134
135function createProgram(gl, vref, fref, attribs, locations) {
136 return getCache(gl).getProgram(vref, fref, attribs, locations)
137}