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. + *

+ * + * @memberof Cesium3DTileset.prototype + * + * @type {number} + * @default 536870912 + * + * @exception {DeveloperError} 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. + *

+ * + * @memberof Cesium3DTileset.prototype + * + * @type {number} + * @default 536870912 + * + * @exception {DeveloperError} 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, }, }, });