浏览器对活动的 WebGL 上下文的数量施加了限制。超过限制,浏览器将开始转储旧的上下文。我的理解是每个域都有限制以及总体最大值。
两个问题:
gma*_*man 10
没有可靠的方法来知道浏览器支持多少上下文,即使你知道它明天可能会改变,或者它可能会根据浏览器运行的机器的各种条件或浏览器自己的启发式改变,比如如果 vram 是低它允许更少的上下文。或者,如果最新的上下文使用太多资源,它会尝试通过丢失其他上下文来释放空间。
我个人的经验法则是浏览器至少支持 8 个上下文。这就是我建立网站的假设。
您可能会理解为什么存在限制。WebGL 应用程序使用大量资源。也许不是全部,但特别是游戏可以轻松使用 vram 的演出,并且 vram 不像普通 ram 那样容易虚拟化,特别是因为为了以某种方式在浏览器本身中显示结果,结果都必须使其相同过程。因此,由于它们可能未虚拟化,并且由于它们可以使用如此多的资源,因此浏览器需要限制一次可以创建的资源数量,以便为用户访问的最新页面释放资源。
有很多技术可以使用单个上下文来显示整个网页上的大量内容,这些内容在您链接到的问答中涵盖或引用。
你可以这样算:
const canvases = [];
let done;
function createCanvas() {
const canvas = document.createElement('canvas');
canvas.addEventListener('webglcontextlost', () => {
done = true;
console.log('num contexts:', canvases.length - 1);
});
const gl = canvas.getContext('webgl');
canvases.push(canvas);
}
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function main() {
while (!done) {
createCanvas();
await wait();
}
}
main();
Run Code Online (Sandbox Code Playgroud)
在我的 Macbook Pro Chrome 80、Firefox 75、Safari 13.1 和 iPhone 11 上的 Safari 上,都报告了 16 个上下文。Pixel 2 XL 上的 Android 上的 Chrome 81 报告为 8,同一设备上的 Firefox 报告为 9。但正如上面所说,所有这些数字明天甚至今天都可能在不同条件下发生变化。
无论浏览器的限制是什么,似乎是 Chrome 中的每个域,但 Firefox 和 Safari 中的每个页面。你可以在这里测试。打开 2 个窗口。在一个窗口中创建 16 个上下文,然后在另一个窗口中再创建一个。在 Chrome 中,只要在第二个窗口中创建了另一个上下文,您就会看到第一个窗口丢失了一个上下文。在 Firefox 和 Safari 中,每个窗口都有自己的限制。
我还发现其他行为有很多变化。在 Chrome 上,我预计如果我在一个窗口中创建 16 个上下文,在另一个窗口中创建 1 个,我会在第一个窗口中看到一个丢失,但是当我关闭第二个窗口时,我会看到在第一个窗口中恢复了一个丢失的上下文。我不。我不知道是否有任何事情会触发该上下文恢复。
在带有上面链接的代码的 Firefox 中,只要我在同一窗口中创建第 17 个上下文,它就会进入无限循环。它丢失了第一个上下文,该上下文注册要恢复,firefox 立即恢复它,这丢失了另一个上下文,重复。这似乎使它无法在 Firefox 中使用。
尝试另一个例子,我不保留对 canvases 的引用,这意味着它们可以被垃圾收集,我在 Firefox 中看到我从来没有收到上下文丢失事件,这是有道理的,因为我不再有对上下文的有效引用。没有理由发送丢失的上下文事件。另一方面,Chrome 仍然发送事件,这在技术上也没有错,因为我注册了该事件,所以事件本身仍然有一个参考,如果我不想知道我应该取消注册该事件。
显然,这是 WebGL 规范中指定和测试不足的部分。
看起来对于丢失的上下文,您真正可以做的唯一一件事就是通知用户他们得到了一个,并为他们提供了一个重新开始的按钮(创建一个新的或刷新页面)
const groups = [];
let done;
function createCanvas(parent, lostCallback) {
const canvas = document.createElement('canvas');
parent.appendChild(canvas);
canvas.addEventListener('webglcontextlost', lostCallback);
const gl = canvas.getContext('webgl');
return {canvas, gl};
}
function createGroup() {
const div = document.createElement('div');
const group = {div};
div.className = 'c';
document.body.appendChild(div);
function restore() {
div.innerHTML = '';
const {canvas, gl} = createCanvas(div, () => {
done = true;
group.gl = undefined;
div.innerHTML = "context lost, click to restore";
div.addEventListener('click', restore, {once: true});
});
group.gl = gl;
group.canvas = canvas;
}
restore();
groups.push(group);
}
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function main() {
while (!done) {
createGroup();
await wait();
}
}
function render() {
for (const {gl} of groups) {
if (!gl) {
continue;
}
gl.clearColor(Math.random() * 0.5 + 0.5, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
main();
Run Code Online (Sandbox Code Playgroud)
.c {
display: inline-block;
border: 1px solid black;
margin: 1px;
font-size: xx-small;
}
canvas {
width: 100px;
height: 10px;
display: block;
}
Run Code Online (Sandbox Code Playgroud)
另请注意,WebGL 失去上下文的原点是 WebGL 无法控制操作系统。例如,在 Windows 中,如果任何应用程序在 GPU 上执行一些耗时过长的操作,操作系统本身将重置 GPU,这实际上会丢失所有应用程序的上下文,而不仅仅是您的浏览器。所有应用程序。浏览器无法阻止这种情况发生,因此浏览器只需将该信息传递给您的网页。同样在 Windows 中,您无需重新启动即可启用/禁用 GPU。这是浏览器无法控制并且只需要告诉您上下文丢失的另一种情况。
归档时间: |
|
查看次数: |
1266 次 |
最近记录: |