Decouple executor group creation from rendering
This commit is contained in:
@@ -146,9 +146,10 @@ class Tile extends EventTarget {
|
|||||||
* Get the interim tile most suitable for rendering using the chain of interim
|
* Get the interim tile most suitable for rendering using the chain of interim
|
||||||
* tiles. This corresponds to the most recent tile that has been loaded, if no
|
* tiles. This corresponds to the most recent tile that has been loaded, if no
|
||||||
* such tile exists, the original tile is returned.
|
* such tile exists, the original tile is returned.
|
||||||
|
* @param {import("./layer/Layer").default} layer Layer.
|
||||||
* @return {!Tile} Best tile for rendering.
|
* @return {!Tile} Best tile for rendering.
|
||||||
*/
|
*/
|
||||||
getInterimTile() {
|
getInterimTile(layer) {
|
||||||
if (!this.interimTile) {
|
if (!this.interimTile) {
|
||||||
//empty chain
|
//empty chain
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -72,6 +72,12 @@ class VectorImageTile extends Tile {
|
|||||||
*/
|
*/
|
||||||
this.sourceTiles_ = sourceTiles;
|
this.sourceTiles_ = sourceTiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.sourceTilesLoaded = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keys of source tiles used by this tile. Use with {@link #getTile}.
|
* Keys of source tiles used by this tile. Use with {@link #getTile}.
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
@@ -107,13 +113,13 @@ class VectorImageTile extends Tile {
|
|||||||
* Use only source tiles that are loaded already
|
* Use only source tiles that are loaded already
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.useLoadedOnly = zoom != tileCoord[0];
|
this.isInterimTile = zoom != tileCoord[0];
|
||||||
|
|
||||||
if (urlTileCoord) {
|
if (urlTileCoord) {
|
||||||
const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||||
const resolution = tileGrid.getResolution(zoom);
|
const resolution = tileGrid.getResolution(zoom);
|
||||||
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||||
const useLoadedOnly = this.useLoadedOnly;
|
const isInterimTile = this.isInterimTile;
|
||||||
let loadCount = 0;
|
let loadCount = 0;
|
||||||
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
|
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
|
||||||
let sharedExtent = getIntersection(extent,
|
let sharedExtent = getIntersection(extent,
|
||||||
@@ -128,7 +134,7 @@ class VectorImageTile extends Tile {
|
|||||||
++loadCount;
|
++loadCount;
|
||||||
const sourceTileKey = sourceTileCoord.toString();
|
const sourceTileKey = sourceTileCoord.toString();
|
||||||
let sourceTile = sourceTiles[sourceTileKey];
|
let sourceTile = sourceTiles[sourceTileKey];
|
||||||
if (!sourceTile && !useLoadedOnly) {
|
if (!sourceTile && !isInterimTile) {
|
||||||
const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
|
const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
|
||||||
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
|
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
|
||||||
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
||||||
@@ -137,19 +143,19 @@ class VectorImageTile extends Tile {
|
|||||||
this.sourceTileListenerKeys_.push(
|
this.sourceTileListenerKeys_.push(
|
||||||
listen(sourceTile, EventType.CHANGE, handleTileChange));
|
listen(sourceTile, EventType.CHANGE, handleTileChange));
|
||||||
}
|
}
|
||||||
if (sourceTile && (!useLoadedOnly || sourceTile.getState() == TileState.LOADED)) {
|
if (sourceTile && (!isInterimTile || sourceTile.getState() == TileState.LOADED)) {
|
||||||
sourceTile.consumers++;
|
sourceTile.consumers++;
|
||||||
this.tileKeys.push(sourceTileKey);
|
this.tileKeys.push(sourceTileKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
if (useLoadedOnly && loadCount == this.tileKeys.length) {
|
if (isInterimTile && loadCount == this.tileKeys.length) {
|
||||||
this.finishLoading_();
|
this.finishLoading_();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createInterimTile_ = function() {
|
this.createInterimTile_ = function(layerId) {
|
||||||
if (this.getState() !== TileState.LOADED && !useLoadedOnly) {
|
if (this.getState() !== TileState.LOADED && !isInterimTile) {
|
||||||
let bestZoom = -1;
|
let bestZoom = -1;
|
||||||
for (const key in sourceTiles) {
|
for (const key in sourceTiles) {
|
||||||
const sourceTile = sourceTiles[key];
|
const sourceTile = sourceTiles[key];
|
||||||
@@ -157,16 +163,20 @@ class VectorImageTile extends Tile {
|
|||||||
const sourceTileCoord = sourceTile.tileCoord;
|
const sourceTileCoord = sourceTile.tileCoord;
|
||||||
const sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
const sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
||||||
if (containsExtent(sourceTileExtent, extent) && sourceTileCoord[0] > bestZoom) {
|
if (containsExtent(sourceTileExtent, extent) && sourceTileCoord[0] > bestZoom) {
|
||||||
|
const lowResExecutorGroup = sourceTile.getLowResExecutorGroup(layerId, zoom, extent);
|
||||||
|
if (lowResExecutorGroup) {
|
||||||
|
// reuse existing replay if we're rendering an interim tile
|
||||||
|
sourceTile.setExecutorGroup(layerId, this.tileCoord.toString(), lowResExecutorGroup);
|
||||||
bestZoom = sourceTileCoord[0];
|
bestZoom = sourceTileCoord[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (bestZoom !== -1) {
|
if (bestZoom !== -1) {
|
||||||
const tile = new VectorImageTile(tileCoord, state, sourceRevision,
|
this.interimTile = new VectorImageTile(tileCoord, state, sourceRevision,
|
||||||
format, tileLoadFunction, urlTileCoord, tileUrlFunction,
|
format, tileLoadFunction, urlTileCoord, tileUrlFunction,
|
||||||
sourceTileGrid, tileGrid, sourceTiles, pixelRatio, projection,
|
sourceTileGrid, tileGrid, sourceTiles, pixelRatio, projection,
|
||||||
tileClass, VOID, bestZoom);
|
tileClass, VOID, bestZoom);
|
||||||
this.interimTile = tile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -174,11 +184,11 @@ class VectorImageTile extends Tile {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getInterimTile() {
|
getInterimTile(layer) {
|
||||||
if (!this.interimTile) {
|
if (!this.interimTile) {
|
||||||
this.createInterimTile_();
|
this.createInterimTile_(getUid(layer));
|
||||||
}
|
}
|
||||||
return super.getInterimTile();
|
return super.getInterimTile(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,7 +341,7 @@ class VectorImageTile extends Tile {
|
|||||||
this.loadListenerKeys_.forEach(unlistenByKey);
|
this.loadListenerKeys_.forEach(unlistenByKey);
|
||||||
this.loadListenerKeys_.length = 0;
|
this.loadListenerKeys_.length = 0;
|
||||||
this.sourceTilesLoaded = true;
|
this.sourceTilesLoaded = true;
|
||||||
this.setState(TileState.LOADED);
|
this.changed();
|
||||||
} else {
|
} else {
|
||||||
this.setState(empty == this.tileKeys.length ? TileState.EMPTY : TileState.ERROR);
|
this.setState(empty == this.tileKeys.length ? TileState.EMPTY : TileState.ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
* @module ol/VectorTile
|
* @module ol/VectorTile
|
||||||
*/
|
*/
|
||||||
import {containsExtent} from './extent.js';
|
import {containsExtent} from './extent.js';
|
||||||
import {getUid} from './util.js';
|
|
||||||
import Tile from './Tile.js';
|
import Tile from './Tile.js';
|
||||||
import TileState from './TileState.js';
|
import TileState from './TileState.js';
|
||||||
|
|
||||||
@@ -140,23 +139,22 @@ class VectorTile extends Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./layer/Layer.js").default} layer Layer.
|
* @param {string} layerId UID of the layer.
|
||||||
* @param {string} key Key.
|
* @param {string} key Key.
|
||||||
* @return {import("./render/canvas/ExecutorGroup.js").default} Executor group.
|
* @return {import("./render/canvas/ExecutorGroup.js").default} Executor group.
|
||||||
*/
|
*/
|
||||||
getExecutorGroup(layer, key) {
|
getExecutorGroup(layerId, key) {
|
||||||
return this.executorGroups_[getUid(layer) + ',' + key];
|
return this.executorGroups_[layerId + ',' + key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the best matching lower resolution replay group for a given zoom and extent.
|
* Get the best matching lower resolution replay group for a given zoom and extent.
|
||||||
* @param {import("./layer/Layer").default} layer Layer.
|
* @param {string} layerId UID of the layer.
|
||||||
* @param {number} zoom Zoom.
|
* @param {number} zoom Zoom.
|
||||||
* @param {import("./extent").Extent} extent Extent.
|
* @param {import("./extent").Extent} extent Extent.
|
||||||
* @return {import("./render/canvas/ExecutorGroup.js").default} Executor groups.
|
* @return {import("./render/canvas/ExecutorGroup.js").default} Executor groups.
|
||||||
*/
|
*/
|
||||||
getLowResExecutorGroup(layer, zoom, extent) {
|
getLowResExecutorGroup(layerId, zoom, extent) {
|
||||||
const layerId = getUid(layer);
|
|
||||||
let bestZoom = 0;
|
let bestZoom = 0;
|
||||||
let replayGroup = null;
|
let replayGroup = null;
|
||||||
for (const key in this.executorGroups_) {
|
for (const key in this.executorGroups_) {
|
||||||
@@ -242,12 +240,12 @@ class VectorTile extends Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./layer/Layer.js").default} layer Layer.
|
* @param {string} layerId UID of the layer.
|
||||||
* @param {string} key Key.
|
* @param {string} key Key.
|
||||||
* @param {import("./render/canvas/ExecutorGroup.js").default} executorGroup Executor group.
|
* @param {import("./render/canvas/ExecutorGroup.js").default} executorGroup Executor group.
|
||||||
*/
|
*/
|
||||||
setExecutorGroup(layer, key, executorGroup) {
|
setExecutorGroup(layerId, key, executorGroup) {
|
||||||
this.executorGroups_[getUid(layer) + ',' + key] = executorGroup;
|
this.executorGroups_[layerId + ',' + key] = executorGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this.isDrawableTile_(tile)) {
|
if (!this.isDrawableTile_(tile)) {
|
||||||
tile = tile.getInterimTile();
|
tile = tile.getInterimTile(tileLayer);
|
||||||
}
|
}
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {getUid} from '../../util.js';
|
|||||||
import {createCanvasContext2D} from '../../dom.js';
|
import {createCanvasContext2D} from '../../dom.js';
|
||||||
import TileState from '../../TileState.js';
|
import TileState from '../../TileState.js';
|
||||||
import ViewHint from '../../ViewHint.js';
|
import ViewHint from '../../ViewHint.js';
|
||||||
import {listen, unlisten} from '../../events.js';
|
import {listen, unlisten, unlistenByKey} from '../../events.js';
|
||||||
import EventType from '../../events/EventType.js';
|
import EventType from '../../events/EventType.js';
|
||||||
import rbush from 'rbush';
|
import rbush from 'rbush';
|
||||||
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
||||||
@@ -147,11 +147,20 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
getTile(z, x, y, pixelRatio, projection) {
|
getTile(z, x, y, pixelRatio, projection) {
|
||||||
const tile = super.getTile(z, x, y, pixelRatio, projection);
|
const tile = /** @type {import("../../VectorImageTile.js").default} */ (super.getTile(z, x, y, pixelRatio, projection));
|
||||||
|
if (tile.getState() === TileState.IDLE) {
|
||||||
|
const key = listen(tile, EventType.CHANGE, function() {
|
||||||
|
if (tile.sourceTilesLoaded) {
|
||||||
|
this.createExecutorGroup_(tile, pixelRatio, projection);
|
||||||
|
unlistenByKey(key);
|
||||||
|
tile.setState(TileState.LOADED);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
if (tile.getState() === TileState.LOADED) {
|
if (tile.getState() === TileState.LOADED) {
|
||||||
this.createExecutorGroup_(/** @type {import("../../VectorImageTile.js").default} */ (tile), pixelRatio, projection);
|
this.createExecutorGroup_(tile, pixelRatio, projection);
|
||||||
if (this.context) {
|
if (this.context) {
|
||||||
this.renderTileImage_(/** @type {import("../../VectorImageTile.js").default} */ (tile), pixelRatio, projection);
|
this.renderTileImage_(tile, pixelRatio, projection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tile;
|
return tile;
|
||||||
@@ -162,7 +171,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
*/
|
*/
|
||||||
getTileImage(tile) {
|
getTileImage(tile) {
|
||||||
const tileLayer = /** @type {import("../../layer/Tile.js").default} */ (this.getLayer());
|
const tileLayer = /** @type {import("../../layer/Tile.js").default} */ (this.getLayer());
|
||||||
return /** @type {import("../../VectorImageTile.js").default} */ (tile).getImage(tileLayer);
|
return tile.getImage(tileLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,6 +195,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
*/
|
*/
|
||||||
createExecutorGroup_(tile, pixelRatio, projection) {
|
createExecutorGroup_(tile, pixelRatio, projection) {
|
||||||
const layer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
|
const layer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
|
||||||
|
const layerId = getUid(layer);
|
||||||
const revision = layer.getRevision();
|
const revision = layer.getRevision();
|
||||||
const renderOrder = /** @type {import("../../render.js").OrderFunction} */ (layer.getRenderOrder()) || null;
|
const renderOrder = /** @type {import("../../render.js").OrderFunction} */ (layer.getRenderOrder()) || null;
|
||||||
|
|
||||||
@@ -207,14 +217,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
if (sourceTile.getState() != TileState.LOADED) {
|
if (sourceTile.getState() != TileState.LOADED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (tile.useLoadedOnly) {
|
if (tile.isInterimTile) {
|
||||||
const lowResExecutorGroup = sourceTile.getLowResExecutorGroup(layer, zoom, tileExtent);
|
|
||||||
if (lowResExecutorGroup) {
|
|
||||||
// reuse existing replay if we're rendering an interim tile
|
// reuse existing replay if we're rendering an interim tile
|
||||||
sourceTile.setExecutorGroup(layer, tile.tileCoord.toString(), lowResExecutorGroup);
|
sourceTile.setExecutorGroup(layerId, tile.tileCoord.toString(),
|
||||||
|
sourceTile.getLowResExecutorGroup(layerId, zoom, tileExtent));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const sourceTileCoord = sourceTile.tileCoord;
|
const sourceTileCoord = sourceTile.tileCoord;
|
||||||
const sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
const sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
||||||
@@ -271,7 +279,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
const executorGroupInstructions = builderGroup.finish();
|
const executorGroupInstructions = builderGroup.finish();
|
||||||
const renderingReplayGroup = new CanvasExecutorGroup(sharedExtent, resolution,
|
const renderingReplayGroup = new CanvasExecutorGroup(sharedExtent, resolution,
|
||||||
pixelRatio, source.getOverlaps(), this.declutterTree_, executorGroupInstructions, layer.getRenderBuffer());
|
pixelRatio, source.getOverlaps(), this.declutterTree_, executorGroupInstructions, layer.getRenderBuffer());
|
||||||
sourceTile.setExecutorGroup(layer, tile.tileCoord.toString(), renderingReplayGroup);
|
sourceTile.setExecutorGroup(getUid(layer), tile.tileCoord.toString(), renderingReplayGroup);
|
||||||
}
|
}
|
||||||
builderState.renderedRevision = revision;
|
builderState.renderedRevision = revision;
|
||||||
builderState.renderedRenderOrder = renderOrder;
|
builderState.renderedRenderOrder = renderOrder;
|
||||||
@@ -303,7 +311,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
if (sourceTile.getState() != TileState.LOADED) {
|
if (sourceTile.getState() != TileState.LOADED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(layer,
|
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(getUid(layer),
|
||||||
tile.tileCoord.toString()));
|
tile.tileCoord.toString()));
|
||||||
found = found || executorGroup.forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance, {},
|
found = found || executorGroup.forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance, {},
|
||||||
/**
|
/**
|
||||||
@@ -431,7 +439,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
if (sourceTile.getState() != TileState.LOADED) {
|
if (sourceTile.getState() != TileState.LOADED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(layer, tileCoord.toString()));
|
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(getUid(layer), tileCoord.toString()));
|
||||||
if (!executorGroup || !executorGroup.hasExecutors(replayTypes)) {
|
if (!executorGroup || !executorGroup.hasExecutors(replayTypes)) {
|
||||||
// sourceTile was not yet loaded when this.createReplayGroup_() was
|
// sourceTile was not yet loaded when this.createReplayGroup_() was
|
||||||
// called, or it has no replays of the types we want to render
|
// called, or it has no replays of the types we want to render
|
||||||
@@ -536,7 +544,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
const transform = resetTransform(this.tmpTransform_);
|
const transform = resetTransform(this.tmpTransform_);
|
||||||
scaleTransform(transform, pixelScale, -pixelScale);
|
scaleTransform(transform, pixelScale, -pixelScale);
|
||||||
translateTransform(transform, -tileExtent[0], -tileExtent[3]);
|
translateTransform(transform, -tileExtent[0], -tileExtent[3]);
|
||||||
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(layer,
|
const executorGroup = /** @type {CanvasExecutorGroup} */ (sourceTile.getExecutorGroup(getUid(layer),
|
||||||
tile.tileCoord.toString()));
|
tile.tileCoord.toString()));
|
||||||
executorGroup.execute(context, transform, 0, {}, true, replays);
|
executorGroup.execute(context, transform, 0, {}, true, replays);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user