Merge pull request #12798 from tschaub/dispose-webgl-tilelayer

More cleanup in the WebGL tile layer's dispose method
This commit is contained in:
Tim Schaub
2021-09-23 12:34:23 +00:00
committed by GitHub
6 changed files with 61 additions and 0 deletions
+5
View File
@@ -348,6 +348,11 @@ class Layer extends BaseLayer {
* Clean up. * Clean up.
*/ */
disposeInternal() { disposeInternal() {
if (this.renderer_) {
this.renderer_.dispose();
delete this.renderer_;
}
this.setSource(null); this.setSource(null);
super.disposeInternal(); super.disposeInternal();
} }
+10
View File
@@ -255,6 +255,9 @@ function parseStyle(style, bandCount) {
* property on the layer object; for example, setting `title: 'My Title'` in the * property on the layer object; for example, setting `title: 'My Title'` in the
* options means that `title` is observable, and has get/set accessors. * options means that `title` is observable, and has get/set accessors.
* *
* **Important**: after removing a `WebGLTile` layer from your map, call `layer.dispose()`
* to clean up underlying resources.
*
* @extends BaseTileLayer<import("../source/DataTile.js").default|import("../source/TileImage.js").default> * @extends BaseTileLayer<import("../source/DataTile.js").default|import("../source/TileImage.js").default>
* @api * @api
*/ */
@@ -320,4 +323,11 @@ class WebGLTileLayer extends BaseTileLayer {
} }
} }
/**
* Clean up underlying WebGL resources.
* @function
* @api
*/
WebGLTileLayer.prototype.dispose;
export default WebGLTileLayer; export default WebGLTileLayer;
+2
View File
@@ -77,6 +77,8 @@ class WebGLLayerRenderer extends LayerRenderer {
*/ */
disposeInternal() { disposeInternal() {
this.helper.dispose(); this.helper.dispose();
delete this.helper;
super.disposeInternal(); super.disposeInternal();
} }
+28
View File
@@ -181,6 +181,11 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
this.indices_ = indices; this.indices_ = indices;
const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 512; const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 512;
/**
* @type {import("../../structs/LRUCache.js").default<import("../../webgl/TileTexture.js").default>}
* @private
*/
this.tileTextureCache_ = new LRUCache(cacheSize); this.tileTextureCache_ = new LRUCache(cacheSize);
this.renderedOpacity_ = NaN; this.renderedOpacity_ = NaN;
@@ -533,6 +538,29 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
} }
return covered; return covered;
} }
/**
* Clean up.
*/
disposeInternal() {
const helper = this.helper;
const gl = helper.getGL();
helper.deleteBuffer(this.indices_);
delete this.indices_;
gl.deleteProgram(this.program_);
delete this.program_;
const tileTextureCache = this.tileTextureCache_;
tileTextureCache.forEach(function (tileTexture) {
tileTexture.dispose();
});
tileTextureCache.clear();
delete this.tileTextureCache_;
super.disposeInternal();
}
} }
/** /**
+7
View File
@@ -442,6 +442,13 @@ class WebGLHelper extends Disposable {
ContextEventType.RESTORED, ContextEventType.RESTORED,
this.boundHandleWebGLContextRestored_ this.boundHandleWebGLContextRestored_
); );
const extension = this.gl_.getExtension('WEBGL_lose_context');
if (extension) {
extension.loseContext();
}
delete this.gl_;
delete this.canvas_;
} }
/** /**
@@ -50,6 +50,15 @@ describe('ol/layer/WebGLTile', function () {
document.body.removeChild(target); document.body.removeChild(target);
}); });
describe('dispose()', () => {
it('calls dispose on the renderer', () => {
const renderer = layer.getRenderer();
const spy = sinon.spy(renderer, 'dispose');
layer.dispose();
expect(spy.called).to.be(true);
});
});
it('creates fragment and vertex shaders', function () { it('creates fragment and vertex shaders', function () {
const compileShaderSpy = sinon.spy(WebGLHelper.prototype, 'compileShader'); const compileShaderSpy = sinon.spy(WebGLHelper.prototype, 'compileShader');
layer.createRenderer(); layer.createRenderer();