Refactor shader and program management

This commit is contained in:
Tom Payne
2012-07-15 14:11:32 +02:00
parent 73187bc018
commit 61ab5c8f49
7 changed files with 160 additions and 247 deletions

View File

@@ -8,7 +8,10 @@ goog.require('goog.webgl');
goog.require('ol.Layer');
goog.require('ol.Map');
goog.require('ol.TileLayer');
goog.require('ol.webgl.Shader');
goog.require('ol.webgl.TileLayerRenderer');
goog.require('ol.webgl.shader.Fragment');
goog.require('ol.webgl.shader.Vertex');
/**
@@ -59,6 +62,30 @@ ol.webgl.Map = function(target, opt_values) {
goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
this.handleWebGLContextRestored, false, this);
/**
* @private
* @type {Object.<number, WebGLShader>}
*/
this.shaderCache_ = {};
/**
* @private
* @type {Object.<string, WebGLProgram>}
*/
this.programCache_ = {};
/**
* @private
* @type {ol.webgl.shader.Fragment}
*/
this.fragmentShader_ = ol.webgl.Map.createFragmentShader_();
/**
* @private
* @type {ol.webgl.shader.Vertex}
*/
this.vertexShader_ = ol.webgl.Map.createVertexShader_();
if (goog.isDef(opt_values)) {
this.setValues(opt_values);
}
@@ -70,6 +97,45 @@ ol.webgl.Map = function(target, opt_values) {
goog.inherits(ol.webgl.Map, ol.Map);
/**
* @private
* @return {ol.webgl.shader.Fragment} Fragment shader.
*/
ol.webgl.Map.createFragmentShader_ = function() {
return new ol.webgl.shader.Fragment([
'precision mediump float;',
'',
'uniform float uAlpha;',
'uniform sampler2D uTexture;',
'',
'varying vec2 vTexCoord;',
'',
'void main(void) {',
' gl_FragColor = vec4(texture2D(uTexture, vTexCoord).rgb, uAlpha);',
'}'
].join('\n'));
};
/**
* @private
* @return {ol.webgl.shader.Vertex} Vertex shader.
*/
ol.webgl.Map.createVertexShader_ = function() {
return new ol.webgl.shader.Vertex([
'attribute vec2 aPosition;',
'attribute vec2 aTexCoord;',
'',
'varying vec2 vTexCoord;',
'',
'void main(void) {',
' gl_Position = vec4(aPosition, 0., 1.);',
' vTexCoord = aTexCoord;',
'}'
].join('\n'));
};
/**
* @inheritDoc
*/
@@ -87,6 +153,23 @@ ol.webgl.Map.prototype.createLayerRenderer = function(layer) {
};
/**
* @inheritDoc
*/
ol.webgl.Map.prototype.disposeInternal = function() {
var gl = this.getGL();
if (!gl.isContextLost()) {
goog.object.forEach(this.programCache_, function(program) {
gl.deleteProgram(program);
});
goog.object.forEach(this.shaderCache_, function(shader) {
gl.deleteShader(shader);
});
}
goog.base(this, 'disposeInternal');
};
/**
* @return {WebGLRenderingContext} GL.
*/
@@ -95,6 +178,60 @@ ol.webgl.Map.prototype.getGL = function() {
};
/**
* @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader.
* @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader.
* @return {WebGLProgram} Program.
*/
ol.webgl.Map.prototype.getProgram = function(
fragmentShaderObject, vertexShaderObject) {
var key =
goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject);
if (key in this.programCache_) {
return this.programCache_[key];
} else {
var gl = this.getGL();
var program = gl.createProgram();
gl.attachShader(program, this.getShader(fragmentShaderObject));
gl.attachShader(program, this.getShader(vertexShaderObject));
gl.linkProgram(program);
if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) &&
!gl.isContextLost()) {
window.console.log(gl.getProgramInfoLog(program));
goog.asserts.assert(
gl.getProgramParameter(program, goog.webgl.LINK_STATUS));
}
this.programCache_[key] = program;
return program;
}
};
/**
* @param {ol.webgl.Shader} shaderObject Shader object.
* @return {WebGLShader} Shader.
*/
ol.webgl.Map.prototype.getShader = function(shaderObject) {
var key = goog.getUid(shaderObject);
if (key in this.shaderCache_) {
return this.shaderCache_[key];
} else {
var gl = this.getGL();
var shader = gl.createShader(shaderObject.getType());
gl.shaderSource(shader, shaderObject.getSource());
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) &&
!gl.isContextLost()) {
window.console.log(gl.getShaderInfoLog(shader));
goog.asserts.assert(
gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS));
}
this.shaderCache_[key] = shader;
return shader;
}
};
/**
* @inheritDoc
*/
@@ -165,6 +302,8 @@ ol.webgl.Map.prototype.handleWebGLContextLost = function(event) {
goog.dispose(layerRenderer);
}, this);
goog.asserts.assert(goog.object.isEmpty(this.layerRenderers));
this.shaderCache_ = {};
this.programCache_ = {};
};

