首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在不同的移动设备/架构上测量Drawcall性能-使用discard()的着色器,还是将顶点放置在远平面之外?

在不同的移动设备/架构上测量Drawcall性能-使用discard()的着色器,还是将顶点放置在远平面之外?
EN

Stack Overflow用户
提问于 2019-05-02 16:01:32
回答 1查看 125关注 0票数 1

我希望在移动设备/架构的WebGL中测量着色器性能。

我知道在着色器中使用'discard()‘效率不是很高,但我想进行一些实验,并获得一些关于着色器在绘制调用方面的性能的数字--其中一个主要标准是在使用'discard()’或只是将对象/顶点放置在平台体的远平面之外时,测量不同移动设备和架构(iPhone、iPad以及瓦片渲染和延迟渲染)的性能。

我是Javascript/WebGL的新手,因此我想请教一些指针,或者可能有人已经有了一些类似的测试,我可以在这些测试的基础上获得一些数字。我还没有在互联网上遇到过这样的片段。任何使用THREE.js或typescript或纯js示例的东西都可以作为入门模板。

谢谢,任何指针都将不胜感激。

谢谢

EN

回答 1

Stack Overflow用户

发布于 2019-05-02 22:59:08

您可以像这样调用gl.readPixels来衡量哪个更快

代码语言:javascript
复制
const startTime = performance.now();
drawLotsOfStuff();
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
const endTime = performance.now();
const elaspedTimeInMilliseconds = endTime - startTime();

这不会告诉你渲染的速度,但它可能会告诉你哪种方法更快。

WebGL是多进程的,特别是在Chrome中。默认情况下,当你只是在一个60fps的应用程序中不断渲染时,一切都有可能并行运行。JavaScript正在调用gl.drawXXX,之前的绘制命令是并行运行的。但是,当您调用gl.readPixels时,必须停止整个并行部分,以便在读取数据之前执行前面的所有绘制命令。

这意味着使用gl.readPixels并不能告诉你某个东西的运行速度有多快。它会告诉你花了多少时间

start 2 or 3 processes

  • coordinate commands

  • wait processes

  • synchronice processes

  • transfer

2 or 3 commands

  1. wait processes
  2. synchronice processes
  3. transfer data from a
    1. 发出一些命令,让这些命令执行
    2. stop将两个进程的数据都从一个进程发送到另一个进程

如果你想知道什么东西画得有多快,你只想对上面的步骤4进行计时,但基于事物是并行的事实,你可以在计时中包括步骤1.、2.、3.、5.、6.和7.。

尽管如此,假设所有这些都是常量,你至少可以知道步骤3比其他步骤3更快还是更慢。

我说可能是因为浏览器中发生了很多事情。可能会出现垃圾收集问题,或者添加更多步骤的其他事情,这会导致时间不佳。

另一个问题是浏览器会,或者至少是故意返回低分辨率的结果来计时。这是为了减轻Spectre issues。我认为Chrome已经重新打开了高分辨率的结果,因为他们增加了进程隔离,尽管不确定。

让我们测试一下,看看是否得到了一致的结果

代码语言:javascript
复制
function main() {
  const gl = document.createElement('canvas').getContext('webgl');

  const vs = `
  attribute vec4 position;
  void main() {
    gl_PointSize = 128.0;
    gl_Position = position;
  }
  `;

  const fastFS = `
  precision highp float;
  void main() {
    gl_FragColor = vec4(1);
  }
  `;

  const slowFS = `
  precision highp float;
  // these are here to try to make sure the loop
  // is not optimized. (though it could still easily
  // be as it's really just color = junk * moreJunk * 100
  uniform vec4 junk;
  uniform vec4 moreJunk;

  void main() {
    vec4 color = vec4(0);
    for (int i = 0; i < 100; ++i) {
      color += junk * moreJunk;
    }
    gl_FragColor = color;
  }
  `;

  const locations = ['position']; // make position location 0
  const fastPrg = twgl.createProgram(gl, [vs, fastFS], locations);
  const slowPrg = twgl.createProgram(gl, [vs, slowFS], locations);

  const fastTime = time(gl, 'fast', fastPrg);
  const slowTime = time(gl, 'slow', slowPrg);

  // Because Safari is the new IE we can't not have attirbutes
  // as Safari fails the WebGL conformance tests for no attribute
  // situations.
  {
    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    gl.bufferData(gl.ARRAY_BUFFER, 1000000, gl.STATIC_DRAW);

    const posLoc = 0;  // assigned in createProgramInfo
    gl.enableVertexAttribArray(posLoc);
    // only taking X from buffer
    gl.vertexAttribPointer(posLoc, 1, gl.FLOAT, false, 0, 0);
  }

  const fastX = slowTime / fastTime;
  console.log(`fast is maybe ${fastX.toFixed(4)}x faster than slow`);
  console.log(gl.getError());

  function time(gl, label, prg) {
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE);
    gl.useProgram(prg);
    // use program once so any initialization behind the scenes
    // happens (voodoo)
    gl.drawArrays(gl.POINTS, 0, 1);
    sync(gl);
    const startTime = performance.now();
    for (let i = 0; i < 100; ++i) {
      gl.drawArrays(gl.POINTS, 0, 1000);
    }
    sync(gl);
    const endTime = performance.now();
    const elapsedTime = endTime - startTime;
    console.log(label, 'elapsedTime:', elapsedTime.toFixed(4));
    return elapsedTime;
  }
  
  function sync(gl) {
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
  }  
}
main();
代码语言:javascript
复制
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

