Merge pull request #498 from twpayne/boost-tile-loading

Boost tile loading
This commit is contained in:
Tom Payne
2013-04-08 03:54:53 -07:00
2 changed files with 44 additions and 41 deletions
+25 -23
View File
@@ -83,18 +83,6 @@ ol.ENABLE_DOM = true;
ol.ENABLE_WEBGL = true; ol.ENABLE_WEBGL = true;
/**
* @define {number} Maximum number of simultaneously loading tiles.
*/
ol.MAXIMUM_TILES_LOADING = 8;
/**
* @define {number} Maximum new tile loads per frame.
*/
ol.MAXIMUM_NEW_TILE_LOADS_PER_FRAME = 2;
/** /**
* @enum {string} * @enum {string}
*/ */
@@ -304,7 +292,6 @@ ol.Map = function(options) {
* @type {ol.TileQueue} * @type {ol.TileQueue}
*/ */
this.tileQueue_ = new ol.TileQueue( this.tileQueue_ = new ol.TileQueue(
ol.MAXIMUM_TILES_LOADING,
goog.bind(this.getTilePriority, this), goog.bind(this.getTilePriority, this),
goog.bind(this.handleTileChange_, this)); goog.bind(this.handleTileChange_, this));
@@ -587,23 +574,38 @@ ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
*/ */
ol.Map.prototype.handlePostRender = function() { ol.Map.prototype.handlePostRender = function() {
// Limit the number of tile loads if animating or interacting.
var limit = (1 << 30) - 1; // a large enough integer
var frameState = this.frameState_; var frameState = this.frameState_;
if (!goog.isNull(frameState)) {
var hints = frameState.viewHints; // Manage the tile queue
if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) { // Image loads are expensive and a limited resource, so try to use them
limit = ol.MAXIMUM_NEW_TILE_LOADS_PER_FRAME; // efficiently:
// * When the view is static we allow a large number of parallel tile loads
// to complete the frame as quickly as possible.
// * When animating or interacting, image loads can cause janks, so we reduce
// the maximum number of loads per frame and limit the number of parallel
// tile loads to remain reactive to view changes and to reduce the chance of
// loading tiles that will quickly disappear from view.
var tileQueue = this.tileQueue_;
if (!tileQueue.isEmpty()) {
var maxTotalLoading = 16;
var maxNewLoads = maxTotalLoading;
if (!goog.isNull(frameState)) {
var hints = frameState.viewHints;
if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) {
maxTotalLoading = 8;
maxNewLoads = 2;
}
}
if (tileQueue.getTilesLoading() < maxTotalLoading) {
tileQueue.reprioritize(); // FIXME only call if view has changed
tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);
} }
} }
this.tileQueue_.reprioritize(); // FIXME only call if needed
this.tileQueue_.loadMoreTiles(limit);
var postRenderFunctions = this.postRenderFunctions_; var postRenderFunctions = this.postRenderFunctions_;
var i; var i;
for (i = 0; i < postRenderFunctions.length; ++i) { for (i = 0; i < postRenderFunctions.length; ++i) {
postRenderFunctions[i](this, this.frameState_); postRenderFunctions[i](this, frameState);
} }
postRenderFunctions.length = 0; postRenderFunctions.length = 0;
}; };
+19 -18
View File
@@ -1,6 +1,7 @@
goog.provide('ol.TilePriorityFunction'); goog.provide('ol.TilePriorityFunction');
goog.provide('ol.TileQueue'); goog.provide('ol.TileQueue');
goog.require('goog.asserts');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('ol.Coordinate'); goog.require('ol.Coordinate');
@@ -18,15 +19,12 @@ ol.TilePriorityFunction;
/** /**
* @constructor * @constructor
* @extends {ol.structs.PriorityQueue} * @extends {ol.structs.PriorityQueue}
* @param {number} maxTilesLoading Maximum number of simultaneously loading
* tiles.
* @param {ol.TilePriorityFunction} tilePriorityFunction * @param {ol.TilePriorityFunction} tilePriorityFunction
* Tile priority function. * Tile priority function.
* @param {Function} tileChangeCallback * @param {Function} tileChangeCallback
* Function called on each tile change event. * Function called on each tile change event.
*/ */
ol.TileQueue = ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {
function(maxTilesLoading, tilePriorityFunction, tileChangeCallback) {
goog.base( goog.base(
this, this,
@@ -51,12 +49,6 @@ ol.TileQueue =
*/ */
this.tileChangeCallback_ = tileChangeCallback; this.tileChangeCallback_ = tileChangeCallback;
/**
* @private
* @type {number}
*/
this.maxTilesLoading_ = maxTilesLoading;
/** /**
* @private * @private
* @type {number} * @type {number}
@@ -67,6 +59,14 @@ ol.TileQueue =
goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); goog.inherits(ol.TileQueue, ol.structs.PriorityQueue);
/**
* @return {number} Number of tiles loading.
*/
ol.TileQueue.prototype.getTilesLoading = function() {
return this.tilesLoading_;
};
/** /**
* @protected * @protected
*/ */
@@ -77,18 +77,19 @@ ol.TileQueue.prototype.handleTileChange = function() {
/** /**
* @param {number} limit Maximum number of new tiles to load. * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
* @param {number} maxNewLoads Maximum number of new tiles to load.
*/ */
ol.TileQueue.prototype.loadMoreTiles = function(limit) { ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
var tile; var newLoads = Math.min(
while (limit > 0 && maxTotalLoading - this.getTilesLoading(), maxNewLoads, this.getCount());
!this.isEmpty() && goog.asserts.assert(newLoads > 0);
this.tilesLoading_ < this.maxTilesLoading_) { var i, tile;
for (i = 0; i < newLoads; ++i) {
tile = /** @type {ol.Tile} */ (this.dequeue()[0]); tile = /** @type {ol.Tile} */ (this.dequeue()[0]);
goog.events.listenOnce(tile, goog.events.EventType.CHANGE, goog.events.listenOnce(tile, goog.events.EventType.CHANGE,
this.handleTileChange, false, this); this.handleTileChange, false, this);
tile.load(); tile.load();
++this.tilesLoading_;
--limit;
} }
this.tilesLoading_ += newLoads;
}; };