[英]Using javascript to detect device CPU/GPU performance?
(The question is not specific to three.js but I will use it as an example) (这个问题不是针对 three.js 的,但我会以它为例)
I have been using three.js to develop a web app interface lately and written some nice fallback between WebGL and Canvas renderer (for desktop browsers).我最近一直在使用 three.js 开发 web 应用程序界面,并在 WebGL 和 Canvas 渲染器(用于桌面浏览器)之间编写了一些不错的后备。
But now the problem becomes how to properly detect device capability, there are 2 aspects to the problem:但是现在问题变成了如何正确检测设备能力,问题有两个方面:
A notable example : Firefox mobile/Opera mobile claims support of WebGL but are buggy or limited by device hardware.一个值得注意的例子:Firefox 移动/Opera 移动声称支持 WebGL,但存在错误或受设备硬件限制。
A few workarounds I come up with so far:到目前为止,我提出了一些解决方法:
Or maybe it doesn't have to be this hard, are there other suggestions?或者也许它不必这么难,还有其他建议吗?
I've ended up using a performance measurement approach on a project where we wanted to utilise canvas features that are available on high spec CPU/GPU desktops, as well as lower speed devices such as tables and phones. 我最终在一个项目中使用了性能测量方法,我们希望利用高规格CPU / GPU桌面上的画布功能,以及桌面和手机等低速设备。
Basically we start at a minimum scene complexity, and if the renderloop takes less than 33ms we add complexity (we also reduce complexity if the renderloop starts taking too long at a later time). 基本上我们从最小的场景复杂度开始,如果renderloop花费不到33ms,我们就增加了复杂性(如果renderloop以后开始花费太长时间,我们也会降低复杂性)。
I suppose in your case you might have to run a quick canvas and webgl performance test and then choose one. 我想在您的情况下,您可能需要运行快速画布和webgl性能测试,然后选择一个。 Having spent some time researching this I've not come across some tricky non-obvious technique that solves this better.
花了一些时间研究这个我没有遇到一些棘手的非显而易见的技术,可以更好地解决这个问题。
您可以使用http://webglstats.com/进行WebGL硬件支持和功能检测。
If your using three.js you can just use the detector.js to find out if webgl is enabled. 如果您使用three.js,您可以使用detector.js来查明是否启用了webgl。 also staying away from the canvasrenderer will help.
也远离canvasrenderer将有所帮助。 use the webglrenderer or the softwarerender.
使用webglrenderer或softwarerender。 as they allow for more vertices.
因为它们允许更多顶点。 the softwarerender is fairly new and needs some work but can be used.
softwarerender相当新,需要一些工作但可以使用。
This is the snippet I wrote to benchmark webgl, using three.js:这是我使用 three.js 写给基准 webgl 的代码片段:
import {
Mesh,
MeshStandardMaterial,
PerspectiveCamera,
Scene,
SphereGeometry,
WebGLRenderer,
} from "three";
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export enum GPUPerformanceLevel {
HIGH = "HIGH",
LOW = "LOW",
}
/**
* Three.js based webgl benchmark
*
* In summary, the `run` method adds `meshPerStep` new spheres every step (frame)
* and measures the fps. If we're able to perform >=`thresholds.steps` of these
* steps, without the fps dropping below `thresholds.fps`, then we label the device
* `GPUPerformanceLevel.HIGH`.
*/
export class GPUBenchmark {
scene = new Scene();
material = new MeshStandardMaterial();
geometry = new SphereGeometry();
static thresholds = { fps: 10, steps: 40 };
static meshPerStep = 1000;
async run(debug = false): Promise<GPUPerformanceLevel> {
const camera = new PerspectiveCamera(75);
const renderer = new WebGLRenderer();
let tPrev = performance.now() / 1000;
let steps = 0;
let passedThreshold = false;
const animate = async () => {
const time = performance.now() / 1000;
const fps = 1 / (time - tPrev);
tPrev = time;
if (debug) {
console.log(`fps: ${fps} steps: ${steps}`);
}
if (
fps > GPUBenchmark.thresholds.fps &&
steps < GPUBenchmark.thresholds.steps
) {
requestAnimationFrame(animate);
this.step();
steps++;
renderer.render(this.scene, camera);
} else {
passedThreshold = true;
}
};
animate();
while (!passedThreshold) {
await sleep(1);
}
this.cleanup();
const level = GPUBenchmark.stepsToPerfLevel(steps);
if (debug) {
console.log("device benchmarked at level:", level);
}
return level;
}
private step() {
for (let i = 0; i < GPUBenchmark.meshPerStep; i++) {
const sphere = new Mesh(this.geometry, this.material);
sphere.frustumCulled = false;
this.scene.add(sphere);
}
}
private cleanup() {
for (const obj of this.scene.children) {
this.scene.remove(obj);
}
//@ts-ignore
this.scene = null;
this.material.dispose();
this.geometry.dispose();
//@ts-ignore
this.material = null;
//@ts-ignore
this.geometry = null;
}
private static stepsToPerfLevel(numSteps: number): GPUPerformanceLevel {
if (numSteps >= GPUBenchmark.thresholds.steps) {
return GPUPerformanceLevel.HIGH;
} else {
return GPUPerformanceLevel.LOW;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.