如何避免 webGL 着色器加载对 cpu 施加过多负载

how to avoid webGL shader loading putting too much load on cpu

加载多个大型着色器程序时,webGl 会对 cpu 施加很大压力,使 UI 停滞,有时甚至会触发 chrome 的 cpu 杀死页面的看门狗。

我该怎么做才能在这种情况下显示 "loading" 屏幕并限制我的处理器使用率,以免被 chrome 抓到?

relevant section of code, which ultimately leads to these actual webGL calls:

var p = this.program = gl.createProgram();
gl.attachShader(p, this.makeShader(gl.VERTEX_SHADER, vertex));
gl.attachShader(p, this.makeShader(gl.FRAGMENT_SHADER, fragment));
gl.linkProgram(p);

一些想法

  1. 您可以尝试等待几帧查看结果

    var vs = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vs, vSource);
    gl.compileShader(vs);
    var fs = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fs, vSource);
    gl.compileShader(fs);
    var p = gl.createProgram();
    gl.attachShader(p, vs);
    gl.attachshader(p, fs);
    gl.linkProgram(p);
    gl.flush(); // Important!
    setTimeout(checkResults, 2000);  // check results 2 seconds later
    
    function checkResults() {
       var status = gl.getProgramParameter(p, gl.LINK_STATUS);
       ...
    }
    

    至少在 Chrome 这可能意味着 GPU 进程将编译程序,而渲染进程(运行 宁你的 JavaScript)将继续 运行 所以至少 JavaScript 不会阻塞,除非你检查结果时它还没有完成。

  2. 将内容分解成多个步骤

    var tasks = [];
    
    addTask(compileVertexShader);
    addTask(compileFragmentShader);
    addTask(linkProgram);
    addTask(render);
    
    function addTask(fn) {
      tasks.push(fn);
      runNextTask();
    }
    
    var taskRunning = false;
    function runNextTask() {
      if (taskRunning) {
        return;
      }
      var taskFn = tasks.shift();
      if (taskFn) {
        taskRunning = true;
        setTimeout(function() {
          taskRunning = false;
          taskFn();
          runNextTask();
        }, 1);
      }
    }
    
    function compileVertexShader() {
      ...
    }
    
    function compileFragmentShader() {
      ...
    }
    
    function linkProgram() {
      ...
    }
    
    function render() {
      ...
    }    
    

    只要一个功能不会花太长时间,就不会有任何问题。

    有一些常用库可以帮助处理此类问题。例如the async library.