diff --git a/CHANGES.md b/CHANGES.md
index 1db5fa562d03..97fcd49f305c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,17 @@
# Change Log
+### 1.107 - 2023-07-01
+
+##### Additions :tada:
+
+- Added `Cesium3DTileset.cacheBytes` and `Cesium3DTileset.maximumCacheOverflowBytes` to better control memory usage. To replicate previous behavior, convert `maximumMemoryUsage` from MB to bytes, assign the value to `cacheBytes`, and set `maximumCacheOverflowBytes = Number.MAX_VALUE`
+
+##### Fixes :wrench:
+
+##### Deprecated :hourglass_flowing_sand:
+
+- `Cesium3DTileset.maximumMemoryUsage` has been deprecated in CesiumJS 1.107. It will be removed in 1.110. Use `Cesium3DTileset.cacheBytes` and `Cesium3DTileset.maximumCacheOverflowBytes` instead. [#11310](https://github.com/CesiumGS/cesium/pull/11310)
+
### 1.106.1 - 2023-06-02
This is an npm-only release to fix a dependency issue published in 1.106
diff --git a/packages/engine/Source/Scene/Cesium3DTile.js b/packages/engine/Source/Scene/Cesium3DTile.js
index 0993a95629bd..9388f5660870 100644
--- a/packages/engine/Source/Scene/Cesium3DTile.js
+++ b/packages/engine/Source/Scene/Cesium3DTile.js
@@ -870,7 +870,7 @@ function isPriorityDeferred(tile, frameState) {
);
const sseRelaxation = tileset.foveatedInterpolationCallback(
tileset.foveatedMinimumScreenSpaceErrorRelaxation,
- tileset.maximumScreenSpaceError,
+ tileset.memoryAdjustedScreenSpaceError,
normalizedFoveatedFactor
);
const sse =
@@ -878,7 +878,7 @@ function isPriorityDeferred(tile, frameState) {
? tile.parent._screenSpaceError * 0.5
: tile._screenSpaceError;
- return tileset.maximumScreenSpaceError - sseRelaxation <= sse;
+ return tileset.memoryAdjustedScreenSpaceError - sseRelaxation <= sse;
}
const scratchJulianDate = new JulianDate();
@@ -957,12 +957,11 @@ function isPriorityProgressiveResolution(tileset, tile) {
return false;
}
+ const maximumScreenSpaceError = tileset.memoryAdjustedScreenSpaceError;
let isProgressiveResolutionTile =
- tile._screenSpaceErrorProgressiveResolution >
- tileset._maximumScreenSpaceError; // Mark non-SSE leaves
+ tile._screenSpaceErrorProgressiveResolution > maximumScreenSpaceError; // Mark non-SSE leaves
tile._priorityProgressiveResolutionScreenSpaceErrorLeaf = false; // Needed for skipLOD
const parent = tile.parent;
- const maximumScreenSpaceError = tileset._maximumScreenSpaceError;
const tilePasses =
tile._screenSpaceErrorProgressiveResolution <= maximumScreenSpaceError;
const parentFails =
diff --git a/packages/engine/Source/Scene/Cesium3DTileset.js b/packages/engine/Source/Scene/Cesium3DTileset.js
index 7d7466bf4b6f..9a81f98a033a 100644
--- a/packages/engine/Source/Scene/Cesium3DTileset.js
+++ b/packages/engine/Source/Scene/Cesium3DTileset.js
@@ -68,7 +68,9 @@ import Cesium3DTilesetSkipTraversal from "./Cesium3DTilesetSkipTraversal.js";
* @property {Axis} [modelForwardAxis=Axis.X] Which axis is considered forward when loading models for tile contents.
* @property {ShadowMode} [shadows=ShadowMode.ENABLED] Determines whether the tileset casts or receives shadows from light sources.
* @property {number} [maximumScreenSpaceError=16] The maximum screen space error used to drive level of detail refinement.
- * @property {number} [maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset.
+ * @property {number} [maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset. Deprecated.
+ * @property {number} [cacheBytes=536870912] The size (in bytes) to which the tile cache will be trimmed, if the cache contains tiles not needed for the current view.
+ * @property {number} [maximumCacheOverflowBytes=536870912] The maximum additional memory (in bytes) to allow for cache headroom, if more than {@link Cesium3DTileset#cacheBytes} are needed for the current view.
* @property {boolean} [cullWithChildrenBounds=true] Optimization option. Whether to cull tiles using the union of their children bounding volumes.
* @property {boolean} [cullRequestsWhileMoving=true] Optimization option. Don't request tiles that will likely be unused when they come back because of the camera's movement. This optimization only applies to stationary tilesets.
* @property {number} [cullRequestsWhileMovingMultiplier=60.0] Optimization option. Multiplier used in culling requests while moving. Larger is more aggressive culling, smaller less aggressive culling.
@@ -221,7 +223,33 @@ function Cesium3DTileset(options) {
options.maximumScreenSpaceError,
16
);
- this._maximumMemoryUsage = defaultValue(options.maximumMemoryUsage, 512);
+ this._memoryAdjustedScreenSpaceError = this._maximumScreenSpaceError;
+
+ let defaultCacheBytes = 512 * 1024 * 1024;
+ if (defined(options.maximumMemoryUsage)) {
+ deprecationWarning(
+ "Cesium3DTileset.maximumMemoryUsage",
+ "Cesium3DTileset.maximumMemoryUsage was deprecated in CesiumJS 1.107. It will be removed in CesiumJS 1.110. Use Cesium3DTileset.cacheBytes instead."
+ );
+ defaultCacheBytes = options.maximumMemoryUsage * 1024 * 1024;
+ }
+ this._cacheBytes = defaultValue(options.cacheBytes, defaultCacheBytes);
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number.greaterThanOrEquals("cacheBytes", this._cacheBytes, 0);
+ //>>includeEnd('debug');
+
+ const maximumCacheOverflowBytes = defaultValue(
+ options.maximumCacheOverflowBytes,
+ 512 * 1024 * 1024
+ );
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number.greaterThanOrEquals(
+ "maximumCacheOverflowBytes",
+ maximumCacheOverflowBytes,
+ 0
+ );
+ //>>includeEnd('debug');
+ this._maximumCacheOverflowBytes = maximumCacheOverflowBytes;
this._styleEngine = new Cesium3DTileStyleEngine();
this._styleApplied = false;
@@ -590,7 +618,7 @@ function Cesium3DTileset(options) {
* console.log('A tile was unloaded from the cache.');
* });
*
- * @see Cesium3DTileset#maximumMemoryUsage
+ * @see Cesium3DTileset#cacheBytes
* @see Cesium3DTileset#trimLoadedTiles
*/
this.tileUnload = new Event();
@@ -1516,6 +1544,7 @@ Object.defineProperties(Cesium3DTileset.prototype, {
//>>includeEnd('debug');
this._maximumScreenSpaceError = value;
+ this._memoryAdjustedScreenSpaceError = value;
},
},
@@ -1545,17 +1574,122 @@ Object.defineProperties(Cesium3DTileset.prototype, {
*
* @exception {DeveloperError} maximumMemoryUsage
must be greater than or equal to zero.
* @see Cesium3DTileset#totalMemoryUsageInBytes
+ *
+ * @deprecated
*/
maximumMemoryUsage: {
get: function () {
+ deprecationWarning(
+ "Cesium3DTileset.maximumMemoryUsage",
+ "Cesium3DTileset.maximumMemoryUsage was deprecated in CesiumJS 1.107. It will be removed in CesiumJS 1.110. Use Cesium3DTileset.cacheBytes instead."
+ );
return this._maximumMemoryUsage;
},
set: function (value) {
+ deprecationWarning(
+ "Cesium3DTileset.maximumMemoryUsage",
+ "Cesium3DTileset.maximumMemoryUsage was deprecated in CesiumJS 1.107. It will be removed in CesiumJS 1.110. Use Cesium3DTileset.cacheBytes instead."
+ );
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("value", value, 0);
//>>includeEnd('debug');
this._maximumMemoryUsage = value;
+ this._cacheBytes = value * 1024 * 1024;
+ },
+ },
+
+ /**
+ * The amount of GPU memory (in bytes) used to cache tiles. This memory usage is estimated from
+ * geometry, textures, and batch table textures of loaded tiles. For point clouds, this value also
+ * includes per-point metadata.
+ *
+ * Tiles not in view are unloaded to enforce this. + *
+ *+ * If decreasing this value results in unloading tiles, the tiles are unloaded the next frame. + *
+ *
+ * If tiles sized more than cacheBytes
are needed to meet the
+ * desired screen space error, determined by {@link Cesium3DTileset#maximumScreenSpaceError},
+ * for the current view, then the memory usage of the tiles loaded will exceed
+ * cacheBytes
by up to maximumCacheOverflowBytes
.
+ * For example, if cacheBytes
is 500000, but 600000 bytes
+ * of tiles are needed to meet the screen space error, then 600000 bytes of tiles
+ * may be loaded (if maximumCacheOverflowBytes
is at least 100000).
+ * When these tiles go out of view, they will be unloaded.
+ *
cacheBytes
must be typeof 'number' and greater than or equal to 0
+ * @see Cesium3DTileset#totalMemoryUsageInBytes
+ */
+ cacheBytes: {
+ get: function () {
+ return this._cacheBytes;
+ },
+ set: function (value) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number.greaterThanOrEquals("value", value, 0);
+ //>>includeEnd('debug');
+
+ this._cacheBytes = value;
+ },
+ },
+
+ /**
+ * The maximum additional amount of GPU memory (in bytes) that will be used to cache tiles.
+ *
+ * If tiles sized more than cacheBytes
plus maximumCacheOverflowBytes
+ * are needed to meet the desired screen space error, determined by
+ * {@link Cesium3DTileset#maximumScreenSpaceError} for the current view, then
+ * {@link Cesium3DTileset#memoryAdjustedScreenSpaceError} will be adjusted
+ * until the tiles required to meet the adjusted screen space error use less
+ * than cacheBytes
plus maximumCacheOverflowBytes
.
+ *
maximumCacheOverflowBytes
must be typeof 'number' and greater than or equal to 0
+ * @see Cesium3DTileset#totalMemoryUsageInBytes
+ */
+ maximumCacheOverflowBytes: {
+ get: function () {
+ return this._maximumCacheOverflowBytes;
+ },
+ set: function (value) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number.greaterThanOrEquals("value", value, 0);
+ //>>includeEnd('debug');
+
+ this._maximumCacheOverflowBytes = value;
+ },
+ },
+
+ /**
+ * If loading the level of detail required by @{link Cesium3DTileset#maximumScreenSpaceError}
+ * results in the memory usage exceeding @{link Cesium3DTileset#cacheBytes}
+ * plus @{link Cesium3DTileset#maximumCacheOverflowBytes}, level of detail refinement
+ * will instead use this (larger) adjusted screen space error to achieve the
+ * best possible visual quality within the available memory
+ *
+ * @memberof Cesium3DTileset.prototype
+ *
+ * @type {number}
+ * @readonly
+ *
+ * @private
+ */
+ memoryAdjustedScreenSpaceError: {
+ get: function () {
+ return this._memoryAdjustedScreenSpaceError;
},
},
@@ -1665,7 +1799,7 @@ Object.defineProperties(Cesium3DTileset.prototype, {
* @type {number}
* @readonly
*
- * @see Cesium3DTileset#maximumMemoryUsage
+ * @see Cesium3DTileset#cacheBytes
*/
totalMemoryUsageInBytes: {
get: function () {
@@ -2524,7 +2658,7 @@ function requestContent(tileset, tile) {
tileset._requestedTilesInFlight.push(tile);
}
-function sortRequestByPriority(a, b) {
+function sortTilesByPriority(a, b) {
return a._priority - b._priority;
}
@@ -2627,7 +2761,7 @@ function cancelOutOfViewRequests(tileset, frameState) {
*/
function requestTiles(tileset) {
const requestedTiles = tileset._requestedTiles;
- requestedTiles.sort(sortRequestByPriority);
+ requestedTiles.sort(sortTilesByPriority);
for (let i = 0; i < requestedTiles.length; ++i) {
requestContent(tileset, requestedTiles[i]);
}
@@ -2694,10 +2828,18 @@ function filterProcessingQueue(tileset) {
function processTiles(tileset, frameState) {
filterProcessingQueue(tileset);
const tiles = tileset._processingQueue;
- const statistics = tileset._statistics;
- let tile;
+
+ const { cacheBytes, maximumCacheOverflowBytes, statistics } = tileset;
+ const cacheByteLimit = cacheBytes + maximumCacheOverflowBytes;
+
+ let memoryExceeded = false;
for (let i = 0; i < tiles.length; ++i) {
- tile = tiles[i];
+ if (tileset.totalMemoryUsageInBytes > cacheByteLimit) {
+ memoryExceeded = true;
+ break;
+ }
+
+ const tile = tiles[i];
try {
tile.process(tileset, frameState);
@@ -2710,6 +2852,37 @@ function processTiles(tileset, frameState) {
handleTileFailure(error, tileset, tile);
}
}
+
+ if (tileset.totalMemoryUsageInBytes < cacheBytes) {
+ decreaseScreenSpaceError(tileset);
+ } else if (memoryExceeded && tiles.length > 0) {
+ increaseScreenSpaceError(tileset);
+ }
+}
+
+function increaseScreenSpaceError(tileset) {
+ //>>includeStart('debug', pragmas.debug);
+ oneTimeWarning(
+ "increase-screenSpaceError",
+ `The tiles needed to meet maximumScreenSpaceError would use more memory than allocated for this tileset.
+ The tileset will be rendered with a larger screen space error (see memoryAdjustedScreenSpaceError).
+ Consider using larger values for cacheBytes and maximumCacheOverflowBytes.`
+ );
+ //>>includeEnd('debug');
+
+ tileset._memoryAdjustedScreenSpaceError *= 1.02;
+ const tiles = tileset._processingQueue;
+ for (let i = 0; i < tiles.length; ++i) {
+ tiles[i].updatePriority();
+ }
+ tiles.sort(sortTilesByPriority);
+}
+
+function decreaseScreenSpaceError(tileset) {
+ tileset._memoryAdjustedScreenSpaceError = Math.max(
+ tileset.memoryAdjustedScreenSpaceError / 1.02,
+ tileset.maximumScreenSpaceError
+ );
}
const scratchCartesian = new Cartesian3();
@@ -3057,7 +3230,7 @@ function destroyTile(tileset, tile) {
/**
* Unloads all tiles that weren't selected the previous frame. This can be used to
* explicitly manage the tile cache and reduce the total number of tiles loaded below
- * {@link Cesium3DTileset#maximumMemoryUsage}.
+ * {@link Cesium3DTileset#cacheBytes}.
* * Tile unloads occur at the next frame to keep all the WebGL delete calls * within the render loop. diff --git a/packages/engine/Source/Scene/Cesium3DTilesetBaseTraversal.js b/packages/engine/Source/Scene/Cesium3DTilesetBaseTraversal.js index a85ddcc4013c..df773afbcc11 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetBaseTraversal.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetBaseTraversal.js @@ -53,7 +53,7 @@ Cesium3DTilesetBaseTraversal.selectTiles = function (tileset, frameState) { if ( root.getScreenSpaceError(frameState, true) <= - tileset._maximumScreenSpaceError + tileset.memoryAdjustedScreenSpaceError ) { return; } diff --git a/packages/engine/Source/Scene/Cesium3DTilesetCache.js b/packages/engine/Source/Scene/Cesium3DTilesetCache.js index 6605a26f47dd..d4a8a5015159 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetCache.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetCache.js @@ -58,8 +58,6 @@ Cesium3DTilesetCache.prototype.unloadTiles = function ( const list = this._list; - const 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. // @@ -68,7 +66,7 @@ Cesium3DTilesetCache.prototype.unloadTiles = function ( let node = list.head; while ( node !== sentinel && - (tileset.totalMemoryUsageInBytes > maximumMemoryUsageInBytes || trimTiles) + (tileset.totalMemoryUsageInBytes > tileset.cacheBytes || trimTiles) ) { const tile = node.item; node = node.next; diff --git a/packages/engine/Source/Scene/Cesium3DTilesetSkipTraversal.js b/packages/engine/Source/Scene/Cesium3DTilesetSkipTraversal.js index aea34eee3fcb..81e18c41e78c 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetSkipTraversal.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetSkipTraversal.js @@ -61,7 +61,7 @@ Cesium3DTilesetSkipTraversal.selectTiles = function (tileset, frameState) { if ( root.getScreenSpaceError(frameState, true) <= - tileset._maximumScreenSpaceError + tileset.memoryAdjustedScreenSpaceError ) { return; } @@ -267,7 +267,10 @@ function executeTraversal(root, frameState) { const { tileset } = root; const baseScreenSpaceError = tileset.immediatelyLoadDesiredLevelOfDetail ? Number.MAX_VALUE - : Math.max(tileset.baseScreenSpaceError, tileset.maximumScreenSpaceError); + : Math.max( + tileset.baseScreenSpaceError, + tileset.memoryAdjustedScreenSpaceError + ); const { canTraverse, loadTile, diff --git a/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js b/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js index fc30a1eca829..12561ba541eb 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js @@ -64,7 +64,7 @@ Cesium3DTilesetTraversal.canTraverse = function (tile) { // Don't traverse if the subtree is expired because it will be destroyed return !tile.contentExpired; } - return tile._screenSpaceError > tile.tileset._maximumScreenSpaceError; + return tile._screenSpaceError > tile.tileset.memoryAdjustedScreenSpaceError; }; /** @@ -260,7 +260,7 @@ function meetsScreenSpaceErrorEarly(tile, frameState) { // Use parent's geometric error with child's box to see if the tile already meet the SSE return ( tile.getScreenSpaceError(frameState, true) <= - tileset._maximumScreenSpaceError + tileset.memoryAdjustedScreenSpaceError ); } diff --git a/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js b/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js index cb8e8af2cfd6..9abb174126d3 100644 --- a/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js +++ b/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js @@ -161,7 +161,7 @@ PointCloudStylingPipelineStage.process = function ( if (is3DTiles) { defaultPointSize = usesAddRefinement ? 5.0 - : content.tileset.maximumScreenSpaceError; + : content.tileset.memoryAdjustedScreenSpaceError; } vec4.x = defaultValue( pointCloudShading.maximumAttenuation, diff --git a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js index d644f3988eff..b526bfd8a322 100644 --- a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js +++ b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js @@ -38,6 +38,11 @@ async function createGooglePhotorealistic3DTileset(key, options) { options = defaultValue(options, {}); options.showCreditsOnScreen = true; + options.cacheBytes = defaultValue(options.cacheBytes, 1536 * 1024 * 1024); + options.maximumCacheOverflowBytes = defaultValue( + options.maximumCacheOverflowBytes, + 1024 * 1024 * 1024 + ); const resource = new Resource({ url: `${GoogleMaps.mapTilesApiEndpoint}3dtiles/root.json`, diff --git a/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js b/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js index d0535302cc31..ed51505b8d44 100644 --- a/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js +++ b/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js @@ -2493,7 +2493,7 @@ describe( ) { const spyUpdate = jasmine.createSpy("listener"); tileset.tileLoad.addEventListener(spyUpdate); - tileset.maximumMemoryUsage = 0; + tileset.cacheBytes = 0; viewRootOnly(); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then( function () { @@ -2539,7 +2539,7 @@ describe( } ); tileset.tileFailed.addEventListener(spyUpdate); - tileset.maximumMemoryUsage = 0; + tileset.cacheBytes = 0; viewRootOnly(); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset); }) @@ -3505,11 +3505,112 @@ describe( }); }); - it("Unloads cached tiles outside of the view frustum using maximumMemoryUsage", function () { + it("Unload all cached tiles not required to meet SSE using cacheBytes", function () { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( tileset ) { - tileset.maximumMemoryUsage = 0; + tileset.cacheBytes = 0; + + // Render parent and four children (using additive refinement) + viewAllTiles(); + scene.renderForSpecs(); + + const statistics = tileset._statistics; + expect(statistics.numberOfCommands).toEqual(5); + expect(statistics.numberOfTilesWithContentReady).toEqual(5); // Five loaded tiles + expect(tileset.totalMemoryUsageInBytes).toEqual(37200); // Specific to this tileset + + // Zoom out so only root tile is needed to meet SSE. This unloads + // the four children since the maximum memory usage is zero. + viewRootOnly(); + scene.renderForSpecs(); + + expect(statistics.numberOfCommands).toEqual(1); + expect(statistics.numberOfTilesWithContentReady).toEqual(1); + expect(tileset.totalMemoryUsageInBytes).toEqual(7440); // Specific to this tileset + + // Zoom back in so all four children are re-requested. + viewAllTiles(); + + return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then( + function () { + expect(statistics.numberOfCommands).toEqual(5); + expect(statistics.numberOfTilesWithContentReady).toEqual(5); // Five loaded tiles + expect(tileset.totalMemoryUsageInBytes).toEqual(37200); // Specific to this tileset + } + ); + }); + }); + + it("Unload some cached tiles not required to meet SSE using cacheBytes", function () { + return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( + tileset + ) { + tileset.cacheBytes = 0.025 * 1024 * 1024; // Just enough memory to allow 3 tiles to remain + // Render parent and four children (using additive refinement) + viewAllTiles(); + scene.renderForSpecs(); + + const statistics = tileset._statistics; + expect(statistics.numberOfCommands).toEqual(5); + expect(statistics.numberOfTilesWithContentReady).toEqual(5); // Five loaded tiles + + // Zoom out so only root tile is needed to meet SSE. This unloads + // two of the four children so three tiles are still loaded (the + // root and two children) since the maximum memory usage is sufficient. + viewRootOnly(); + scene.renderForSpecs(); + + expect(statistics.numberOfCommands).toEqual(1); + expect(statistics.numberOfTilesWithContentReady).toEqual(3); + + // Zoom back in so the two children are re-requested. + viewAllTiles(); + + return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then( + function () { + expect(statistics.numberOfCommands).toEqual(5); + expect(statistics.numberOfTilesWithContentReady).toEqual(5); // Five loaded tiles + } + ); + }); + }); + + it("Restrict tileset memory usage with maximumCacheOverflowBytes", function () { + return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( + tileset + ) { + tileset.cacheBytes = 0.025 * 1024 * 1024; // Just enough memory to allow 3 tiles to remain + tileset.maximumCacheOverflowBytes = 0; + expect(tileset.memoryAdjustedScreenSpaceError).toEqual(16); + + // Zoom out so only root tile is needed to meet SSE. + viewRootOnly(); + scene.renderForSpecs(); + const statistics = tileset._statistics; + expect(statistics.numberOfCommands).toEqual(1); + expect(statistics.numberOfTilesWithContentReady).toEqual(3); + + // Zoom back in and attempt to render all tiles + viewAllTiles(); + + return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then( + function () { + // Only 3 tiles should have been actually loaded + expect(statistics.numberOfCommands).toEqual(3); + expect(statistics.numberOfTilesWithContentReady).toEqual(3); // Three loaded tiles + // SSE should have been adjusted higher + expect(tileset.memoryAdjustedScreenSpaceError).toBeGreaterThan(16); + } + ); + }); + }); + + it("Unloads cached tiles outside of the view frustum using cacheBytes", function () { + return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( + tileset + ) { + tileset.cacheBytes = 0; scene.renderForSpecs(); const statistics = tileset._statistics; @@ -3535,13 +3636,13 @@ describe( }); }); - it("Unloads cached tiles in a tileset with external tileset JSON file using maximumMemoryUsage", function () { + it("Unloads cached tiles in a tileset with external tileset JSON file using cacheBytes", function () { return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then( function (tileset) { const statistics = tileset._statistics; const cacheList = tileset._cache._list; - tileset.maximumMemoryUsage = 0.02; + tileset.cacheBytes = 0.02 * 1024 * 1024; scene.renderForSpecs(); expect(statistics.numberOfCommands).toEqual(5); @@ -3572,12 +3673,12 @@ describe( ); }); - it("Unloads cached tiles in a tileset with empty tiles using maximumMemoryUsage", function () { + it("Unloads cached tiles in a tileset with empty tiles using cacheBytes", function () { return Cesium3DTilesTester.loadTileset(scene, tilesetEmptyRootUrl).then( function (tileset) { const statistics = tileset._statistics; - tileset.maximumMemoryUsage = 0.02; + tileset.cacheBytes = 0.02 * 1024 * 1024; scene.renderForSpecs(); expect(statistics.numberOfCommands).toEqual(4); @@ -3603,7 +3704,7 @@ describe( ); }); - it("Unload cached tiles when a tileset uses replacement refinement using maximumMemoryUsage", function () { + it("Unload cached tiles when a tileset uses replacement refinement using cacheBytes", function () { // No children have content, but all grandchildren have content // // C @@ -3614,7 +3715,7 @@ describe( scene, tilesetReplacement1Url ).then(function (tileset) { - tileset.maximumMemoryUsage = 0; // Only root needs to be visible + tileset.cacheBytes = 0; // Only root needs to be visible // Render parent and four children (using additive refinement) viewAllTiles(); @@ -3648,7 +3749,7 @@ describe( return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( tileset ) { - tileset.maximumMemoryUsage = 0.05; + tileset.cacheBytes = 0.05 * 1024 * 1024; // Render parent and four children (using additive refinement) viewAllTiles(); @@ -3678,7 +3779,7 @@ describe( return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function ( tileset ) { - tileset.maximumMemoryUsage = 0; + tileset.cacheBytes = 0; // Render parent and four children (using additive refinement) viewAllTiles(); @@ -3716,6 +3817,20 @@ describe( }).toThrowDeveloperError(); }); + it("cacheBytes throws when negative", async function () { + const tileset = await Cesium3DTileset.fromUrl(tilesetUrl, options); + expect(function () { + tileset.cacheBytes = -1; + }).toThrowDeveloperError(); + }); + + it("maximumCacheOverflowBytes throws when negative", async function () { + const tileset = await Cesium3DTileset.fromUrl(tilesetUrl, options); + expect(function () { + tileset.maximumCacheOverflowBytes = -1; + }).toThrowDeveloperError(); + }); + it("maximumScreenSpaceError throws when negative", async function () { const tileset = await Cesium3DTileset.fromUrl(tilesetUrl, options); expect(function () { @@ -4856,7 +4971,7 @@ describe( const cartographics = [centerCartographic]; return Cesium3DTilesTester.loadTileset(scene, tilesetUniform).then( function (tileset) { - tileset.maximumMemoryUsage = 0; + tileset.cacheBytes = 0; return sampleHeightMostDetailed(cartographics).then(function () { expect(centerCartographic.height).toEqualEpsilon( 2.47, diff --git a/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js b/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js index 38639d9da85e..d2fb924c6212 100644 --- a/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js +++ b/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js @@ -764,6 +764,7 @@ describe( }, tileset: { maximumScreenSpaceError: 16, + memoryAdjustedScreenSpaceError: 16, }, }, });