簡體   English   中英

使用 javascript 檢測設備 CPU/GPU 性能?

[英]Using javascript to detect device CPU/GPU performance?

(這個問題不是針對 three.js 的,但我會以它為例)

我最近一直在使用 three.js 開發 web 應用程序界面,並在 WebGL 和 Canvas 渲染器(用於桌面瀏覽器)之間編寫了一些不錯的后備。

但是現在問題變成了如何正確檢測設備能力,問題有兩個方面:

  1. 瀏覽器功能(靜態功能,如 webgl/canvas):這在 web 社區中使用簡單的功能檢測在很大程度上得到了解決。
  2. 設備能力:這是困難的部分,如果不能直接訪問設備的硬件信息,我們需要一些方法來判斷我們是否應該回退到對硬件要求較低的代碼。

一個值得注意的例子:Firefox 移動/Opera 移動聲稱支持 WebGL,但存在錯誤或受設備硬件限制。

到目前為止,我提出了一些解決方法:

  1. 使用通用功能作為性能指標- 例如,觸摸設備通常具有不太強大的硬件。 缺點:它不是面向未來的。
  2. 黑名單已知有問題的瀏覽器/設備- UA 嗅探將是不可避免的,並且可能難以維護。
  3. 性能測試——因此問題是,除了運行代碼和測量幀率之外,還有更好的選擇嗎?

或者也許它不必這么難,還有其他建議嗎?

我最終在一個項目中使用了性能測量方法,我們希望利用高規格CPU / GPU桌面上的畫布功能,以及桌面和手機等低速設備。

基本上我們從最小的場景復雜度開始,如果renderloop花費不到33ms,我們就增加了復雜性(如果renderloop以后開始花費太長時間,我們也會降低復雜性)。

我想在您的情況下,您可能需要運行快速畫布和webgl性能測試,然后選擇一個。 花了一些時間研究這個我沒有遇到一些棘手的非顯而易見的技術,可以更好地解決這個問題。

您可以使用http://webglstats.com/進行WebGL硬件支持和功能檢測。

如果您使用three.js,您可以使用detector.js來查明是否啟用了webgl。 也遠離canvasrenderer將有所幫助。 使用webglrenderer或softwarerender。 因為它們允許更多頂點。 softwarerender相當新,需要一些工作但可以使用。

這是我使用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM