Files
openlayers/src/ol/webgl/context.js
Andreas Hocevar fbdbbfb7a7 Get rid of stability annotations and document stability with api
This change adds a stability value to the api annotation, with
'experimental' as default value.

enum, typedef and event annotations are never exportable, but
api annotations are needed there to make them appear in the
docs.

Nested typedefs are no longer inlined recursively, because the
resulting tables get too wide with the current template.
2014-04-29 09:53:07 -06:00

270 lines
6.7 KiB
JavaScript

goog.provide('ol.webgl.Context');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.log');
goog.require('goog.object');
goog.require('ol.structs.Buffer');
goog.require('ol.structs.IntegerSet');
goog.require('ol.webgl.WebGLContextEventType');
/**
* @typedef {{buf: ol.structs.Buffer,
* buffer: WebGLBuffer,
* dirtySet: ol.structs.IntegerSet}}
*/
ol.webgl.BufferCacheEntry;
/**
* @constructor
* @extends {goog.events.EventTarget}
* @param {HTMLCanvasElement} canvas Canvas.
* @param {WebGLRenderingContext} gl GL.
* @todo api
*/
ol.webgl.Context = function(canvas, gl) {
/**
* @private
* @type {HTMLCanvasElement}
*/
this.canvas_ = canvas;
/**
* @private
* @type {WebGLRenderingContext}
*/
this.gl_ = gl;
/**
* @private
* @type {Object.<number, ol.webgl.BufferCacheEntry>}
*/
this.bufferCache_ = {};
/**
* @private
* @type {Object.<number, WebGLShader>}
*/
this.shaderCache_ = {};
/**
* @private
* @type {Object.<string, WebGLProgram>}
*/
this.programCache_ = {};
/**
* @private
* @type {WebGLProgram}
*/
this.currentProgram_ = null;
goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST,
this.handleWebGLContextLost, false, this);
goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
this.handleWebGLContextRestored, false, this);
};
/**
* @param {number} target Target.
* @param {ol.structs.Buffer} buf Buffer.
*/
ol.webgl.Context.prototype.bindBuffer = function(target, buf) {
var gl = this.getGL();
var arr = buf.getArray();
var bufferKey = goog.getUid(buf);
if (bufferKey in this.bufferCache_) {
var bufferCacheEntry = this.bufferCache_[bufferKey];
gl.bindBuffer(target, bufferCacheEntry.buffer);
bufferCacheEntry.dirtySet.forEachRange(function(start, stop) {
// FIXME check if slice is really efficient here
var slice = arr.slice(start, stop);
gl.bufferSubData(
target,
start,
target == goog.webgl.ARRAY_BUFFER ?
new Float32Array(slice) :
new Uint16Array(slice));
});
bufferCacheEntry.dirtySet.clear();
} else {
var buffer = gl.createBuffer();
gl.bindBuffer(target, buffer);
gl.bufferData(
target,
target == goog.webgl.ARRAY_BUFFER ?
new Float32Array(arr) : new Uint16Array(arr),
buf.getUsage());
var dirtySet = new ol.structs.IntegerSet();
buf.addDirtySet(dirtySet);
this.bufferCache_[bufferKey] = {
buf: buf,
buffer: buffer,
dirtySet: dirtySet
};
}
};
/**
* @param {ol.structs.Buffer} buf Buffer.
*/
ol.webgl.Context.prototype.deleteBuffer = function(buf) {
var gl = this.getGL();
var bufferKey = goog.getUid(buf);
goog.asserts.assert(bufferKey in this.bufferCache_);
var bufferCacheEntry = this.bufferCache_[bufferKey];
bufferCacheEntry.buf.removeDirtySet(bufferCacheEntry.dirtySet);
if (!gl.isContextLost()) {
gl.deleteBuffer(bufferCacheEntry.buffer);
}
delete this.bufferCache_[bufferKey];
};
/**
* @inheritDoc
*/
ol.webgl.Context.prototype.disposeInternal = function() {
goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) {
bufferCacheEntry.buf.removeDirtySet(bufferCacheEntry.dirtySet);
});
var gl = this.getGL();
if (!gl.isContextLost()) {
goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) {
gl.deleteBuffer(bufferCacheEntry.buffer);
});
goog.object.forEach(this.programCache_, function(program) {
gl.deleteProgram(program);
});
goog.object.forEach(this.shaderCache_, function(shader) {
gl.deleteShader(shader);
});
}
};
/**
* @return {HTMLCanvasElement} Canvas.
*/
ol.webgl.Context.prototype.getCanvas = function() {
return this.canvas_;
};
/**
* @return {WebGLRenderingContext} GL.
* @todo api
*/
ol.webgl.Context.prototype.getGL = function() {
return this.gl_;
};
/**
* @param {ol.webgl.Shader} shaderObject Shader object.
* @return {WebGLShader} Shader.
*/
ol.webgl.Context.prototype.getShader = function(shaderObject) {
var shaderKey = goog.getUid(shaderObject);
if (shaderKey in this.shaderCache_) {
return this.shaderCache_[shaderKey];
} else {
var gl = this.getGL();
var shader = gl.createShader(shaderObject.getType());
gl.shaderSource(shader, shaderObject.getSource());
gl.compileShader(shader);
if (goog.DEBUG) {
if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) &&
!gl.isContextLost()) {
goog.log.error(this.logger_, gl.getShaderInfoLog(shader));
}
}
goog.asserts.assert(
gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) ||
gl.isContextLost());
this.shaderCache_[shaderKey] = shader;
return shader;
}
};
/**
* @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader.
* @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader.
* @return {WebGLProgram} Program.
*/
ol.webgl.Context.prototype.getProgram = function(
fragmentShaderObject, vertexShaderObject) {
var programKey =
goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject);
if (programKey in this.programCache_) {
return this.programCache_[programKey];
} 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 (goog.DEBUG) {
if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) &&
!gl.isContextLost()) {
goog.log.error(this.logger_, gl.getProgramInfoLog(program));
}
}
goog.asserts.assert(
gl.getProgramParameter(program, goog.webgl.LINK_STATUS) ||
gl.isContextLost());
this.programCache_[programKey] = program;
return program;
}
};
/**
* FIXME empy description for jsdoc
*/
ol.webgl.Context.prototype.handleWebGLContextLost = function() {
goog.object.clear(this.bufferCache_);
goog.object.clear(this.shaderCache_);
goog.object.clear(this.programCache_);
this.currentProgram_ = null;
};
/**
* FIXME empy description for jsdoc
*/
ol.webgl.Context.prototype.handleWebGLContextRestored = function() {
};
/**
* @param {WebGLProgram} program Program.
* @return {boolean} Changed.
* @todo api
*/
ol.webgl.Context.prototype.useProgram = function(program) {
if (program == this.currentProgram_) {
return false;
} else {
var gl = this.getGL();
gl.useProgram(program);
this.currentProgram_ = program;
return true;
}
};
/**
* @private
* @type {goog.log.Logger}
*/
ol.webgl.Context.prototype.logger_ = goog.log.getLogger('ol.webgl.Context');