Skip to content

Commit b653d6c

Browse files
committed
Merge remote-tracking branch 'agi/3d-tiles' into improved-tile-loading
2 parents 3bd95ab + 37e4690 commit b653d6c

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

Source/Scene/Cesium3DTileset.js

+39-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
define([
33
'../Core/Cartesian3',
44
'../Core/Cartographic',
5+
'../Core/Check',
56
'../Core/Color',
67
'../Core/clone',
78
'../Core/defaultValue',
@@ -51,6 +52,7 @@ define([
5152
], function(
5253
Cartesian3,
5354
Cartographic,
55+
Check,
5456
Color,
5557
clone,
5658
defaultValue,
@@ -111,6 +113,7 @@ define([
111113
* @param {Boolean} [options.show=true] Determines if the tileset will be shown.
112114
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the tileset's root tile.
113115
* @param {Number} [options.maximumScreenSpaceError=16] The maximum screen-space error used to drive level-of-detail refinement.
116+
* @param {Number} [options.maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset.
114117
* @param {Boolean} [options.refineToVisible=false] Whether replacement refinement should refine when all visible children are ready. An experimental optimization.
115118
* @param {Boolean} [options.cullWithChildrenBounds=true] Whether to cull tiles using the union of their children bounding volumes.
116119
* @param {Boolean} [options.dynamicScreenSpaceError=false] Reduce the screen space error for tiles that are further away from the camera.
@@ -271,6 +274,7 @@ define([
271274
this._maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 16);
272275
this._baseScreenSpaceError = defaultValue(options.baseScreenSpaceError, 1024);
273276
this._maximumNumberOfLoadedTiles = defaultValue(options.maximumNumberOfLoadedTiles, 256);
277+
this._maximumMemoryUsage = defaultValue(options.maximumMemoryUsage, 512);
274278
this._styleEngine = new Cesium3DTileStyleEngine();
275279

276280
/**
@@ -497,7 +501,7 @@ define([
497501
* console.log('A tile was unloaded from the cache.');
498502
* });
499503
*
500-
* @see Cesium3DTileset#maximumNumberOfLoadedTiles
504+
* @see Cesium3DTileset#maximumMemoryUsage
501505
* @see Cesium3DTileset#trimLoadedTiles
502506
*/
503507
this.tileUnload = new Event();
@@ -844,38 +848,38 @@ define([
844848
},
845849

846850
/**
847-
* The maximum number of tiles to load. Tiles not in view are unloaded to enforce this.
851+
* The maximum amount of memory in MB that can be used by the tileset.
852+
* Tiles not in view are unloaded to enforce this.
848853
* <p>
849854
* If decreasing this value results in unloading tiles, the tiles are unloaded the next frame.
850855
* </p>
851856
* <p>
852-
* If more tiles than <code>maximumNumberOfLoadedTiles</code> are needed
857+
* If tiles sized more than <code>maximumMemoryUsage</code> are needed
853858
* to meet the desired screen-space error, determined by {@link Cesium3DTileset#maximumScreenSpaceError},
854-
* for the current view than the number of tiles loaded will exceed
855-
* <code>maximumNumberOfLoadedTiles</code>. For example, if the maximum is 128 tiles, but
856-
* 150 tiles are needed to meet the screen-space error, then 150 tiles may be loaded. When
859+
* for the current view, then the memory usage of the tiles loaded will exceed
860+
* <code>maximumMemoryUsage</code>. For example, if the maximum is 256 MB, but
861+
* 300 MB of tiles are needed to meet the screen-space error, then 300 MB of tiles may be loaded. When
857862
* these tiles go out of view, they will be unloaded.
858863
* </p>
859864
*
860865
* @memberof Cesium3DTileset.prototype
861866
*
862867
* @type {Number}
863-
* @default 256
868+
* @default 512
864869
*
865-
* @exception {DeveloperError} <code>maximumNumberOfLoadedTiles</code> must be greater than or equal to zero.
870+
* @exception {DeveloperError} <code>maximumMemoryUsage</code> must be greater than or equal to zero.
871+
* @see Cesium3DTileset#totalMemoryUsageInBytes
866872
*/
867-
maximumNumberOfLoadedTiles : {
873+
maximumMemoryUsage : {
868874
get : function() {
869-
return this._maximumNumberOfLoadedTiles;
875+
return this._maximumMemoryUsage;
870876
},
871877
set : function(value) {
872878
//>>includeStart('debug', pragmas.debug);
873-
if (value < 0) {
874-
throw new DeveloperError('maximumNumberOfLoadedTiles must be greater than or equal to zero');
875-
}
879+
Check.typeOf.number.greaterThanOrEquals('value', value, 0);
876880
//>>includeEnd('debug');
877881

878-
this._maximumNumberOfLoadedTiles = value;
882+
this._maximumMemoryUsage = value;
879883
}
880884
},
881885

@@ -1010,6 +1014,21 @@ define([
10101014
set : function(value) {
10111015
this._skipLevels = value;
10121016
}
1017+
},
1018+
1019+
/**
1020+
* Returns the total amount of memory used in bytes by the tileset.
1021+
* This is calculated as the sum of the vertex and index buffer, texture memory and batch table size
1022+
* of the loaded tiles in the tileset.
1023+
*
1024+
* @type {Number}
1025+
* @see Cesium3DTileset#maximumMemoryUsage
1026+
*/
1027+
totalMemoryUsageInBytes : {
1028+
get : function() {
1029+
var stats = this._statistics;
1030+
return stats.textureMemorySizeInBytes + stats.vertexMemorySizeInBytes + stats.batchTableMemorySizeInBytes;
1031+
}
10131032
}
10141033
});
10151034

@@ -1533,17 +1552,19 @@ define([
15331552
tileset._trimTiles = false;
15341553

15351554
var stats = tileset._statistics;
1536-
var maximumNumberOfLoadedTiles = tileset._maximumNumberOfLoadedTiles + 1; // + 1 to account for sentinel
15371555
var replacementList = tileset._replacementList;
15381556
var tileUnload = tileset.tileUnload;
15391557

1558+
var totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes;
1559+
var maximumMemoryUsageInBytes = tileset._maximumMemoryUsage * 1024 * 1024;
1560+
15401561
// Traverse the list only to the sentinel since tiles/nodes to the
15411562
// right of the sentinel were used this frame.
15421563
//
15431564
// The sub-list to the left of the sentinel is ordered from LRU to MRU.
15441565
var sentinel = tileset._replacementSentinel;
15451566
var node = replacementList.head;
1546-
while ((node !== sentinel) && ((replacementList.length > maximumNumberOfLoadedTiles) || trimTiles)) {
1567+
while ((node !== sentinel) && ((totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) {
15471568
var tile = node.item;
15481569

15491570
decrementPointAndFeatureLoadCounts(tileset, tile.content);
@@ -1555,13 +1576,14 @@ define([
15551576
replacementList.remove(currentNode);
15561577

15571578
--stats.numberContentReady;
1579+
totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes;
15581580
}
15591581
}
15601582

15611583
/**
15621584
* Unloads all tiles that weren't selected the previous frame. This can be used to
15631585
* explicitly manage the tile cache and reduce the total number of tiles loaded below
1564-
* {@link Cesium3DTileset#maximumNumberOfLoadedTiles}.
1586+
* {@link Cesium3DTileset#maximumMemoryUsage}.
15651587
* <p>
15661588
* Tile unloads occur at the next frame to keep all the WebGL delete calls
15671589
* within the render loop.

Specs/Scene/Cesium3DTilesetSpec.js

+21-18
Original file line numberDiff line numberDiff line change
@@ -2009,9 +2009,9 @@ defineSuite([
20092009
///////////////////////////////////////////////////////////////////////////
20102010
// Cache replacement tests
20112011

2012-
it('Unload all cached tiles not required to meet SSE', function() {
2012+
it('Unload all cached tiles not required to meet SSE using maximumMemoryUsage', function() {
20132013
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) {
2014-
tileset.maximumNumberOfLoadedTiles = 1;
2014+
tileset.maximumMemoryUsage = 0;
20152015

20162016
// Render parent and four children (using additive refinement)
20172017
viewAllTiles();
@@ -2020,28 +2020,31 @@ defineSuite([
20202020
var stats = tileset._statistics;
20212021
expect(stats.numberOfCommands).toEqual(5);
20222022
expect(stats.numberContentReady).toEqual(5); // Five loaded tiles
2023+
expect(tileset.totalMemoryUsageInBytes).toEqual(44400); // Specific to this tileset
20232024

20242025
// Zoom out so only root tile is needed to meet SSE. This unloads
2025-
// the four children since the max number of loaded tiles is one.
2026+
// the four children since the maximum memory usage is zero.
20262027
viewRootOnly();
20272028
scene.renderForSpecs();
20282029

20292030
expect(stats.numberOfCommands).toEqual(1);
20302031
expect(stats.numberContentReady).toEqual(1);
2032+
expect(tileset.totalMemoryUsageInBytes).toEqual(8880); // Specific to this tileset
20312033

20322034
// Zoom back in so all four children are re-requested.
20332035
viewAllTiles();
20342036

20352037
return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() {
20362038
expect(stats.numberOfCommands).toEqual(5);
20372039
expect(stats.numberContentReady).toEqual(5); // Five loaded tiles
2040+
expect(tileset.totalMemoryUsageInBytes).toEqual(44400); // Specific to this tileset
20382041
});
20392042
});
20402043
});
20412044

2042-
it('Unload some cached tiles not required to meet SSE', function() {
2045+
it('Unload some cached tiles not required to meet SSE using maximumMemoryUsage', function() {
20432046
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) {
2044-
tileset.maximumNumberOfLoadedTiles = 3;
2047+
tileset.maximumMemoryUsage = 0.03; // Just enough memory to allow 3 tiles to remain
20452048

20462049
// Render parent and four children (using additive refinement)
20472050
viewAllTiles();
@@ -2053,7 +2056,7 @@ defineSuite([
20532056

20542057
// Zoom out so only root tile is needed to meet SSE. This unloads
20552058
// two of the four children so three tiles are still loaded (the
2056-
// root and two children) since the max number of loaded tiles is three.
2059+
// root and two children) since the maximum memory usage is sufficient.
20572060
viewRootOnly();
20582061
scene.renderForSpecs();
20592062

@@ -2070,9 +2073,9 @@ defineSuite([
20702073
});
20712074
});
20722075

2073-
it('Unloads cached tiles outside of the view frustum', function() {
2076+
it('Unloads cached tiles outside of the view frustum using maximumMemoryUsage', function() {
20742077
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) {
2075-
tileset.maximumNumberOfLoadedTiles = 0;
2078+
tileset.maximumMemoryUsage = 0;
20762079

20772080
scene.renderForSpecs();
20782081
var stats = tileset._statistics;
@@ -2098,12 +2101,12 @@ defineSuite([
20982101
});
20992102
});
21002103

2101-
it('Unloads cached tiles in a tileset with external tileset.json', function() {
2104+
it('Unloads cached tiles in a tileset with external tileset.json using maximumMemoryUsage', function() {
21022105
return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) {
21032106
var stats = tileset._statistics;
21042107
var replacementList = tileset._replacementList;
21052108

2106-
tileset.maximumNumberOfLoadedTiles = 2;
2109+
tileset.maximumMemoryUsage = 0.025;
21072110

21082111
scene.renderForSpecs();
21092112
expect(stats.numberOfCommands).toEqual(5);
@@ -2131,11 +2134,11 @@ defineSuite([
21312134
});
21322135
});
21332136

2134-
it('Unloads cached tiles in a tileset with empty tiles', function() {
2137+
it('Unloads cached tiles in a tileset with empty tiles using maximumMemoryUsage', function() {
21352138
return Cesium3DTilesTester.loadTileset(scene, tilesetEmptyRootUrl).then(function(tileset) {
21362139
var stats = tileset._statistics;
21372140

2138-
tileset.maximumNumberOfLoadedTiles = 2;
2141+
tileset.maximumMemoryUsage = 0.025;
21392142

21402143
scene.renderForSpecs();
21412144
expect(stats.numberOfCommands).toEqual(4);
@@ -2160,15 +2163,15 @@ defineSuite([
21602163
});
21612164
});
21622165

2163-
it('Unload cached tiles when a tileset uses replacement refinement', function() {
2166+
it('Unload cached tiles when a tileset uses replacement refinement using maximumMemoryUsage', function() {
21642167
// No children have content, but all grandchildren have content
21652168
//
21662169
// C
21672170
// E E
21682171
// C C C C
21692172
//
21702173
return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement1Url).then(function(tileset) {
2171-
tileset.maximumNumberOfLoadedTiles = 1;
2174+
tileset.maximumMemoryUsage = 0; // Only root needs to be visible
21722175

21732176
// Render parent and four children (using additive refinement)
21742177
viewAllTiles();
@@ -2198,7 +2201,7 @@ defineSuite([
21982201

21992202
it('Explicitly unloads cached tiles with trimLoadedTiles', function() {
22002203
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) {
2201-
tileset.maximumNumberOfLoadedTiles = 5;
2204+
tileset.maximumMemoryUsage = 0.05;
22022205

22032206
// Render parent and four children (using additive refinement)
22042207
viewAllTiles();
@@ -2226,7 +2229,7 @@ defineSuite([
22262229

22272230
it('tileUnload event is raised', function() {
22282231
return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) {
2229-
tileset.maximumNumberOfLoadedTiles = 1;
2232+
tileset.maximumMemoryUsage = 0;
22302233

22312234
// Render parent and four children (using additive refinement)
22322235
viewAllTiles();
@@ -2252,12 +2255,12 @@ defineSuite([
22522255
});
22532256
});
22542257

2255-
it('maximumNumberOfLoadedTiles throws when negative', function() {
2258+
it('maximumMemoryUsage throws when negative', function() {
22562259
var tileset = new Cesium3DTileset({
22572260
url : tilesetUrl
22582261
});
22592262
expect(function() {
2260-
tileset.maximumNumberOfLoadedTiles = -1;
2263+
tileset.maximumMemoryUsage = -1;
22612264
}).toThrowDeveloperError();
22622265
});
22632266

0 commit comments

Comments
 (0)