测量WebGL帧延迟

时间:2018-10-20 23:29:04

标签: profiling webgl

我已经在WebGL中编写了GPU路径跟踪器,并希望查看渲染单个帧需要多长时间。我该如何在台式机和移动浏览器上进行移植?

我对如何执行此操作有一些想法,但都无济于事:


想法1:测量完成之间的延迟时间:

gl.finish(); var t0=performance.now();
//(render)
gl.finish(); var t1=performance.now();
var latency = 0.001*( t1 - t0 );

这不起作用! Chrome(在用途上极其错误地)aliases gl.finish()gl.flush(),因此测得的延迟与完成的工作几乎没有关系。


想法2:Use EXT_disjoint_timer_query / EXT_disjoint_timer_query_webgl2

这不起作用! {@ 3}在Rowhammer式攻击中被滥用,因此can be used


想法3:使用performance.now()测量两次调用window.requestAnimationFrame(...)的时间。

这不起作用!由于渲染成本很高,出于功率/热量的原因,我仅在发生某些更改(例如相机位置)时才重新绘制帧。因此,所测得的延迟可能会很大(并且无论如何都会在下一个帧中报告)。

1 个答案:

答案 0 :(得分:1)

您无法从浏览器内部检查延迟。无法知道图像何时真正出现在屏幕上。浏览器可能是双缓冲或三缓冲的,操作系统本身通常具有复合步骤,因此如果用户在电视上进行帧插值也可能添加帧,则可以添加帧。也许您实际上并不是要测量“延迟”,但是如果您确实要测量“延迟”,则只能使用外部设备进行测量。

即使在OpenGL中,也无法直接使用gl.finish测量渲染时间。您将不会测量“渲染”时间。您将测量“启动时间” +“渲染时间” +“停止时间”,因此您可以使用gl.finish来确定一种技术是否比另一种更快,但是您不能使用gl.finish找出帧的速度,因为在正常操作中,图形是流水线的,跨多个线程或进程运行。调用gl.finish会增加同步这些线程和进程的开销,这可能不仅仅是渲染。

您可能会使用gl.finish定时来渲染最小的东西(单个1像素三角形的纯色)。用它来测量“同步”多个线程的开销,并从较长渲染的较长时间中减去该时间,但即使在平铺架构GPU上也存在问题,因为平铺架构GPU使用了避免过度绘制的技术。

换句话说,如果您在传统GPU上绘制2个重叠的不透明三角形,则将绘制两个三角形的每个像素,但在平铺的GPU上,重叠像素将仅绘制一次。这意味着单独定时绘制特定图形不会告诉您它们组合时的速度。

在任何情况下,您都可以通过调用gl.finish来模拟gl.readPixels(使所有进程陷入僵局)来读取单个像素,因为为了使该像素到达JavaScript,必须停止并同步所有进程

如上所述,您应该首先绘制一个像素来测量同步过程的开销,然后从测量中减去该时间。

您也不应该使用第一个测量值并绘制几次,因为许多事情都是延迟初始化的,因此您进行任何内容的第一个渲染都可能比第二个渲染慢。

因此,步骤将类似于

  1. 初始化webgl和您的所有资源
  2. 使用简单的着色器绘制单个像素
  3. 绘制要测量的东西
  4. gl.readPixels一个像素(刷新以前的内容)
  5. syncStart = performance.now()
  6. 使用简单的着色器绘制单个像素
  7. gl.readPixels一个像素
  8. syncTime = performance.now()-syncStart
  9. drawStart = performance.now()
  10. 绘制要测量的东西
  11. gl.readPixels一个像素
  12. renderTime =(performance.now()-drawStart)-syncTime

第2步和第3步将强制执行任何隐藏的初始化,因此请确保在第2步和第3步中使用了所有资源,使用了所有纹理,使用了所有缓冲区,等等。