diff --git a/src/ol/layer/WebGLTile.js b/src/ol/layer/WebGLTile.js index 7080c7ce3c..04ad68e0a0 100644 --- a/src/ol/layer/WebGLTile.js +++ b/src/ol/layer/WebGLTile.js @@ -63,6 +63,8 @@ import {assign} from '../obj.js'; * temporary layers. The standard way to add a layer to a map and have it managed by the map is to * use {@link module:ol/Map#addLayer}. * @property {boolean} [useInterimTilesOnError=true] Use interim tiles on error. + * @property {number} [cacheSize=512] The internal texture cache size. This needs to be large enough to render + * two zoom levels worth of tiles. */ /** @@ -265,12 +267,23 @@ class WebGLTileLayer extends BaseTileLayer { const style = options.style || {}; delete options.style; + + const cacheSize = options.cacheSize; + delete options.cacheSize; + super(options); /** * @type {Style} + * @private */ this.style_ = style; + + /** + * @type {number} + * @private + */ + this.cacheSize_ = cacheSize; } /** @@ -292,6 +305,7 @@ class WebGLTileLayer extends BaseTileLayer { fragmentShader: parsedStyle.fragmentShader, uniforms: parsedStyle.uniforms, className: this.getClassName(), + cacheSize: this.cacheSize_, }); } diff --git a/src/ol/renderer/webgl/TileLayer.js b/src/ol/renderer/webgl/TileLayer.js index 48f0a197d9..0540d0a69f 100644 --- a/src/ol/renderer/webgl/TileLayer.js +++ b/src/ol/renderer/webgl/TileLayer.js @@ -56,6 +56,8 @@ const attributeDescriptions = [ }, ]; +const empty = {}; + /** * Transform a zoom level into a depth value ranging from -1 to 1. * @param {number} z A zoom level. @@ -103,6 +105,7 @@ function getRenderExtent(frameState) { * @property {Object} [uniforms] Additional uniforms * made available to shaders. * @property {string} [className='ol-layer'] A CSS class name to set to the canvas element. + * @property {number} [cacheSize=512] The texture cache size. */ /** @@ -177,7 +180,8 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { this.helper.flushBufferData(indices); this.indices_ = indices; - this.tileTextureCache_ = new LRUCache(512); + const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 512; + this.tileTextureCache_ = new LRUCache(cacheSize); this.renderedOpacity_ = NaN; } @@ -468,23 +472,17 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer { } // TODO: let the renderers manage their own cache instead of managing the source cache - if (tileSource.canExpireCache()) { - /** - * @param {import("../../PluggableMap.js").default} map Map. - * @param {import("../../PluggableMap.js").FrameState} frameState Frame state. - */ - const postRenderFunction = function (map, frameState) { - const tileSourceKey = getUid(tileSource); - if (tileSourceKey in frameState.usedTiles) { - tileSource.expireCache( - frameState.viewState.projection, - frameState.usedTiles[tileSourceKey] - ); - } - }; + /** + * Here we unconditionally expire the source cache since the renderer maintains + * its own cache. + * @param {import("../../PluggableMap.js").default} map Map. + * @param {import("../../PluggableMap.js").FrameState} frameState Frame state. + */ + const postRenderFunction = function (map, frameState) { + tileSource.expireCache(tileSource.getProjection(), empty); + }; - frameState.postRenderFunctions.push(postRenderFunction); - } + frameState.postRenderFunctions.push(postRenderFunction); this.postRender(frameState); return canvas; diff --git a/src/ol/source/DataTile.js b/src/ol/source/DataTile.js index 3a813aa34e..cc1acc26aa 100644 --- a/src/ol/source/DataTile.js +++ b/src/ol/source/DataTile.js @@ -23,7 +23,6 @@ import {getUid} from '../util.js'; * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. * @property {boolean} [opaque=false] Whether the layer is opaque. * @property {import("./State.js").default} [state] The source state. - * @property {number} [cacheSize] Number of tiles to retain in the cache. * @property {number} [tilePixelRatio] Tile pixel ratio. * @property {boolean} [wrapX=true] Render tiles beyond the antimeridian. * @property {number} [transition] Transition time when fading in new tiles (in miliseconds). @@ -56,7 +55,7 @@ class DataTileSource extends TileSource { } super({ - cacheSize: options.cacheSize, + cacheSize: 0.1, // don't cache on the source projection: projection, tileGrid: tileGrid, opaque: options.opaque, diff --git a/test/browser/spec/ol/layer/webgltile.test.js b/test/browser/spec/ol/layer/webgltile.test.js index 1fae9b1771..edd5aab452 100644 --- a/test/browser/spec/ol/layer/webgltile.test.js +++ b/test/browser/spec/ol/layer/webgltile.test.js @@ -5,7 +5,7 @@ import WebGLHelper from '../../../../../src/ol/webgl/Helper.js'; import WebGLTileLayer from '../../../../../src/ol/layer/WebGLTile.js'; import {createCanvasContext2D} from '../../../../../src/ol/dom.js'; -describe('ol.layer.Tile', function () { +describe('ol/layer/WebGLTile', function () { /** @type {WebGLTileLayer} */ let layer; /** @type {Map} */ @@ -120,6 +120,17 @@ describe('ol.layer.Tile', function () { }); }); + it('tries to expire the source tile cache', (done) => { + const source = layer.getSource(); + const expire = sinon.spy(source, 'expireCache'); + + layer.updateStyleVariables({r: 1, g: 2, b: 3}); + map.once('rendercomplete', () => { + expect(expire.called).to.be(true); + done(); + }); + }); + it('throws on incorrect style configs', function () { function incorrectStyle() { layer.style_ = { diff --git a/test/browser/spec/ol/renderer/webgl/tilelayer.test.js b/test/browser/spec/ol/renderer/webgl/tilelayer.test.js index d1dc885246..ed4a224640 100644 --- a/test/browser/spec/ol/renderer/webgl/tilelayer.test.js +++ b/test/browser/spec/ol/renderer/webgl/tilelayer.test.js @@ -54,6 +54,11 @@ describe('ol.renderer.webgl.TileLayer', function () { }; }); + it('maintains a cache on the renderer instead of the source', function () { + expect(tileLayer.getSource().tileCache.highWaterMark).to.be(0.1); + expect(renderer.tileTextureCache_.highWaterMark).to.be(512); + }); + it('#prepareFrame()', function () { const source = tileLayer.getSource(); tileLayer.setSource(null); @@ -73,7 +78,7 @@ describe('ol.renderer.webgl.TileLayer', function () { expect(rendered).to.be.a(HTMLCanvasElement); expect(frameState.tileQueue.getCount()).to.be(1); expect(Object.keys(frameState.wantedTiles).length).to.be(1); - expect(frameState.postRenderFunctions.length).to.be(0); // no tile expired + expect(frameState.postRenderFunctions.length).to.be(1); // clear source cache (use renderer cache) expect(renderer.tileTextureCache_.count_).to.be(1); });