From da6f4cc764001b69989d56c7f7b2f223f2563835 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sun, 7 Apr 2013 18:10:19 +0200 Subject: [PATCH 1/6] Make maximum number of tiles loading a parameter to loadMoreTiles --- src/ol/map.js | 3 +-- src/ol/tilequeue.js | 16 ++++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index eb16d3c95b..598c5dd276 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -304,7 +304,6 @@ ol.Map = function(options) { * @type {ol.TileQueue} */ this.tileQueue_ = new ol.TileQueue( - ol.MAXIMUM_TILES_LOADING, goog.bind(this.getTilePriority, this), goog.bind(this.handleTileChange_, this)); @@ -598,7 +597,7 @@ ol.Map.prototype.handlePostRender = function() { } this.tileQueue_.reprioritize(); // FIXME only call if needed - this.tileQueue_.loadMoreTiles(limit); + this.tileQueue_.loadMoreTiles(limit, ol.MAXIMUM_TILES_LOADING); var postRenderFunctions = this.postRenderFunctions_; var i; diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index 94274ca6d7..672d658e9e 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -18,15 +18,12 @@ ol.TilePriorityFunction; /** * @constructor * @extends {ol.structs.PriorityQueue} - * @param {number} maxTilesLoading Maximum number of simultaneously loading - * tiles. * @param {ol.TilePriorityFunction} tilePriorityFunction * Tile priority function. * @param {Function} tileChangeCallback * Function called on each tile change event. */ -ol.TileQueue = - function(maxTilesLoading, tilePriorityFunction, tileChangeCallback) { +ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { goog.base( this, @@ -51,12 +48,6 @@ ol.TileQueue = */ this.tileChangeCallback_ = tileChangeCallback; - /** - * @private - * @type {number} - */ - this.maxTilesLoading_ = maxTilesLoading; - /** * @private * @type {number} @@ -78,12 +69,13 @@ ol.TileQueue.prototype.handleTileChange = function() { /** * @param {number} limit Maximum number of new tiles to load. + * @param {number} maxTilesLoading Maximum number tiles to load simultaneously. */ -ol.TileQueue.prototype.loadMoreTiles = function(limit) { +ol.TileQueue.prototype.loadMoreTiles = function(limit, maxTilesLoading) { var tile; while (limit > 0 && !this.isEmpty() && - this.tilesLoading_ < this.maxTilesLoading_) { + this.tilesLoading_ < maxTilesLoading) { tile = /** @type {ol.Tile} */ (this.dequeue()[0]); goog.events.listenOnce(tile, goog.events.EventType.CHANGE, this.handleTileChange, false, this); From b93283e8f397f0ee09b3df8d51e2bfde38d9f728 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sun, 7 Apr 2013 18:25:19 +0200 Subject: [PATCH 2/6] Boost number of loading tiles when not animating or interacting --- src/ol/map.js | 20 +++++--------------- src/ol/tilequeue.js | 12 ++++++------ 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index 598c5dd276..c7ccdd4191 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -83,18 +83,6 @@ ol.ENABLE_DOM = 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} */ @@ -587,17 +575,19 @@ ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { 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 maxTotalLoading = 16; + var maxNewLoads = maxTotalLoading; var frameState = this.frameState_; if (!goog.isNull(frameState)) { var hints = frameState.viewHints; if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) { - limit = ol.MAXIMUM_NEW_TILE_LOADS_PER_FRAME; + maxTotalLoading = 8; + maxNewLoads = 2; } } this.tileQueue_.reprioritize(); // FIXME only call if needed - this.tileQueue_.loadMoreTiles(limit, ol.MAXIMUM_TILES_LOADING); + this.tileQueue_.loadMoreTiles(maxTotalLoading, maxNewLoads); var postRenderFunctions = this.postRenderFunctions_; var i; diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index 672d658e9e..b996e69392 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -68,19 +68,19 @@ ol.TileQueue.prototype.handleTileChange = function() { /** - * @param {number} limit Maximum number of new tiles to load. - * @param {number} maxTilesLoading Maximum number tiles to load simultaneously. + * @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, maxTilesLoading) { +ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { var tile; - while (limit > 0 && + while (maxNewLoads > 0 && !this.isEmpty() && - this.tilesLoading_ < maxTilesLoading) { + this.tilesLoading_ < maxTotalLoading) { tile = /** @type {ol.Tile} */ (this.dequeue()[0]); goog.events.listenOnce(tile, goog.events.EventType.CHANGE, this.handleTileChange, false, this); tile.load(); ++this.tilesLoading_; - --limit; + --maxNewLoads; } }; From 5b133d40d9404e379a70f4a7966d801930ee8915 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sun, 7 Apr 2013 18:31:56 +0200 Subject: [PATCH 3/6] Only reprioritize tile queue when more tiles will be loaded --- src/ol/map.js | 6 ++++-- src/ol/tilequeue.js | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index c7ccdd4191..48fdf6b895 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -586,8 +586,10 @@ ol.Map.prototype.handlePostRender = function() { } } - this.tileQueue_.reprioritize(); // FIXME only call if needed - this.tileQueue_.loadMoreTiles(maxTotalLoading, maxNewLoads); + if (this.tileQueue_.getTilesLoading() < maxTotalLoading) { + this.tileQueue_.reprioritize(); // FIXME only call if view has changed + this.tileQueue_.loadMoreTiles(maxTotalLoading, maxNewLoads); + } var postRenderFunctions = this.postRenderFunctions_; var i; diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index b996e69392..a2989b3f42 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -58,6 +58,14 @@ ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); +/** + * @return {number} Number of tiles loading. + */ +ol.TileQueue.prototype.getTilesLoading = function() { + return this.tilesLoading_; +}; + + /** * @protected */ From 60a913aef349c03d7a8f8473e3f1c972a47cb14f Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sun, 7 Apr 2013 19:12:35 +0200 Subject: [PATCH 4/6] Compute number of new tiles to load exactly --- src/ol/tilequeue.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index a2989b3f42..37265f7008 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -80,15 +80,16 @@ ol.TileQueue.prototype.handleTileChange = function() { * @param {number} maxNewLoads Maximum number of new tiles to load. */ ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { - var tile; - while (maxNewLoads > 0 && - !this.isEmpty() && - this.tilesLoading_ < maxTotalLoading) { - tile = /** @type {ol.Tile} */ (this.dequeue()[0]); - goog.events.listenOnce(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - tile.load(); - ++this.tilesLoading_; - --maxNewLoads; + var newLoads = Math.min( + maxTotalLoading - this.getTilesLoading(), maxNewLoads, this.getCount()); + if (newLoads > 0) { + var i, tile; + for (i = 0; i < newLoads; ++i) { + tile = /** @type {ol.Tile} */ (this.dequeue()[0]); + goog.events.listenOnce(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); + tile.load(); + } + this.tilesLoading_ += newLoads; } }; From 6f49cb8abe43ba7dea862c9b37ea29a604b9a595 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 8 Apr 2013 12:12:25 +0200 Subject: [PATCH 5/6] Assert that loadMoreTiles is only called when more tiles will be loaded --- src/ol/tilequeue.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index 37265f7008..197567c14c 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -1,6 +1,7 @@ goog.provide('ol.TilePriorityFunction'); goog.provide('ol.TileQueue'); +goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('ol.Coordinate'); @@ -82,14 +83,13 @@ ol.TileQueue.prototype.handleTileChange = function() { ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { var newLoads = Math.min( maxTotalLoading - this.getTilesLoading(), maxNewLoads, this.getCount()); - if (newLoads > 0) { - var i, tile; - for (i = 0; i < newLoads; ++i) { - tile = /** @type {ol.Tile} */ (this.dequeue()[0]); - goog.events.listenOnce(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - tile.load(); - } - this.tilesLoading_ += newLoads; + goog.asserts.assert(newLoads > 0); + var i, tile; + for (i = 0; i < newLoads; ++i) { + tile = /** @type {ol.Tile} */ (this.dequeue()[0]); + goog.events.listenOnce(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); + tile.load(); } + this.tilesLoading_ += newLoads; }; From 01440b484bfd0298b59ef73787ba886a72cda1d5 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 8 Apr 2013 12:14:33 +0200 Subject: [PATCH 6/6] Only manage the tile queue if it is not empty and improve comment --- src/ol/map.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index 48fdf6b895..f78e50f861 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -574,27 +574,38 @@ ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { */ ol.Map.prototype.handlePostRender = function() { - // Limit the number of tile loads if animating or interacting. - var maxTotalLoading = 16; - var maxNewLoads = maxTotalLoading; var frameState = this.frameState_; - if (!goog.isNull(frameState)) { - var hints = frameState.viewHints; - if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) { - maxTotalLoading = 8; - maxNewLoads = 2; - } - } - if (this.tileQueue_.getTilesLoading() < maxTotalLoading) { - this.tileQueue_.reprioritize(); // FIXME only call if view has changed - this.tileQueue_.loadMoreTiles(maxTotalLoading, maxNewLoads); + // Manage the tile queue + // Image loads are expensive and a limited resource, so try to use them + // 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); + } } var postRenderFunctions = this.postRenderFunctions_; var i; for (i = 0; i < postRenderFunctions.length; ++i) { - postRenderFunctions[i](this, this.frameState_); + postRenderFunctions[i](this, frameState); } postRenderFunctions.length = 0; };