View File

@@ -1,79 +0,0 @@
goog.provide('ol.webgl.Program');
goog.require('goog.asserts');
goog.require('goog.webgl');
goog.require('ol.webgl.GLObject');
goog.require('ol.webgl.VertexAttrib');
goog.require('ol.webgl.shader.Fragment');
goog.require('ol.webgl.shader.Vertex');
/**
* @constructor
* @extends {ol.webgl.GLObject}
* @param {ol.webgl.shader.Fragment} fragmentShader Fragment shader.
* @param {ol.webgl.shader.Vertex} vertexShader Vertex shader.
*/
ol.webgl.Program = function(fragmentShader, vertexShader) {
goog.base(this);
/**
* @private
* @type {ol.webgl.shader.Fragment}
*/
this.fragmentShader_ = fragmentShader;
/**
* @private
* @type {ol.webgl.shader.Vertex}
*/
this.vertexShader_ = vertexShader;
/**
* @private
* @type {WebGLProgram}
*/
this.program_ = null;
};
goog.inherits(ol.webgl.Program, ol.webgl.GLObject);
/**
* @inheritDoc
*/
ol.webgl.Program.prototype.setGL = function(gl) {
if (!goog.isNull(this.gl)) {
if (!goog.isNull(this.program_)) {
this.gl.deleteProgram(this.program_);
this.program_ = null;
}
this.fragmentShader_.setGL(null);
this.vertexShader_.setGL(null);
}
goog.base(this, 'setGL', gl);
if (!goog.isNull(gl)) {
this.fragmentShader_.setGL(gl);
this.vertexShader_.setGL(gl);
var program = gl.createProgram();
gl.attachShader(program, this.fragmentShader_.get());
gl.attachShader(program, this.vertexShader_.get());
gl.linkProgram(program);
if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS)) {
window.console.log(gl.getProgramInfoLog(program));
goog.asserts.assert(
gl.getProgramParameter(program, goog.webgl.LINK_STATUS));
}
this.program_ = program;
}
};
/**
*/
ol.webgl.Program.prototype.use = function() {
var gl = this.getGL();
gl.useProgram(this.program_);
};

View File

@@ -1,64 +0,0 @@
goog.provide('ol.webgl.ProgramCache');
goog.require('goog.dispose');
goog.require('goog.object');
goog.require('ol.webgl.GLObject');
goog.require('ol.webgl.Program');
goog.require('ol.webgl.shader.Fragment');
goog.require('ol.webgl.shader.Vertex');
/**
* @constructor
* @extends {ol.webgl.GLObject}
*/
ol.webgl.ProgramCache = function() {
goog.base(this);
/**
* @private
* @type {Object.<string, Object.<string, ol.webgl.Program>>}
*/
this.programss_ = {};
};
goog.inherits(ol.webgl.ProgramCache, ol.webgl.GLObject);
/**
* @param {ol.webgl.shader.Fragment} fragmentShader Fragment shader.
* @param {ol.webgl.shader.Vertex} vertexShader Vertex shader.
* @return {ol.webgl.Program} Program.
*/
ol.webgl.ProgramCache.prototype.get =
function(fragmentShader, vertexShader) {
var program, programs;
var fragmentShaderKey = goog.getUid(fragmentShader);
if (fragmentShaderKey in this.programss_) {
programs = this.programss_[fragmentShaderKey];
} else {
programs = {};
this.programss_[fragmentShaderKey] = programs;
}
var vertexShaderKey = goog.getUid(vertexShader);
if (vertexShaderKey in programs) {
program = programs[vertexShaderKey];
} else {
program = new ol.webgl.Program(fragmentShader, vertexShader);
programs[vertexShaderKey] = program;
}
return program;
};
/**
* @inheritDoc
*/
ol.webgl.ProgramCache.prototype.setGL = function(gl) {
goog.object.forEach(this.programss_, function(programs) {
goog.disposeAll(goog.object.getValues(programs));
});
goog.base(this, 'setGL', gl);
};

View File

