From 549b07aead0584bc0366d402a4a92b90b2f6acd9 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:09:30 +0100 Subject: [PATCH 1/5] defer preload of tiles not immediately required handle empty reproj tiles ignore view zoom if layer inside ol/source/Raster --- src/ol/renderer/webgl/TileLayer.js | 50 ++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/ol/renderer/webgl/TileLayer.js b/src/ol/renderer/webgl/TileLayer.js index 5de570b2c8..b71820b4dd 100644 --- a/src/ol/renderer/webgl/TileLayer.js +++ b/src/ol/renderer/webgl/TileLayer.js @@ -2,6 +2,7 @@ * @module ol/renderer/webgl/TileLayer */ import LRUCache from '../../structs/LRUCache.js'; +import ReprojTile from '../../reproj/Tile.js'; import TileRange from '../../TileRange.js'; import TileState from '../../TileState.js'; import TileTexture from '../../webgl/TileTexture.js'; @@ -316,8 +317,9 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { * @param {import("../../extent.js").Extent} extent The extent to be rendered. * @param {number} initialZ The zoom level. * @param {Object>} tileTexturesByZ The zoom level. + * @param {number} preload Number of additional levels to load. */ - enqueueTiles(frameState, extent, initialZ, tileTexturesByZ) { + enqueueTiles(frameState, extent, initialZ, tileTexturesByZ, preload) { const viewState = frameState.viewState; const tileLayer = this.getLayer(); const tileSource = tileLayer.getRenderSource(); @@ -330,12 +332,23 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { } const wantedTiles = frameState.wantedTiles[tileSourceKey]; - const tileTextureCache = this.tileTextureCache_; + + const map = tileLayer.getMapInternal(); const minZ = Math.max( - initialZ - tileLayer.getPreload(), + initialZ - preload, tileGrid.getMinZoom(), - tileLayer.getMinZoom() + tileGrid.getZForResolution( + Math.min( + tileLayer.getMaxResolution(), + map + ? map + .getView() + .getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0)) + : tileGrid.getResolution(0) + ), + tileSource.zDirection + ) ); for (let z = initialZ; z >= minZ; --z) { const tileRange = tileGrid.getTileRangeForExtentAndZ( @@ -437,16 +450,34 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { */ const tileTexturesByZ = {}; + const preload = tileLayer.getPreload(); if (frameState.nextExtent) { const targetZ = tileGrid.getZForResolution( viewState.nextResolution, tileSource.zDirection ); const nextExtent = getRenderExtent(frameState, frameState.nextExtent); - this.enqueueTiles(frameState, nextExtent, targetZ, tileTexturesByZ); + this.enqueueTiles( + frameState, + nextExtent, + targetZ, + tileTexturesByZ, + preload + ); } - this.enqueueTiles(frameState, extent, z, tileTexturesByZ); + this.enqueueTiles(frameState, extent, z, tileTexturesByZ, 0); + if (preload > 0) { + setTimeout(() => { + this.enqueueTiles( + frameState, + extent, + z - 1, + tileTexturesByZ, + preload - 1 + ); + }, 0); + } /** * A lookup of alpha values for tiles at the target rendering resolution @@ -465,6 +496,9 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { for (let i = 0, ii = tileTextures.length; i < ii; ++i) { const tileTexture = tileTextures[i]; const tile = tileTexture.tile; + if (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY) { + continue; + } const tileCoord = tile.tileCoord; if (tileTexture.loaded) { @@ -753,6 +787,10 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { continue; } const tileTexture = tileTextureCache.get(cacheKey); + const tile = tileTexture.tile; + if (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY) { + return null; + } if (!tileTexture.loaded) { continue; } From 69fd11e8369117595ff9d59b302e93ee4dda7e49 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:14:36 +0100 Subject: [PATCH 2/5] handle empty reproj tiles --- src/ol/renderer/canvas/TileLayer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ol/renderer/canvas/TileLayer.js b/src/ol/renderer/canvas/TileLayer.js index 6e4b710fdb..af199884c8 100644 --- a/src/ol/renderer/canvas/TileLayer.js +++ b/src/ol/renderer/canvas/TileLayer.js @@ -181,7 +181,10 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { pixelRatio, projection ); - if (!(tile instanceof ImageTile || tile instanceof ReprojTile)) { + if ( + !(tile instanceof ImageTile || tile instanceof ReprojTile) || + (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY) + ) { return null; } From 49234b22634a1cd9e490b39fdb9e68d50b69b9c5 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Wed, 24 Aug 2022 22:00:59 +0100 Subject: [PATCH 3/5] defer preload of tiles not immediately required --- .../spec/ol/renderer/webgl/TileLayer.test.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/browser/spec/ol/renderer/webgl/TileLayer.test.js b/test/browser/spec/ol/renderer/webgl/TileLayer.test.js index 4d8af2618b..42a17c75e4 100644 --- a/test/browser/spec/ol/renderer/webgl/TileLayer.test.js +++ b/test/browser/spec/ol/renderer/webgl/TileLayer.test.js @@ -1,5 +1,7 @@ +import Map from '../../../../../../src/ol/Map.js'; import TileQueue from '../../../../../../src/ol/TileQueue.js'; import TileState from '../../../../../../src/ol/TileState.js'; +import View from '../../../../../../src/ol/View.js'; import WebGLTileLayer from '../../../../../../src/ol/layer/WebGLTile.js'; import {DataTile} from '../../../../../../src/ol/source.js'; import {VOID} from '../../../../../../src/ol/functions.js'; @@ -54,6 +56,11 @@ describe('ol/renderer/webgl/TileLayer', function () { tileQueue: new TileQueue(VOID, VOID), renderTargets: {}, }; + + const map = new Map({ + view: new View(), + }); + tileLayer.set('map', map, true); }); afterEach(function () { @@ -111,7 +118,7 @@ describe('ol/renderer/webgl/TileLayer', function () { it('enqueues tiles at a single zoom level (preload: 0)', () => { renderer.prepareFrame(frameState); const extent = [-1, -1, 1, 1]; - renderer.enqueueTiles(frameState, extent, 10, {}); + renderer.enqueueTiles(frameState, extent, 10, {}, tileLayer.getPreload()); const source = tileLayer.getSource(); const sourceKey = getUid(source); @@ -132,7 +139,7 @@ describe('ol/renderer/webgl/TileLayer', function () { tileLayer.setPreload(2); renderer.prepareFrame(frameState); const extent = [-1, -1, 1, 1]; - renderer.enqueueTiles(frameState, extent, 10, {}); + renderer.enqueueTiles(frameState, extent, 10, {}, tileLayer.getPreload()); const source = tileLayer.getSource(); const sourceKey = getUid(source); @@ -162,7 +169,7 @@ describe('ol/renderer/webgl/TileLayer', function () { tileLayer.setMinZoom(9); renderer.prepareFrame(frameState); const extent = [-1, -1, 1, 1]; - renderer.enqueueTiles(frameState, extent, 10, {}); + renderer.enqueueTiles(frameState, extent, 10, {}, tileLayer.getPreload()); const source = tileLayer.getSource(); const sourceKey = getUid(source); From b3172a8c8b6629a32a21228969de0bb51d55fd5e Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Thu, 25 Aug 2022 11:52:04 +0100 Subject: [PATCH 4/5] defer preload of tiles not immediately required --- .../cases/webgl-tile-preload/expected.png | Bin 0 -> 6782 bytes .../cases/webgl-tile-preload/main.js | 20 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/rendering/cases/webgl-tile-preload/expected.png create mode 100644 test/rendering/cases/webgl-tile-preload/main.js diff --git a/test/rendering/cases/webgl-tile-preload/expected.png b/test/rendering/cases/webgl-tile-preload/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..fc0d58549364794f0e0e54300f140e1579fe8237 GIT binary patch literal 6782 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 Date: Thu, 25 Aug 2022 12:44:47 +0100 Subject: [PATCH 5/5] test layer min zoom relates to view zoom --- .../spec/ol/renderer/webgl/TileLayer.test.js | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/test/browser/spec/ol/renderer/webgl/TileLayer.test.js b/test/browser/spec/ol/renderer/webgl/TileLayer.test.js index 42a17c75e4..6f5f555b6e 100644 --- a/test/browser/spec/ol/renderer/webgl/TileLayer.test.js +++ b/test/browser/spec/ol/renderer/webgl/TileLayer.test.js @@ -17,6 +17,8 @@ describe('ol/renderer/webgl/TileLayer', function () { let tileLayer; /** @type {import('../../../../../../src/ol/Map.js').FrameState} */ let frameState; + /** @type {Map} */ + let map; beforeEach(function () { const size = 256; const context = createCanvasContext2D(size, size); @@ -57,7 +59,7 @@ describe('ol/renderer/webgl/TileLayer', function () { renderTargets: {}, }; - const map = new Map({ + map = new Map({ view: new View(), }); tileLayer.set('map', map, true); @@ -65,6 +67,7 @@ describe('ol/renderer/webgl/TileLayer', function () { afterEach(function () { tileLayer.dispose(); + map.dispose(); }); it('maintains a cache on the renderer instead of the source', function () { @@ -189,5 +192,38 @@ describe('ol/renderer/webgl/TileLayer', function () { }; expect(wantedTiles).to.eql(expected); }); + + it('layer min zoom relates to view zoom levels', () => { + map.setView( + new View({maxResolution: map.getView().getMaxResolution() * 2}) + ); + tileLayer.setPreload(Infinity); + tileLayer.setMinZoom(9); + renderer.prepareFrame(frameState); + const extent = [-1, -1, 1, 1]; + renderer.enqueueTiles(frameState, extent, 10, {}, tileLayer.getPreload()); + + const source = tileLayer.getSource(); + const sourceKey = getUid(source); + expect(frameState.wantedTiles[sourceKey]).to.be.an(Object); + + const wantedTiles = frameState.wantedTiles[sourceKey]; + + const expected = { + '/10,511,511': true, + '/10,511,512': true, + '/10,512,511': true, + '/10,512,512': true, + '/9,255,255': true, + '/9,255,256': true, + '/9,256,255': true, + '/9,256,256': true, + '/8,127,127': true, + '/8,127,128': true, + '/8,128,127': true, + '/8,128,128': true, + }; + expect(wantedTiles).to.eql(expected); + }); }); });