Skip to content

Commit

Permalink
Merge pull request #528 from AnalyticalGraphicsInc/contextObjectCache
Browse files Browse the repository at this point in the history
Context object cache
  • Loading branch information
pjcozzi committed Feb 25, 2013
2 parents 884fadc + 6c26cec commit 1c9e463
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 90 deletions.
23 changes: 23 additions & 0 deletions Source/Renderer/Context.js
Expand Up @@ -254,6 +254,18 @@ define([

this._defaultTexture = undefined;
this._defaultCubeMap = undefined;

/**
* A cache of objects tied to this context. Just before the Context is destroyed,
* <code>destroy</code> will be invoked on each object in this object literal that has
* such a method. This is useful for caching any objects that might otherwise
* be stored globally, except they're tied to a particular context, and to manage
* their lifetime.
*
* @private
* @type {Object}
*/
this.cache = {};
};

Context.prototype._enableOrDisable = function(glEnum, enable) {
Expand Down Expand Up @@ -2794,6 +2806,17 @@ define([
};

Context.prototype.destroy = function() {
// Destroy all objects in the cache that have a destroy method.
var cache = this.cache;
for (var property in cache) {
if (cache.hasOwnProperty(property)) {
var propertyValue = cache[property];
if (typeof propertyValue.destroy !== 'undefined') {
propertyValue.destroy();
}
}
}

this._shaderCache = this._shaderCache.destroy();
this._defaultTexture = this._defaultTexture && this._defaultTexture.destroy();
this._defaultCubeMap = this._defaultCubeMap && this._defaultCubeMap.destroy();
Expand Down
38 changes: 14 additions & 24 deletions Source/Scene/BillboardCollection.js
Expand Up @@ -551,18 +551,11 @@ define([
function getDirectionsVertexBuffer(context) {
var sixteenK = 16 * 1024;

// Per-context cache for billboard collections
context._primitivesCache = context._primitivesCache || {};
var primitivesCache = context._primitivesCache;
primitivesCache._billboardCollection = primitivesCache._billboardCollection || {};
var c = primitivesCache._billboardCollection;

if (c.directionsVertexBuffer) {
return c.directionsVertexBuffer;
var directionsVertexBuffer = context.cache.billboardCollection_directionsVertexBuffer;
if (typeof directionsVertexBuffer !== 'undefined') {
return directionsVertexBuffer;
}

c.directionsVertexBuffer = c.directionsVertexBuffer && c.directionsVertexBuffer.destroy();

var directions = new Uint8Array(sixteenK * 4 * 2);
for (var i = 0, j = 0; i < sixteenK; ++i) {
directions[j++] = 0;
Expand All @@ -580,22 +573,18 @@ define([

// PERFORMANCE_IDEA: Should we reference count billboard collections, and eventually delete this?
// Is this too much memory to allocate up front? Should we dynamically grow it?
c.directionsVertexBuffer = context.createVertexBuffer(directions, BufferUsage.STATIC_DRAW);
c.directionsVertexBuffer.setVertexArrayDestroyable(false);
return c.directionsVertexBuffer;
directionsVertexBuffer = context.createVertexBuffer(directions, BufferUsage.STATIC_DRAW);
directionsVertexBuffer.setVertexArrayDestroyable(false);
context.cache.billboardCollection_directionsVertexBuffer = directionsVertexBuffer;
return directionsVertexBuffer;
}

function getIndexBuffer(context) {
var sixteenK = 16 * 1024;

// Per-context cache for billboard collections
context._primitivesCache = context._primitivesCache || {};
var primitivesCache = context._primitivesCache;
primitivesCache._billboardCollection = primitivesCache._billboardCollection || {};
var c = primitivesCache._billboardCollection;

if (c.indexBuffer) {
return c.indexBuffer;
var indexBuffer = context.cache.billboardCollection_indexBuffer;
if (typeof indexBuffer !== 'undefined') {
return indexBuffer;
}

var length = sixteenK * 6;
Expand All @@ -612,9 +601,10 @@ define([

// PERFORMANCE_IDEA: Should we reference count billboard collections, and eventually delete this?
// Is this too much memory to allocate up front? Should we dynamically grow it?
c.indexBuffer = context.createIndexBuffer(indices, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
c.indexBuffer.setVertexArrayDestroyable(false);
return c.indexBuffer;
indexBuffer = context.createIndexBuffer(indices, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
indexBuffer.setVertexArrayDestroyable(false);
context.cache.billboardCollection_indexBuffer = indexBuffer;
return indexBuffer;
}

BillboardCollection.prototype.computeNewBuffersUsage = function() {
Expand Down
39 changes: 8 additions & 31 deletions Source/Scene/EllipsoidPrimitive.js
Expand Up @@ -190,47 +190,25 @@ define([
};
};

// Per-context cache for ellipsoids
var vertexArrayCache = {};

function getVertexArray(context) {
var c = vertexArrayCache[context.getId()];

if (typeof c !== 'undefined' &&
typeof c.vertexArray !== 'undefined') {
var vertexArray = context.cache.ellipsoidPrimitive_vertexArray;

++c.referenceCount;
return c;
if (typeof vertexArray !== 'undefined') {
return vertexArray;
}

var mesh = BoxTessellator.compute({
dimensions : new Cartesian3(2.0, 2.0, 2.0)
});

var va = context.createVertexArrayFromMesh({
vertexArray = context.createVertexArrayFromMesh({
mesh: mesh,
attributeIndices: attributeIndices,
bufferUsage: BufferUsage.STATIC_DRAW
});

var cachedVA = {
vertexArray : va,
referenceCount : 1,

release : function() {
if (typeof this.vertexArray !== 'undefined' &&
--this.referenceCount === 0) {

// PERFORMANCE_IDEA: Schedule this for a few hundred frames later so we don't thrash the cache
this.vertexArray = this.vertexArray.destroy();
}

return undefined;
}
};

vertexArrayCache[context.getId()] = cachedVA;
return cachedVA;
context.cache.ellipsoidPrimitive_vertexArray = vertexArray;
return vertexArray;
}

/**
Expand Down Expand Up @@ -314,7 +292,7 @@ define([
this._sp = context.getShaderCache().getShaderProgram(EllipsoidVS, fsSource, attributeIndices);

colorCommand.primitiveType = PrimitiveType.TRIANGLES;
colorCommand.vertexArray = this._va.vertexArray;
colorCommand.vertexArray = this._va;
colorCommand.renderState = this._rs;
colorCommand.shaderProgram = this._sp;
colorCommand.uniformMap = combine([this._uniforms, this._material._uniforms], false, false);
Expand Down Expand Up @@ -349,7 +327,7 @@ define([
this._pickSP = context.getShaderCache().getShaderProgram(EllipsoidVS, pickFS, attributeIndices);

pickCommand.primitiveType = PrimitiveType.TRIANGLES;
pickCommand.vertexArray = this._va.vertexArray;
pickCommand.vertexArray = this._va;
pickCommand.renderState = this._rs;
pickCommand.shaderProgram = this._pickSP;
pickCommand.uniformMap = combine([this._uniforms, pickMaterial._uniforms], false, false);
Expand Down Expand Up @@ -402,7 +380,6 @@ define([
*/
EllipsoidPrimitive.prototype.destroy = function() {
this._sp = this._sp && this._sp.release();
this._va = this._va && this._va.release();
this._pickSP = this._pickSP && this._pickSP.release();
this._pickId = this._pickId && this._pickId.destroy();
return destroyObject(this);
Expand Down
17 changes: 11 additions & 6 deletions Source/Scene/Tile.js
Expand Up @@ -652,18 +652,23 @@ define([
return parent.terrainData.isChildAvailable(parent.x, parent.y, tile.x, tile.y);
}

var waterMaskDataByContext = {};

function createWaterMaskTexture(context, waterMask) {
var result;

var contextID = context.getId();
var waterMaskData = waterMaskDataByContext[contextID];
var waterMaskData = context.cache.tile_waterMaskData;
if (typeof waterMaskData === 'undefined') {
waterMaskData = waterMaskDataByContext[contextID] = {
waterMaskData = context.cache.tile_waterMaskData = {
allWaterTexture : undefined,
allLandTexture : undefined,
sampler : undefined
sampler : undefined,
destroy : function() {
if (typeof this.allWaterTexture !== 'undefined') {
this.allWaterTexture.destroy();
}
if (typeof this.allLandTexture !== 'undefined') {
this.allLandTexture.destroy();
}
}
};
}

Expand Down
36 changes: 7 additions & 29 deletions Source/Scene/ViewportQuad.js
Expand Up @@ -105,17 +105,12 @@ define([
textureCoordinates : 1
};

var vertexArrayCache = {};

function getVertexArray(context) {
// Per-context cache for viewport quads
var c = vertexArrayCache[context.getId()];

if (typeof c !== 'undefined' &&
typeof c.vertexArray !== 'undefined') {
var vertexArray = context.cache.viewportQuad_vertexArray;

++c.referenceCount;
return c;
if (typeof vertexArray !== 'undefined') {
return vertexArray;
}

var mesh = {
Expand Down Expand Up @@ -144,30 +139,14 @@ define([
}
};

var va = context.createVertexArrayFromMesh({
vertexArray = context.createVertexArrayFromMesh({
mesh : mesh,
attributeIndices : attributeIndices,
bufferUsage : BufferUsage.STATIC_DRAW
});

var cachedVA = {
vertexArray : va,
referenceCount : 1,

release : function() {
if (typeof this.vertexArray !== 'undefined' &&
--this.referenceCount === 0) {

// TODO: Schedule this for a few hundred frames later so we don't thrash the cache
this.vertexArray = this.vertexArray.destroy();
}

return undefined;
}
};

vertexArrayCache[context.getId()] = cachedVA;
return cachedVA;
context.cache.viewportQuad_vertexArray = vertexArray;
return vertexArray;
}

/**
Expand All @@ -194,7 +173,7 @@ define([

if (typeof this._va === 'undefined') {
this._va = getVertexArray(context);
this._overlayCommand.vertexArray = this._va.vertexArray;
this._overlayCommand.vertexArray = this._va;
this._overlayCommand.renderState = context.createRenderState({
blending : BlendingState.ALPHA_BLEND
});
Expand Down Expand Up @@ -260,7 +239,6 @@ define([
* quad = quad && quad.destroy();
*/
ViewportQuad.prototype.destroy = function() {
this._va = this._va && this._va.release();
this._overlayCommand.shaderProgram = this._overlayCommand.shaderProgram && this._overlayCommand.shaderProgram.release();

return destroyObject(this);
Expand Down
15 changes: 15 additions & 0 deletions Specs/Renderer/ContextSpec.js
Expand Up @@ -226,4 +226,19 @@ defineSuite([
c.destroy();
expect(c.isDestroyed()).toEqual(true);
});

it('destroying Context destroys objects in cache', function() {
var c = createContext();
var destroyableObject = jasmine.createSpyObj('destroyableObject', ['destroy']);
c.cache.foo = destroyableObject;
c.destroy();
expect(destroyableObject.destroy).toHaveBeenCalled();
});

it('non-destroyable objects are allowed in the cache', function() {
var c = createContext();
var nonDestroyableObject = {};
c.cache.foo = nonDestroyableObject;
c.destroy();
});
}, 'WebGL');

0 comments on commit 1c9e463

Please sign in to comment.