【发布时间】:2021-01-04 20:25:00
【问题描述】:
我正在研究可以使用bufferData 和STATIC_DRAW 上传到WebGL 1 应用程序的顶点数据量的实际上限。我准备了一个 sn-p,可让您将每帧推送的三角形数量从 0 调整为 10'000'000。我没有使用更高效的bufferSubData 和STREAM_DRAW 选项,因为我真的想体验最坏的情况。另外,我在屏幕上绘制的三角形非常小,因此填充率不会严重影响结果。
const canvas = document.createElement("canvas");
canvas.width = 320;
canvas.height = 180;
canvas.style.border = "1px solid black";
const gl = canvas.getContext("webgl");
document.body.appendChild(canvas);
const MAX_TRIANGLES = 10000000;
document.body.appendChild(document.createTextNode("Triangles to upload each frame: "));
const range = document.createElement("input");
range.type = "range";
range.min = 0;
range.max = MAX_TRIANGLES;
range.value = 100;
document.body.appendChild(range);
let nTriangles = range.value;
range.addEventListener("input", () => {
nTriangles = range.value;
});
const mbPerFrame = document.createElement("div");
document.body.appendChild(mbPerFrame);
const fps = document.createElement("div");
document.body.appendChild(fps);
gl.clearColor(0.2, 0.3, 0.5, 1.0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
const vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, "attribute vec2 a_position; void main(void) { gl_Position = vec4(a_position / 100.0, 0.0, 1.0); }");
gl.compileShader(vs);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, "precision mediump float; void main(void) { gl_FragColor = vec4(0.05, 0.0, 0.0, 0.05); }");
gl.compileShader(fs);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 8, 0);
gl.enableVertexAttribArray(0);
const randomVertexData = new Float32Array(3 * 2 * MAX_TRIANGLES);
for (let i = 0; i < 3 * MAX_TRIANGLES; i++) {
randomVertexData[i * 2 + 0] = Math.random() * 2 - 1;
randomVertexData[i * 2 + 1] = Math.random() * 2 - 1;
}
gl.useProgram(program);
const frameTimes = new Set();
function frame() {
frameTimes.add(performance.now());
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(randomVertexData.buffer, 0, nTriangles * 3 * 2), gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, nTriangles * 3);
requestAnimationFrame(frame);
}
setInterval(() => {
const now = performance.now();
let framesLastSecond = 0;
frameTimes.forEach((frameTime) => {
if (now - frameTime < 1000) {
framesLastSecond++;
} else {
frameTimes.delete(frameTime);
}
});
mbPerFrame.innerText = `${Math.floor((nTriangles * 3 * 2 * 4 / (1024 * 1024)) * 100) / 100} MB per frame`;
fps.innerText = `${framesLastSecond} FPS`;
}, 1000);
requestAnimationFrame(frame);
渲染循环基本上是这样做的:
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(randomVertexData.buffer, 0, nTriangles * 3 * 2), gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, nTriangles * 3);
其中randomVertexData是一些预先准备好的数据,nTriangles是由滑块控制的。
当您向右滑动滑块时,您会看到以 MB 为单位的大小增加而帧速率下降。
在我的机器(配备 i7 vPro 和 Quadro M1000 的戴尔笔记本电脑)上,每帧上传 30 MB 仍然会产生 60 FPS,这对于我的应用程序来说已经绰绰有余了。在我的智能手机(摩托罗拉 G7 Power)上,每帧上传 4 MB 仍然会产生 60 FPS。
问题
- 我是否正确设计了这个性能实验?
- 我可以信任/将其结果扩展到现实世界吗?
- 您认为 2020 年中端移动设备和笔记本电脑每帧推送多少数据是合理的?
【问题讨论】:
-
snippet 比 codepen 更有用。站点规则实质上是说,如果您要询问的代码不在问题本身中,则问题不在主题范围内。您是在询问您的性能测试是否正确,但性能测试的代码不在问题本身中。
-
谢谢@gman,很棒的建议。我将代码转换为sn-p。我在想也许 1) 本身更像是一个 CodeReview 问题,但我认为 1) 2) 3) 的精神作为一个整体更适合 StackOverflow。