Skip to content

Commit

Permalink
Merge pull request #9313 from CesiumGS/terrainDataThrottleControl
Browse files Browse the repository at this point in the history
Added throttle option to TerrainData.createMesh
  • Loading branch information
lilleyse authored Feb 28, 2021
2 parents c5abf0d + c0c23e3 commit 52c3e87
Show file tree
Hide file tree
Showing 20 changed files with 486 additions and 240 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Removed `EasingFunction.QUADRACTIC_IN`, which was deprecated in CesiumJS 1.77. Use `EasingFunction.QUADRATIC_IN`.
- Removed `EasingFunction.QUADRACTIC_OUT`, which was deprecated in CesiumJS 1.77. Use `EasingFunction.QUADRATIC_OUT`.
- Removed `EasingFunction.QUADRACTIC_IN_OUT`, which was deprecated in CesiumJS 1.77. Use `EasingFunction.QUADRATIC_IN_OUT`.
- Changed `TaskProcessor.maximumActiveTasks` constructor option to be infinity by default. [#9313](https://github.com/CesiumGS/cesium/pull/9313)

##### Fixes :wrench:

Expand Down
5 changes: 1 addition & 4 deletions Source/Core/GoogleEarthEnterpriseMetadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,7 @@ GoogleEarthEnterpriseMetadata.prototype.isValid = function (quadKey) {
return valid;
};

var taskProcessor = new TaskProcessor(
"decodeGoogleEarthEnterprisePacket",
Number.POSITIVE_INFINITY
);
var taskProcessor = new TaskProcessor("decodeGoogleEarthEnterprisePacket");

/**
* Retrieves a Google Earth Enterprise quadtree packet.
Expand Down
57 changes: 36 additions & 21 deletions Source/Core/GoogleEarthEnterpriseTerrainData.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import OrientedBoundingBox from "./OrientedBoundingBox.js";
import QuantizedMeshTerrainData from "./QuantizedMeshTerrainData.js";
import Rectangle from "./Rectangle.js";
import TaskProcessor from "./TaskProcessor.js";
import TerrainData from "./TerrainData.js";
import TerrainEncoding from "./TerrainEncoding.js";
import TerrainMesh from "./TerrainMesh.js";

Expand Down Expand Up @@ -116,8 +117,11 @@ Object.defineProperties(GoogleEarthEnterpriseTerrainData.prototype, {
},
});

var taskProcessor = new TaskProcessor(
"createVerticesFromGoogleEarthEnterpriseBuffer"
var createMeshTaskName = "createVerticesFromGoogleEarthEnterpriseBuffer";
var createMeshTaskProcessorNoThrottle = new TaskProcessor(createMeshTaskName);
var createMeshTaskProcessorThrottle = new TaskProcessor(
createMeshTaskName,
TerrainData.maximumAsynchronousTasks
);

var nativeRectangleScratch = new Rectangle();
Expand All @@ -128,33 +132,37 @@ var rectangleScratch = new Rectangle();
*
* @private
*
* @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} x The X coordinate of the tile for which to create the terrain data.
* @param {Number} y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} level The level of the tile for which to create the terrain data.
* @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Object} options Object with the following properties:
* @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} options.x The X coordinate of the tile for which to create the terrain data.
* @param {Number} options.y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} options.level The level of the tile for which to create the terrain data.
* @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Boolean} [options.throttle=true] If true, indicates that this operation will need to be retried if too many asynchronous mesh creations are already in progress.
* @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
* asynchronous mesh creations are already in progress and the operation should
* be retried later.
*/
GoogleEarthEnterpriseTerrainData.prototype.createMesh = function (
tilingScheme,
x,
y,
level,
exaggeration
) {
GoogleEarthEnterpriseTerrainData.prototype.createMesh = function (options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);

//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("tilingScheme", tilingScheme);
Check.typeOf.number("x", x);
Check.typeOf.number("y", y);
Check.typeOf.number("level", level);
Check.typeOf.object("options.tilingScheme", options.tilingScheme);
Check.typeOf.number("options.x", options.x);
Check.typeOf.number("options.y", options.y);
Check.typeOf.number("options.level", options.level);
//>>includeEnd('debug');

var tilingScheme = options.tilingScheme;
var x = options.x;
var y = options.y;
var level = options.level;
var exaggeration = defaultValue(options.exaggeration, 1.0);
var throttle = defaultValue(options.throttle, true);

var ellipsoid = tilingScheme.ellipsoid;
tilingScheme.tileXYToNativeRectangle(x, y, level, nativeRectangleScratch);
tilingScheme.tileXYToRectangle(x, y, level, rectangleScratch);
exaggeration = defaultValue(exaggeration, 1.0);

// Compute the center of the tile for RTC rendering.
var center = ellipsoid.cartographicToCartesian(
Expand All @@ -165,7 +173,11 @@ GoogleEarthEnterpriseTerrainData.prototype.createMesh = function (
var thisLevelMaxError = levelZeroMaxError / (1 << level);
this._skirtHeight = Math.min(thisLevelMaxError * 8.0, 1000.0);

var verticesPromise = taskProcessor.scheduleTask({
var createMeshTaskProcessor = throttle
? createMeshTaskProcessorThrottle
: createMeshTaskProcessorNoThrottle;

var verticesPromise = createMeshTaskProcessor.scheduleTask({
buffer: this._buffer,
nativeRectangle: nativeRectangleScratch,
rectangle: rectangleScratch,
Expand Down Expand Up @@ -249,7 +261,10 @@ GoogleEarthEnterpriseTerrainData.prototype.interpolateHeight = function (
return interpolateMeshHeight(this, u, v);
};

var upsampleTaskProcessor = new TaskProcessor("upsampleQuantizedTerrainMesh");
var upsampleTaskProcessor = new TaskProcessor(
"upsampleQuantizedTerrainMesh",
TerrainData.maximumAsynchronousTasks
);

/**
* Upsamples this terrain data for use by a descendant tile. The resulting instance will contain a subset of the
Expand Down
5 changes: 1 addition & 4 deletions Source/Core/GoogleEarthEnterpriseTerrainProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,7 @@ Object.defineProperties(GoogleEarthEnterpriseTerrainProvider.prototype, {
},
});

var taskProcessor = new TaskProcessor(
"decodeGoogleEarthEnterprisePacket",
Number.POSITIVE_INFINITY
);
var taskProcessor = new TaskProcessor("decodeGoogleEarthEnterprisePacket");

// If the tile has its own terrain, then you can just use its child bitmask. If it was requested using it's parent
// then you need to check all of its children to see if they have terrain.
Expand Down
99 changes: 52 additions & 47 deletions Source/Core/HeightmapTerrainData.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import when from "../ThirdParty/when.js";
import BoundingSphere from "./BoundingSphere.js";
import Cartesian3 from "./Cartesian3.js";
import Check from "./Check.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";
Expand All @@ -11,6 +12,7 @@ import CesiumMath from "./Math.js";
import OrientedBoundingBox from "./OrientedBoundingBox.js";
import Rectangle from "./Rectangle.js";
import TaskProcessor from "./TaskProcessor.js";
import TerrainData from "./TerrainData.js";
import TerrainEncoding from "./TerrainEncoding.js";
import TerrainMesh from "./TerrainMesh.js";
import TerrainProvider from "./TerrainProvider.js";
Expand Down Expand Up @@ -182,48 +184,49 @@ Object.defineProperties(HeightmapTerrainData.prototype, {
},
});

var taskProcessor = new TaskProcessor("createVerticesFromHeightmap");
var createMeshTaskName = "createVerticesFromHeightmap";
var createMeshTaskProcessorNoThrottle = new TaskProcessor(createMeshTaskName);
var createMeshTaskProcessorThrottle = new TaskProcessor(
createMeshTaskName,
TerrainData.maximumAsynchronousTasks
);

/**
* Creates a {@link TerrainMesh} from this terrain data.
*
* @private
*
* @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} x The X coordinate of the tile for which to create the terrain data.
* @param {Number} y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} level The level of the tile for which to create the terrain data.
* @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Object} options Object with the following properties:
* @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} options.x The X coordinate of the tile for which to create the terrain data.
* @param {Number} options.y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} options.level The level of the tile for which to create the terrain data.
* @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Boolean} [options.throttle=true] If true, indicates that this operation will need to be retried if too many asynchronous mesh creations are already in progress.
* @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
* asynchronous mesh creations are already in progress and the operation should
* be retried later.
*/
HeightmapTerrainData.prototype.createMesh = function (
tilingScheme,
x,
y,
level,
exaggeration
) {
HeightmapTerrainData.prototype.createMesh = function (options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);

//>>includeStart('debug', pragmas.debug);
if (!defined(tilingScheme)) {
throw new DeveloperError("tilingScheme is required.");
}
if (!defined(x)) {
throw new DeveloperError("x is required.");
}
if (!defined(y)) {
throw new DeveloperError("y is required.");
}
if (!defined(level)) {
throw new DeveloperError("level is required.");
}
Check.typeOf.object("options.tilingScheme", options.tilingScheme);
Check.typeOf.number("options.x", options.x);
Check.typeOf.number("options.y", options.y);
Check.typeOf.number("options.level", options.level);
//>>includeEnd('debug');

var tilingScheme = options.tilingScheme;
var x = options.x;
var y = options.y;
var level = options.level;
var exaggeration = defaultValue(options.exaggeration, 1.0);
var throttle = defaultValue(options.throttle, true);

var ellipsoid = tilingScheme.ellipsoid;
var nativeRectangle = tilingScheme.tileXYToNativeRectangle(x, y, level);
var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
exaggeration = defaultValue(exaggeration, 1.0);

// Compute the center of the tile for RTC rendering.
var center = ellipsoid.cartographicToCartesian(Rectangle.center(rectangle));
Expand All @@ -238,7 +241,11 @@ HeightmapTerrainData.prototype.createMesh = function (
var thisLevelMaxError = levelZeroMaxError / (1 << level);
this._skirtHeight = Math.min(thisLevelMaxError * 4.0, 1000.0);

var verticesPromise = taskProcessor.scheduleTask({
var createMeshTaskProcessor = throttle
? createMeshTaskProcessorThrottle
: createMeshTaskProcessorNoThrottle;

var verticesPromise = createMeshTaskProcessor.scheduleTask({
heightmap: this._buffer,
structure: structure,
includeWebMercatorT: true,
Expand Down Expand Up @@ -305,34 +312,32 @@ HeightmapTerrainData.prototype.createMesh = function (
};

/**
* @param {Object} options Object with the following properties:
* @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} options.x The X coordinate of the tile for which to create the terrain data.
* @param {Number} options.y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} options.level The level of the tile for which to create the terrain data.
* @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
*
* @private
*/
HeightmapTerrainData.prototype._createMeshSync = function (
tilingScheme,
x,
y,
level,
exaggeration
) {
HeightmapTerrainData.prototype._createMeshSync = function (options) {
//>>includeStart('debug', pragmas.debug);
if (!defined(tilingScheme)) {
throw new DeveloperError("tilingScheme is required.");
}
if (!defined(x)) {
throw new DeveloperError("x is required.");
}
if (!defined(y)) {
throw new DeveloperError("y is required.");
}
if (!defined(level)) {
throw new DeveloperError("level is required.");
}
Check.typeOf.object("options.tilingScheme", options.tilingScheme);
Check.typeOf.number("options.x", options.x);
Check.typeOf.number("options.y", options.y);
Check.typeOf.number("options.level", options.level);
//>>includeEnd('debug');

var tilingScheme = options.tilingScheme;
var x = options.x;
var y = options.y;
var level = options.level;
var exaggeration = defaultValue(options.exaggeration, 1.0);

var ellipsoid = tilingScheme.ellipsoid;
var nativeRectangle = tilingScheme.tileXYToNativeRectangle(x, y, level);
var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
exaggeration = defaultValue(exaggeration, 1.0);

// Compute the center of the tile for RTC rendering.
var center = ellipsoid.cartographicToCartesian(Rectangle.center(rectangle));
Expand Down
64 changes: 36 additions & 28 deletions Source/Core/QuantizedMeshTerrainData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import when from "../ThirdParty/when.js";
import BoundingSphere from "./BoundingSphere.js";
import Cartesian2 from "./Cartesian2.js";
import Cartesian3 from "./Cartesian3.js";
import Check from "./Check.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";
Expand All @@ -10,6 +11,7 @@ import Intersections2D from "./Intersections2D.js";
import CesiumMath from "./Math.js";
import OrientedBoundingBox from "./OrientedBoundingBox.js";
import TaskProcessor from "./TaskProcessor.js";
import TerrainData from "./TerrainData.js";
import TerrainEncoding from "./TerrainEncoding.js";
import TerrainMesh from "./TerrainMesh.js";

Expand Down Expand Up @@ -262,49 +264,52 @@ function sortIndicesIfNecessary(indices, sortFunction, vertexCount) {
return indices;
}

var createMeshTaskProcessor = new TaskProcessor(
"createVerticesFromQuantizedTerrainMesh"
var createMeshTaskName = "createVerticesFromQuantizedTerrainMesh";
var createMeshTaskProcessorNoThrottle = new TaskProcessor(createMeshTaskName);
var createMeshTaskProcessorThrottle = new TaskProcessor(
createMeshTaskName,
TerrainData.maximumAsynchronousTasks
);

/**
* Creates a {@link TerrainMesh} from this terrain data.
*
* @private
*
* @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} x The X coordinate of the tile for which to create the terrain data.
* @param {Number} y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} level The level of the tile for which to create the terrain data.
* @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Object} options Object with the following properties:
* @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs.
* @param {Number} options.x The X coordinate of the tile for which to create the terrain data.
* @param {Number} options.y The Y coordinate of the tile for which to create the terrain data.
* @param {Number} options.level The level of the tile for which to create the terrain data.
* @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
* @param {Boolean} [options.throttle=true] If true, indicates that this operation will need to be retried if too many asynchronous mesh creations are already in progress.
* @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
* asynchronous mesh creations are already in progress and the operation should
* be retried later.
*/
QuantizedMeshTerrainData.prototype.createMesh = function (
tilingScheme,
x,
y,
level,
exaggeration
) {
QuantizedMeshTerrainData.prototype.createMesh = function (options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);

//>>includeStart('debug', pragmas.debug);
if (!defined(tilingScheme)) {
throw new DeveloperError("tilingScheme is required.");
}
if (!defined(x)) {
throw new DeveloperError("x is required.");
}
if (!defined(y)) {
throw new DeveloperError("y is required.");
}
if (!defined(level)) {
throw new DeveloperError("level is required.");
}
Check.typeOf.object("options.tilingScheme", options.tilingScheme);
Check.typeOf.number("options.x", options.x);
Check.typeOf.number("options.y", options.y);
Check.typeOf.number("options.level", options.level);
//>>includeEnd('debug');

var tilingScheme = options.tilingScheme;
var x = options.x;
var y = options.y;
var level = options.level;
var exaggeration = defaultValue(options.exaggeration, 1.0);
var throttle = defaultValue(options.throttle, true);

var ellipsoid = tilingScheme.ellipsoid;
var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
exaggeration = defaultValue(exaggeration, 1.0);

var createMeshTaskProcessor = throttle
? createMeshTaskProcessorThrottle
: createMeshTaskProcessorNoThrottle;

var verticesPromise = createMeshTaskProcessor.scheduleTask({
minimumHeight: this._minimumHeight,
Expand Down Expand Up @@ -405,7 +410,10 @@ QuantizedMeshTerrainData.prototype.createMesh = function (
});
};

var upsampleTaskProcessor = new TaskProcessor("upsampleQuantizedTerrainMesh");
var upsampleTaskProcessor = new TaskProcessor(
"upsampleQuantizedTerrainMesh",
TerrainData.maximumAsynchronousTasks
);

/**
* Upsamples this terrain data for use by a descendant tile. The resulting instance will contain a subset of the
Expand Down
Loading

0 comments on commit 52c3e87

Please sign in to comment.