@@ -1,28 +1,14 @@
goog.provide('ol.webgl.Shader');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.webgl');
goog.require('ol.webgl.GLObject');
goog.require('ol.webgl.Uniform');
goog.require('goog.functions');
/**
* @constructor
* @extends {ol.webgl.GLObject}
* @param {string} source Source.
* @param {Array.<ol.webgl.Uniform>=} opt_uniforms Uniforms.
*/
ol.webgl.Shader = function(source, opt_uniforms) {
goog.base(this);
/**
* @private
* @type {WebGLShader}
*/
this.shader_ = null;
ol.webgl.Shader = function(source) {
/**
* @private
@@ -30,88 +16,24 @@ ol.webgl.Shader = function(source, opt_uniforms) {
*/
this.source_ = source;
/**
* @private
* @type {Array.<ol.webgl.Uniform>}
*/
this.uniforms_ = opt_uniforms || [];
};
goog.inherits(ol.webgl.Shader, ol.webgl.GLObject);
/**
*/
ol.webgl.Shader.prototype.compile = function() {
var gl = this.getGL();
this.shader_ = this.create();
gl.shaderSource(this.shader_, this.source_);
gl.compileShader(this.shader_);
if (!gl.getShaderParameter(this.shader_, goog.webgl.COMPILE_STATUS)) {
window.console.log(gl.getShaderInfoLog(this.shader_));
goog.asserts.assert(
gl.getShaderParameter(this.shader_, goog.webgl.COMPILE_STATUS));
}
};
/**
* @protected
* @return {WebGLShader} Shader.
* @return {number} Type.
*/
ol.webgl.Shader.prototype.create = goog.abstractMethod;
ol.webgl.Shader.prototype.getType = goog.abstractMethod;
/**
* @return {WebGLShader} Shader.
* @return {string} Source.
*/
ol.webgl.Shader.prototype.get = function() {
return this.shader_;
ol.webgl.Shader.prototype.getSource = function() {
return this.source_;
};
/**
* @return {boolean} Is animated?
*/
ol.webgl.Shader.prototype.isAnimated = function() {
return false;
};
/**
* @inheritDoc
*/
ol.webgl.Shader.prototype.setGL = function(gl) {
if (!goog.isNull(this.gl)) {
goog.array.forEach(this.uniforms_, function(uniform) {
uniform.setGL(null);
});
if (!goog.isNull(this.shader_)) {
this.gl.deleteShader(this.shader_);
this.shader_ = null;
}
}
goog.base(this, 'setGL', gl);
if (!goog.isNull(gl)) {
this.compile();
goog.array.forEach(this.uniforms_, function(uniform) {
uniform.setGL(gl);
});
}
};
/**
* @param {WebGLProgram} program Program.
*/
ol.webgl.Shader.prototype.setProgram = function(program) {
goog.array.forEach(this.uniforms_, function(uniform) {
uniform.setProgram(program);
});
};
/**
*/
ol.webgl.Shader.prototype.setUniforms = function() {
};
ol.webgl.Shader.prototype.isAnimated = goog.functions.FALSE;

View File

@@ -1,5 +1,6 @@
goog.provide('ol.webgl.shader.Fragment');
goog.require('goog.webgl');
goog.require('ol.webgl.Shader');
@@ -8,19 +9,16 @@ goog.require('ol.webgl.Shader');
* @constructor
* @extends {ol.webgl.Shader}
* @param {string} source Source.
* @param {Array.<ol.webgl.Uniform>=} opt_uniforms Uniforms.
*/
ol.webgl.shader.Fragment = function(source, opt_uniforms) {
goog.base(this, source, opt_uniforms);
ol.webgl.shader.Fragment = function(source) {
goog.base(this, source);
};
goog.inherits(ol.webgl.shader.Fragment, ol.webgl.Shader);
/**
* @protected
* @return {WebGLShader} Shader.
* @inheritDoc
*/
ol.webgl.shader.Fragment.prototype.create = function() {
var gl = this.getGL();
return gl.createShader(gl.FRAGMENT_SHADER);
ol.webgl.shader.Fragment.prototype.getType = function() {
return goog.webgl.FRAGMENT_SHADER;
};

View File

@@ -1,5 +1,6 @@
goog.provide('ol.webgl.shader.Vertex');
goog.require('goog.webgl');
goog.require('ol.webgl.Shader');
@@ -8,19 +9,16 @@ goog.require('ol.webgl.Shader');
* @constructor
* @extends {ol.webgl.Shader}
* @param {string} source Source.
* @param {Array.<ol.webgl.Uniform>=} opt_uniforms Uniforms.
*/
ol.webgl.shader.Vertex = function(source, opt_uniforms) {
goog.base(this, source, opt_uniforms);
ol.webgl.shader.Vertex = function(source) {
goog.base(this, source);
};
goog.inherits(ol.webgl.shader.Vertex, ol.webgl.Shader);
/**
* @protected
* @return {WebGLShader} Shader.
* @inheritDoc
*/
ol.webgl.shader.Vertex.prototype.create = function() {
var gl = this.getGL();
return gl.createShader(gl.VERTEX_SHADER);
ol.webgl.shader.Vertex.prototype.getType = function() {
return goog.webgl.VERTEX_SHADER;
};

View File

@@ -8,9 +8,8 @@ goog.require('ol.webgl.GLObject');
/**
* @constructor
* @extends {ol.webgl.GLObject}
* @param {Image} image Image.
*/
ol.webgl.Texture = function(image) {
ol.webgl.Texture = function() {
goog.base(this);