以毫秒为单位测量WebGL纹理负载



如何以毫秒为单位测量WebGL纹理负载?

现在,我有一组图像,这些图像将使用游戏循环渲染为地图,我感兴趣的是捕捉WebGL加载每个纹理图像所需的时间(以毫秒为单位)。我想知道如何衡量这一点,因为JavaScript与WebGL并不同步。

在WebGL中测量任何时间的唯一方法是计算出在一定时间内可以做多少工作。选择一个目标速度,比如每秒30帧,使用requestAnimationFrame,不断增加工作量,直到超过目标。

var targetSpeed  = 1/30;
var amountOfWork = 1;
var then = 0;
function test(time) {
time *= 0.001;  // because I like seconds 
var deltaTime = time - then;
then = time;
if (deltaTime < targetTime) {
amountOfWork += 1;
}
for (var ii = 0; ii < amountOfWork; ++ii) {
doWork();
}
requestAnimationFrame(test);
}
requestAnimationFrame(test);

这并没有那么简单,因为浏览器,至少根据我的经验,似乎并没有给帧一个真正稳定的时间。

注意事项

  1. 不要假设requestAnimationFrame的帧速率为60fps。

    有很多设备运行速度更快(VR)或更慢(低端高清dpi显示器)。

  2. 在停止之前,不要测量开始发出命令的时间

    测量自上次请求AnimationFrame以来的时间。WebGL只是将命令插入缓冲区。这些命令在驱动程序中执行甚至可能在另一个过程中

    var start = performance.now;         // WRONG!
    gl.someCommand(...);                 // WRONG!
    gl.flush(...);                       // WRONG!
    var time = performance.now - start;  // WRONG!
    
  3. 实际使用资源。

    许多资源都是延迟初始化的,所以只需上传一个资源但不使用它不会给你一个准确的测量。你会需要对上传的每个纹理进行绘制。当然用一个简单的着色器绘制一个小的1像素1三角形。这个着色器必须实际访问资源,否则驱动程序我不做任何懒惰的初始化。

  4. 不要认为不同类型/大小的纹理会成比例速度的变化。

    不同事物的驱动因素。例如,一些GPU可能不支持除了RGBA纹理。如果上传LUMINANCE纹理驱动程序将把它扩展到RGBA。因此,如果您使用RGBA纹理计时并假设上传相同尺寸的LUMINANCE纹理速度是错误的4倍

    同样,不要假设不同大小的纹理将在速度与它们的大小成正比。驱动器内部缓冲器其他限制意味着不同的大小可能会有所不同路径。

    换句话说,你不能假设1024x1024纹理会上传速度是512x512纹理的4倍。

  5. 请注意,即使这样也不会承诺真实世界的结果

    我的意思是,例如,如果你使用平铺的硬件(iPhone那么GPU的工作方式是收集所有绘图命令,将它们分离为平铺,剔除任何绘制不可见的,只绘制剩下的作为大多数桌面GPU绘制每个三角形的每个像素。

    因为平铺的GPU最后一切都完成了,这意味着如果你继续上传数据到相同的纹理,并在每次上传之间绘制在绘制之前,必须保留所有纹理的副本。在内部,它可能会在某个时间点刷新和在再次缓冲之前提取它所拥有的。

    即使是桌面驱动程序也希望通过管道上传,因此您可以上传内容到纹理B,绘制,将新内容上传到纹理B,画如果驾驶员正在绘制第一幅图它不想等待GPU以便替换内容。相反,它只是想将新内容上传到其他地方没有使用,然后它可以将纹理指向新的目录

    在正常使用中,这不是问题,因为几乎没有人上传大量的纹理。他们最多上传1或2个视频帧或1或2个程序生成的纹理。但当你基准测试你在给驾驶员施加压力并让它做事它实际上不会正常运行。在上面的例子中,它可能假设一个纹理不太可能一帧上传10000次你将达到一个极限,它必须冻结管道,直到将绘制一些排队的纹理。冻结会使你的结果看起来比正常情况下要慢用例。

    重点是,你可能会基准测试,并被告知需要5毫秒上传一个纹理,但实际上只需要3毫秒,你只需要停滞了很多次的管道,而在您的基准之外不太可能发生。

最新更新