UNPKG

gl-shader

Version:
137 lines (119 loc) 3.53 kB
'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) }