如何防止 Chrome 在切换选项卡后处理(?)我的 webgl 绘图上下文?
How do I prevent Chrome from disposing(?) of my webgl drawing context after switching tabs?
Chrome(当前)出现意外问题。我有一个 Web 应用程序,它使用 webGL canvas 进行一些基本的图像处理,然后将 webGl canvas 复制到 2d canvas 以保存图像数据。问题是在我切换标签后,webgl canvas 的绘图上下文似乎在 Chrome 中丢失了。这在我尝试过的任何其他浏览器(FF、IE 11/Edge、Safari)中都不会发生。
如果确实发生了这种情况,我希望 Chrome 也会触发 webgl 上下文丢失事件,但我从未得到该事件。
这里有一个非常简单的 fiddle 来演示这个问题。
https://jsfiddle.net/JoeBlow/m14evgzj/
1) 加载绘制到 webgl 的页面 canvas
2) 切换到新标签页
3) 切换回原来的标签页
4) 单击'Copy Image'。
如果我重新初始化 3d canvas(重新加载所有内容并重新绘制),那么即使在标签切换之后一切都会按预期工作,但我试图避免捕获 blur/focus 事件window/viewport.
这是简化的代码:
window.canvasSource = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');
var canvasOptions = { preserveDrawingBuffer: true };
//var sourceContext = canvasSource.getContext("2d", options);
var destinationContext = canvasDestination.getContext("2d", canvasOptions);
window.canvasSource.addEventListener("webglcontextlost", function(event) {
console.log('context lost');
event.preventDefault();
}, false);
window.canvasSource.addEventListener("webglcontextrestored", init3d, false);
btnToggle.addEventListener('click', function() {
if (window.canvasSource.style.visibility != "hidden") {
window.canvasSource.style['visibility']='hidden';
}
else {
window.canvasSource.style['visibility'] = 'visible';
}
});
btnCopy.addEventListener('click', function() {
destinationContext.drawImage(window.canvasSource,0,0);
});
btnClear.addEventListener('click', function() {
destinationContext.clearRect(0,0, 1500, 1500);
});
btnInit3d.addEventListener('click', function() {
init3d();
});
function init3d() {
console.log('init3d()');
window.gl = window.canvasSource.getContext("webgl", canvasOptions);
var gl = window.gl;
if (gl==null)
console.log("couldn't get webgl context");
else
console.log(gl);
gl.viewport(0, 0, window.canvasSource.width, window.canvasSource.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);
program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
}
init3d();
我猜这个问题与 this one.
有关
显然,chrome 会在选项卡模糊时清除 drawingBuffer,即使您确实告诉它不要这样做。
一个可能的解决方法是为自己创建一个 preserveDrawingBuffer
对象。
2DContext 不受此错误的影响,因此您可以创建一个屏幕外 2D 上下文,而不是在您的 wegbl 启动时设置 preserveDrawingBuffer
,您将在其上绘制每个新的 webgl 上下文 draw
.
var canvasSource = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
//var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');
var gl;
// we don't need to preserve the drawing buffer anymore
// since we'll do it manually
//var canvasOptions = { preserveDrawingBuffer: true};
var bufferContext = canvasSource.cloneNode().getContext('2d');
// 2D context don't have an preserveDrawingBuffer option
var destinationContext = canvasDestination.getContext("2d");
btnCopy.addEventListener('click', function() {
var error = gl.getError();
if (error) {
console.log('Gl Error: ' + error);
}
// we draw the buffer canvas instead of the webgl one
destinationContext.drawImage(bufferContext.canvas, 0, 0);
});
btnClear.addEventListener('click', function() {
destinationContext.clearRect(0, 0, 1500, 1500);
});
function init3d() {
gl = canvasSource.getContext("webgl");
if (gl == null)
console.log("couldn't get webgl context");
gl.viewport(0, 0, canvasSource.width, canvasSource.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// at each draw, save the webgl state
bufferContext.drawImage(canvasSource, 0,0);
}
init3d();
<canvas id="source"> </canvas>
<canvas id="destination"> </canvas>
<div>
<button id="btnCopy">Copy Image</button>
<button id="btnClear">Clear Copy</button>
</div>
Chrome(当前)出现意外问题。我有一个 Web 应用程序,它使用 webGL canvas 进行一些基本的图像处理,然后将 webGl canvas 复制到 2d canvas 以保存图像数据。问题是在我切换标签后,webgl canvas 的绘图上下文似乎在 Chrome 中丢失了。这在我尝试过的任何其他浏览器(FF、IE 11/Edge、Safari)中都不会发生。
如果确实发生了这种情况,我希望 Chrome 也会触发 webgl 上下文丢失事件,但我从未得到该事件。
这里有一个非常简单的 fiddle 来演示这个问题。
https://jsfiddle.net/JoeBlow/m14evgzj/
1) 加载绘制到 webgl 的页面 canvas
2) 切换到新标签页
3) 切换回原来的标签页
4) 单击'Copy Image'。
如果我重新初始化 3d canvas(重新加载所有内容并重新绘制),那么即使在标签切换之后一切都会按预期工作,但我试图避免捕获 blur/focus 事件window/viewport.
这是简化的代码:
window.canvasSource = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');
var canvasOptions = { preserveDrawingBuffer: true };
//var sourceContext = canvasSource.getContext("2d", options);
var destinationContext = canvasDestination.getContext("2d", canvasOptions);
window.canvasSource.addEventListener("webglcontextlost", function(event) {
console.log('context lost');
event.preventDefault();
}, false);
window.canvasSource.addEventListener("webglcontextrestored", init3d, false);
btnToggle.addEventListener('click', function() {
if (window.canvasSource.style.visibility != "hidden") {
window.canvasSource.style['visibility']='hidden';
}
else {
window.canvasSource.style['visibility'] = 'visible';
}
});
btnCopy.addEventListener('click', function() {
destinationContext.drawImage(window.canvasSource,0,0);
});
btnClear.addEventListener('click', function() {
destinationContext.clearRect(0,0, 1500, 1500);
});
btnInit3d.addEventListener('click', function() {
init3d();
});
function init3d() {
console.log('init3d()');
window.gl = window.canvasSource.getContext("webgl", canvasOptions);
var gl = window.gl;
if (gl==null)
console.log("couldn't get webgl context");
else
console.log(gl);
gl.viewport(0, 0, window.canvasSource.width, window.canvasSource.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);
program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
}
init3d();
我猜这个问题与 this one.
有关显然,chrome 会在选项卡模糊时清除 drawingBuffer,即使您确实告诉它不要这样做。
一个可能的解决方法是为自己创建一个 preserveDrawingBuffer
对象。
2DContext 不受此错误的影响,因此您可以创建一个屏幕外 2D 上下文,而不是在您的 wegbl 启动时设置 preserveDrawingBuffer
,您将在其上绘制每个新的 webgl 上下文 draw
.
var canvasSource = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
//var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');
var gl;
// we don't need to preserve the drawing buffer anymore
// since we'll do it manually
//var canvasOptions = { preserveDrawingBuffer: true};
var bufferContext = canvasSource.cloneNode().getContext('2d');
// 2D context don't have an preserveDrawingBuffer option
var destinationContext = canvasDestination.getContext("2d");
btnCopy.addEventListener('click', function() {
var error = gl.getError();
if (error) {
console.log('Gl Error: ' + error);
}
// we draw the buffer canvas instead of the webgl one
destinationContext.drawImage(bufferContext.canvas, 0, 0);
});
btnClear.addEventListener('click', function() {
destinationContext.clearRect(0, 0, 1500, 1500);
});
function init3d() {
gl = canvasSource.getContext("webgl");
if (gl == null)
console.log("couldn't get webgl context");
gl.viewport(0, 0, canvasSource.width, canvasSource.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// at each draw, save the webgl state
bufferContext.drawImage(canvasSource, 0,0);
}
init3d();
<canvas id="source"> </canvas>
<canvas id="destination"> </canvas>
<div>
<button id="btnCopy">Copy Image</button>
<button id="btnClear">Clear Copy</button>
</div>