当我运行上面的时候,我得到了从3.5x到4.5x的快速着色器比慢速着色器的结果,所以你可以看到结果不一致,但至少我们知道快速着色器实际上比慢速着色器更快,这足以让我们选择一种方法而不是另一种方法。

当然,在不同的GPU上结果可能会有所不同。在iOS上尤其如此,因为iOS设备使用。即使我们要求系统在每次绘制调用和100个绘制调用中绘制100个四边形,换句话说,10000个四边形,平铺渲染器也可能意识到它只需要绘制最后一个四边形。一种解决方法可能是打开与

代码语言:javascript
复制
gl.enable(gl.BLEND);

这样,我相信平铺渲染器不能只渲染最后一个四边形。

不幸的是,当我在iOS上运行上面的例子时,我得到的结果是快比慢,这表明(1)浏览器中的计时分辨率是多么糟糕,或者(2)不同的平铺架构是如何工作的,或者(3) iOS驱动程序实际上确实优化了循环。

让我们通过在内部循环中使用纹理来使慢速着色器变得更慢,这样我们实际上必须在每次循环迭代时查找不同的结果。

代码语言:javascript
复制
function main() {
  const gl = document.createElement('canvas').getContext('webgl');

  const vs = `
  attribute vec4 position;
  void main() {
    gl_PointSize = 128.0;
    gl_Position = position;
  }
  `;

  const fastFS = `
  precision highp float;
  void main() {
    gl_FragColor = vec4(1);
  }
  `;

  const slowFS = `
  precision highp float;
  uniform vec4 junk;
  uniform vec4 moreJunk;
  uniform sampler2D tex;

  void main() {
    vec4 color = vec4(0);
    for (int i = 0; i < 100; ++i) {
      // AFAIK this can not be optimized too much as the inputs
      // change over the loop looking up different parts of the texture.
      color += texture2D(tex, fract(junk * moreJunk * float(i)).xy * gl_PointCoord.xy);
    }
    gl_FragColor = color;
  }
  `;

  const fastPrg = twgl.createProgram(gl, [vs, fastFS]);
  const slowPrg = twgl.createProgram(gl, [vs, slowFS]);

  // Because Safari is the new IE we can't not have attirbutes
  // as Safari fails the WebGL conformance tests for no attribute
  // situations.
  {
    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    gl.bufferData(gl.ARRAY_BUFFER, 1000000, gl.STATIC_DRAW);

    const posLoc = 0;  // assigned in createProgramInfo
    gl.enableVertexAttribArray(posLoc);
    // only taking X from buffer
    gl.vertexAttribPointer(posLoc, 1, gl.FLOAT, false, 0, 0);
  }

  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  const data = new Uint8Array(1024 * 1024 * 4);
  for (let i = 0; i < data.length; ++i) {
    data[i] = Math.random() * 256;
  }
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1024, 1024, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
  gl.generateMipmap(gl.TEXTURE_2D);

  const fastTime = time(gl, 'fast', fastPrg);
  const slowTime = time(gl, 'slow', slowPrg);

  const fastX = slowTime / fastTime;
  console.log(`fast is maybe ${fastX.toFixed(4)}x faster than slow`);

  function time(gl, label, prg) {
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE);
    gl.useProgram(prg);
    // use program once so any initialization behind the scenes
    // happens (voodoo)
    gl.drawArrays(gl.POINTS, 0, 1);
    sync(gl);
    const startTime = performance.now();
    for (let i = 0; i < 100; ++i) {
      gl.drawArrays(gl.POINTS, 0, 1000);
    }
    sync(gl);
    const endTime = performance.now();
    const elapsedTime = endTime - startTime;
    console.log(label, 'elapsedTime:', elapsedTime.toFixed(4));
    return elapsedTime;
  }

  function sync(gl) {
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
  }

}
main();
代码语言:javascript
复制
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

现在在我的iPhoneX上,我发现快比慢快得多。

那么,我们学到了什么呢?我们可能了解到,如果您的着色器具有类似的性能级别,则很难可靠地区分哪个更快。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55948019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档