Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request performance improvements #6243

Closed
wants to merge 9 commits into from
8 changes: 4 additions & 4 deletions Source/Scene/Cesium3DTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,16 @@ define([
this.hasTilesetContent = false;

/**
* The corresponding node in the cache replacement list.
* The corresponding node in the cache.
*
* See {@link Cesium3DTilesetCache}
*
* @type {DoublyLinkedListNode}
* @readonly
*
* @private
*/
this.replacementNode = undefined;
this.cacheNode = undefined;

var expire = header.expire;
var expireDuration;
Expand Down Expand Up @@ -730,8 +732,6 @@ define([
this._contentReadyToProcessPromise = undefined;
this._contentReadyPromise = undefined;

this.replacementNode = undefined;

this.lastStyleTime = 0;
this.clippingPlanesDirty = (this._clippingPlanesState === 0);
this._clippingPlanesState = 0;
Expand Down
67 changes: 17 additions & 50 deletions Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ define([
'./Cesium3DTileColorBlendMode',
'./Cesium3DTileContentState',
'./Cesium3DTileOptimizations',
'./Cesium3DTilesetCache',
'./Cesium3DTilesetStatistics',
'./Cesium3DTilesetTraversal',
'./Cesium3DTileStyleEngine',
Expand Down Expand Up @@ -68,6 +69,7 @@ define([
Cesium3DTileColorBlendMode,
Cesium3DTileContentState,
Cesium3DTileOptimizations,
Cesium3DTilesetCache,
Cesium3DTilesetStatistics,
Cesium3DTilesetTraversal,
Cesium3DTileStyleEngine,
Expand Down Expand Up @@ -168,6 +170,7 @@ define([
this._properties = undefined; // Metadata for per-model/point/etc properties
this._geometricError = undefined; // Geometric error when the tree is not rendered at all
this._gltfUpAxis = undefined;
this._cache = new Cesium3DTilesetCache();
this._processingQueue = [];
this._selectedTiles = [];
this._requestedTiles = [];
Expand All @@ -176,14 +179,6 @@ define([
this._loadTimestamp = undefined;
this._timeSinceLoad = 0.0;

var replacementList = new DoublyLinkedList();

// [head, sentinel) -> tiles that weren't selected this frame and may be replaced
// (sentinel, tail] -> tiles that were selected this frame
this._replacementList = replacementList; // Tiles with content loaded. For cache management.
this._replacementSentinel = replacementList.add();
this._trimTiles = false;

this._cullWithChildrenBounds = defaultValue(options.cullWithChildrenBounds, true);

this._hasMixedContent = false;
Expand Down Expand Up @@ -1485,10 +1480,8 @@ define([
tileset._statistics.incrementLoadCounts(tile.content);
++tileset._statistics.numberOfTilesWithContentReady;

// Add to the tile cache. Previously expired tiles are already in the cache.
if (!defined(tile.replacementNode)) {
tile.replacementNode = tileset._replacementList.add(tile);
}
// Add to the tile cache. Previously expired tiles are already in the cache and won't get re-added.
tileset._cache.add(tile);
}

tileset.tileLoad.raiseEvent(tile);
Expand Down Expand Up @@ -1748,52 +1741,27 @@ define([
stack.push(children[i]);
}
if (tile !== root) {
unloadTileFromCache(tileset, tile);
tile.destroy();
destroyTile(tileset, tile);
--statistics.numberOfTilesTotal;
}
}
root.children = [];
}

function unloadTileFromCache(tileset, tile) {
var node = tile.replacementNode;
if (!defined(node)) {
return;
}

var statistics = tileset._statistics;
var replacementList = tileset._replacementList;
var tileUnload = tileset.tileUnload;
function unloadTile(tileset, tile) {
tileset.tileUnload.raiseEvent(tile);
tileset._statistics.decrementLoadCounts(tile.content);
--tileset._statistics.numberOfTilesWithContentReady;
tile.unloadContent();
}

tileUnload.raiseEvent(tile);
replacementList.remove(node);
statistics.decrementLoadCounts(tile.content);
--statistics.numberOfTilesWithContentReady;
function destroyTile(tileset, tile) {
tileset._cache.unloadTile(tileset, tile, unloadTile);
tile.destroy();
}

function unloadTiles(tileset) {
var trimTiles = tileset._trimTiles;
tileset._trimTiles = false;

var replacementList = tileset._replacementList;

var totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes;
var maximumMemoryUsageInBytes = tileset._maximumMemoryUsage * 1024 * 1024;

// Traverse the list only to the sentinel since tiles/nodes to the
// right of the sentinel were used this frame.
//
// The sub-list to the left of the sentinel is ordered from LRU to MRU.
var sentinel = tileset._replacementSentinel;
var node = replacementList.head;
while ((node !== sentinel) && ((totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) {
var tile = node.item;
node = node.next;
unloadTileFromCache(tileset, tile);
tile.unloadContent();
totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes;
}
tileset._cache.unloadTiles(tileset, unloadTile);
}

/**
Expand All @@ -1806,8 +1774,7 @@ define([
* </p>
*/
Cesium3DTileset.prototype.trimLoadedTiles = function() {
// Defer to next frame so WebGL delete calls happen inside the render loop
this._trimTiles = true;
this._cache.trim();
};

///////////////////////////////////////////////////////////////////////////
Expand Down
79 changes: 79 additions & 0 deletions Source/Scene/Cesium3DTilesetCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
define([
'../Core/defined',
'../Core/DoublyLinkedList'
], function(
defined,
DoublyLinkedList) {
'use strict';

/**
* Stores tiles with content loaded.
*
* @private
*/
function Cesium3DTilesetCache() {
// [head, sentinel) -> tiles that weren't selected this frame and may be removed from the cache
// (sentinel, tail] -> tiles that were selected this frame
this._list = new DoublyLinkedList();
this._sentinel = this._list.add();
this._trimTiles = false;
}

Cesium3DTilesetCache.prototype.reset = function() {
// Move sentinel node to the tail so, at the start of the frame, all tiles
// may be potentially replaced. Tiles are moved to the right of the sentinel
// when they are selected so they will not be replaced.
this._list.splice(this._list.tail, this._sentinel);
};

Cesium3DTilesetCache.prototype.touch = function(tile) {
var node = tile.cacheNode;
if (defined(node)) {
this._list.splice(this._sentinel, node);
}
};

Cesium3DTilesetCache.prototype.add = function(tile) {
if (!defined(tile.cacheNode)) {
tile.cacheNode = this._list.add(tile);
}
};

Cesium3DTilesetCache.prototype.unloadTile = function(tileset, tile, unloadCallback) {
var node = tile.cacheNode;
if (!defined(node)) {
return;
}

this._list.remove(node);
tile.cacheNode = undefined;
unloadCallback(tileset, tile);
};

Cesium3DTilesetCache.prototype.unloadTiles = function(tileset, unloadCallback) {
var trimTiles = this._trimTiles;
this._trimTiles = false;

var list = this._list;

var maximumMemoryUsageInBytes = tileset.maximumMemoryUsage * 1024 * 1024;

// Traverse the list only to the sentinel since tiles/nodes to the
// right of the sentinel were used this frame.
//
// The sub-list to the left of the sentinel is ordered from LRU to MRU.
var sentinel = this._sentinel;
var node = list.head;
while ((node !== sentinel) && ((tileset.totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) {
var tile = node.item;
node = node.next;
this.unloadTile(tileset, tile, unloadCallback);
}
};

Cesium3DTilesetCache.prototype.trim = function() {
this._trimTiles = true;
};

return Cesium3DTilesetCache;
});
14 changes: 4 additions & 10 deletions Source/Scene/Cesium3DTilesetTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ define([
/**
* @private
*/
var Cesium3DTilesetTraversal = {};
function Cesium3DTilesetTraversal() {
}

function selectTiles(tileset, frameState, outOfCore) {
if (tileset.debugFreezeFrame) {
Expand All @@ -40,11 +41,7 @@ define([
tileset._selectedTilesToStyle.length = 0;
tileset._hasMixedContent = false;

// Move sentinel node to the tail so, at the start of the frame, all tiles
// may be potentially replaced. Tiles are moved to the right of the sentinel
// when they are selected so they will not be replaced.
var replacementList = tileset._replacementList;
replacementList.splice(replacementList.tail, tileset._replacementSentinel);
tileset._cache.reset();

var root = tileset._root;
root.updateTransform(tileset._modelMatrix);
Expand Down Expand Up @@ -625,10 +622,7 @@ define([
if (!outOfCore) {
return;
}
var node = tile.replacementNode;
if (defined(node)) {
tileset._replacementList.splice(tileset._replacementSentinel, node);
}
tileset._cache.touch(tile);
}

function computeSSE(tile, frameState) {
Expand Down
8 changes: 4 additions & 4 deletions Specs/Scene/Cesium3DTilesetSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2294,14 +2294,14 @@ defineSuite([
it('Unloads cached tiles in a tileset with external tileset JSON file using maximumMemoryUsage', function() {
return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) {
var statistics = tileset._statistics;
var replacementList = tileset._replacementList;
var cacheList = tileset._cache._list;

tileset.maximumMemoryUsage = 0.025;

scene.renderForSpecs();
expect(statistics.numberOfCommands).toEqual(5);
expect(statistics.numberOfTilesWithContentReady).toEqual(5);
expect(replacementList.length - 1).toEqual(5); // Only tiles with content are on the replacement list. -1 for sentinel.
expect(cacheList.length - 1).toEqual(5); // Only tiles with content are on the replacement list. -1 for sentinel.

// Zoom out so only root tile is needed to meet SSE. This unloads
// all tiles except the root and one of the b3dm children
Expand All @@ -2310,7 +2310,7 @@ defineSuite([

expect(statistics.numberOfCommands).toEqual(1);
expect(statistics.numberOfTilesWithContentReady).toEqual(2);
expect(replacementList.length - 1).toEqual(2);
expect(cacheList.length - 1).toEqual(2);

// Reset camera so all tiles are reloaded
viewAllTiles();
Expand All @@ -2319,7 +2319,7 @@ defineSuite([
expect(statistics.numberOfCommands).toEqual(5);
expect(statistics.numberOfTilesWithContentReady).toEqual(5);

expect(replacementList.length - 1).toEqual(5);
expect(cacheList.length - 1).toEqual(5);
});
});
});
Expand Down