From c6b126e155f4e67b3986f71854edebe13950ead6 Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:31:52 +0100 Subject: [PATCH 1/6] shared-webgl-context: original patch from experimentation --- src/core/LayerGL.js | 51 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/src/core/LayerGL.js b/src/core/LayerGL.js index 484fc40c..a02f6ea3 100644 --- a/src/core/LayerGL.js +++ b/src/core/LayerGL.js @@ -21,6 +21,8 @@ import graphicGL from '../util/graphicGL'; import notifier from 'claygl/src/core/mixin/notifier'; import requestAnimationFrame from 'zrender/lib/animation/requestAnimationFrame'; +var _LayerGL_global_renderer = undefined; + /** * @constructor * @alias module:echarts-gl/core/LayerGL @@ -44,13 +46,16 @@ var LayerGL = function (id, zr) { * @type {clay.Renderer} */ try { - this.renderer = new Renderer({ - clearBit: 0, - devicePixelRatio: zr.painter.dpr, - preserveDrawingBuffer: true, - // PENDING - premultipliedAlpha: true - }); + if (!_LayerGL_global_renderer) { + _LayerGL_global_renderer = new src_Renderer({ + clearBit: 0, + devicePixelRatio: zr.painter.dpr, + preserveDrawingBuffer: true, + // PENDING + premultipliedAlpha: true + }); + } + this.renderer = _LayerGL_global_renderer; this.renderer.resize(zr.painter.getWidth(), zr.painter.getHeight()); } catch (e) { @@ -71,7 +76,12 @@ var LayerGL = function (id, zr) { * Canvas dom for webgl rendering * @type {HTMLCanvasElement} */ - this.dom = this.renderer.canvas; + this.dom = document.createElement('canvas'); + this.domCanvasContext = this.dom.getContext('2d') + this.dom.style.width = this.renderer.canvas.style.width; + this.dom.style.height = this.renderer.canvas.style.height; + this.dom.width = this.renderer.canvas.width; + this.dom.height = this.renderer.canvas.height; var style = this.dom.style; style.position = 'absolute'; style.left = '0'; @@ -182,6 +192,11 @@ LayerGL.prototype.removeViewsAll = function () { LayerGL.prototype.resize = function (width, height) { var renderer = this.renderer; renderer.resize(width, height); + + this.dom.style.width = this.renderer.canvas.style.width; + this.dom.style.height = this.renderer.canvas.style.height; + this.dom.width = this.renderer.canvas.width; + this.dom.height = this.renderer.canvas.height; }; /** @@ -189,6 +204,21 @@ LayerGL.prototype.resize = function (width, height) { * @return {[type]} [description] */ LayerGL.prototype.clear = function () { + if (this.renderer.gl.isContextLost()) { + console.log('context lost, recreating renderer') + if (_LayerGL_global_renderer.gl.isContextLost()) { + this.renderer = new Renderer({ + clearBit: 0, + devicePixelRatio: this.zr.painter.dpr, + preserveDrawingBuffer: true, + // PENDING + premultipliedAlpha: true + }); + } + this.renderer = _LayerGL_global_renderer; + } + this.renderer.resize(this.zr.painter.getWidth(), this.zr.painter.getHeight()); + var gl = this.renderer.gl; var clearColor = this._backgroundColor || [0, 0, 0, 0]; gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); @@ -261,6 +291,9 @@ LayerGL.prototype._doRender = function (accumulating) { this.views[i].render(this.renderer, accumulating); } this.renderer.restoreViewport(); + + this.domCanvasContext.clearRect(0,0,this.dom.width,this.dom.height) + this.domCanvasContext.drawImage(this.renderer.canvas, 0, 0, this.renderer.canvas.width, this.renderer.canvas.height); }; /** @@ -675,4 +708,4 @@ LayerGL.prototype._dispatchToView = function (eventName, e) { Object.assign(LayerGL.prototype, notifier); -export default LayerGL; \ No newline at end of file +export default LayerGL; From a3f12863cf24e1dcc020c743b15789154008fb3d Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:33:34 +0100 Subject: [PATCH 2/6] shared-webgl-context: clean up patch, correct src_Renderer -> Renderer --- src/core/LayerGL.js | 47 +++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/core/LayerGL.js b/src/core/LayerGL.js index a02f6ea3..e850dd3c 100644 --- a/src/core/LayerGL.js +++ b/src/core/LayerGL.js @@ -46,16 +46,7 @@ var LayerGL = function (id, zr) { * @type {clay.Renderer} */ try { - if (!_LayerGL_global_renderer) { - _LayerGL_global_renderer = new src_Renderer({ - clearBit: 0, - devicePixelRatio: zr.painter.dpr, - preserveDrawingBuffer: true, - // PENDING - premultipliedAlpha: true - }); - } - this.renderer = _LayerGL_global_renderer; + this.resetRenderer(); this.renderer.resize(zr.painter.getWidth(), zr.painter.getHeight()); } catch (e) { @@ -114,6 +105,20 @@ var LayerGL = function (id, zr) { this._disposed = false; }; +LayerGL.prototype.resetRenderer = function () { + if (!_LayerGL_global_renderer || _LayerGL_global_renderer.gl.isContextLost()) { + console.log('creating new renderer') + _LayerGL_global_renderer = new Renderer({ + clearBit: 0, + devicePixelRatio: this.zr.painter.dpr, + preserveDrawingBuffer: true, + // PENDING + premultipliedAlpha: true + }); + } + this.renderer = _LayerGL_global_renderer; +}; + LayerGL.prototype.setUnpainted = function () {}; /** @@ -204,21 +209,6 @@ LayerGL.prototype.resize = function (width, height) { * @return {[type]} [description] */ LayerGL.prototype.clear = function () { - if (this.renderer.gl.isContextLost()) { - console.log('context lost, recreating renderer') - if (_LayerGL_global_renderer.gl.isContextLost()) { - this.renderer = new Renderer({ - clearBit: 0, - devicePixelRatio: this.zr.painter.dpr, - preserveDrawingBuffer: true, - // PENDING - premultipliedAlpha: true - }); - } - this.renderer = _LayerGL_global_renderer; - } - this.renderer.resize(this.zr.painter.getWidth(), this.zr.painter.getHeight()); - var gl = this.renderer.gl; var clearColor = this._backgroundColor || [0, 0, 0, 0]; gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); @@ -255,6 +245,13 @@ LayerGL.prototype.needsRefresh = function () { * Refresh the layer, will be invoked by zrender */ LayerGL.prototype.refresh = function (bgColor) { + if (this.renderer.gl.isContextLost()) { + console.log('context lost, resetting renderer') + this.resetRenderer(); + } + + // make sure global renderer canvas size matches this layer + this.renderer.resize(this.zr.painter.getWidth(), this.zr.painter.getHeight()); this._backgroundColor = bgColor ? graphicGL.parseColor(bgColor) : [0, 0, 0, 0]; this.renderer.clearColor = this._backgroundColor; From abe3acc39fdd98fe48907741eb7e94c363754774 Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:34:55 +0100 Subject: [PATCH 3/6] shared-webgl-context: fix for render after accumulating where other plots could affect the background color --- src/core/LayerGL.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/LayerGL.js b/src/core/LayerGL.js index e850dd3c..e6dcdd44 100644 --- a/src/core/LayerGL.js +++ b/src/core/LayerGL.js @@ -282,6 +282,14 @@ LayerGL.prototype.renderToCanvas = function (ctx) { }; LayerGL.prototype._doRender = function (accumulating) { + if (this.renderer.gl.isContextLost()) { + console.log('context lost, resetting renderer') + this.resetRenderer(); + } + + // Needed in case we are not directly called from render() + this.renderer.clearColor = this._backgroundColor; + this.clear(); this.renderer.saveViewport(); for (var i = 0; i < this.views.length; i++) { From c891309dfe2741d5d9f62060e628dc7c5eafec02 Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:35:54 +0100 Subject: [PATCH 4/6] shared-webgl-context: fix context being lost during accumulation; have to rerender completely --- src/core/LayerGL.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/LayerGL.js b/src/core/LayerGL.js index e6dcdd44..44557057 100644 --- a/src/core/LayerGL.js +++ b/src/core/LayerGL.js @@ -283,12 +283,17 @@ LayerGL.prototype.renderToCanvas = function (ctx) { LayerGL.prototype._doRender = function (accumulating) { if (this.renderer.gl.isContextLost()) { - console.log('context lost, resetting renderer') + console.log('context lost, resetting renderer and refreshing') this.resetRenderer(); + + // Context lost in the "middle" of rendering/accumulating; trigger full rerender + this.needsRefresh(); + return; } // Needed in case we are not directly called from render() this.renderer.clearColor = this._backgroundColor; + this.renderer.resize(this.zr.painter.getWidth(), this.zr.painter.getHeight()); this.clear(); this.renderer.saveViewport(); From 33edb15fe78c4d4274caa5788687bc6ed0453f7a Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:37:22 +0100 Subject: [PATCH 5/6] shared-webgl-context: quick fix for flowGL animation --- src/chart/flowGL/FlowGLView.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/chart/flowGL/FlowGLView.js b/src/chart/flowGL/FlowGLView.js index f8a78b59..37ab15c2 100644 --- a/src/chart/flowGL/FlowGLView.js +++ b/src/chart/flowGL/FlowGLView.js @@ -64,6 +64,9 @@ export default echarts.ChartView.extend({ __percent: 1 }) .during(function () { + if (self._renderer && self._renderer.gl.isContextLost()) { + self._renderer = self._layerGL.renderer; + } var timeNow = + (new Date()); var dTime = Math.min(timeNow - time, 20); time = time + dTime; @@ -94,6 +97,7 @@ export default echarts.ChartView.extend({ afterRender: function (globeModel, ecModel, api, layerGL) { var renderer = layerGL.renderer; this._renderer = renderer; + this._layerGL = layerGL; }, _updateData: function (seriesModel, api) { From 69b31512d249c56f9438032b12fd3ea9473d167a Mon Sep 17 00:00:00 2001 From: Muck van Weerdenburg Date: Tue, 1 Feb 2022 08:38:17 +0100 Subject: [PATCH 6/6] shared-webgl-context: added test case with multiple plots and controls to trigger lost contexts --- test/multi.html | 413 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 test/multi.html diff --git a/test/multi.html b/test/multi.html new file mode 100644 index 00000000..30406c55 --- /dev/null +++ b/test/multi.html @@ -0,0 +1,413 @@ + + + + + Multiple plots - ECHARTS-GL + + + + + + +
+ x + + +
+
+ + +