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

Measure WebGL texture load in ms

我如何测量以毫秒为单位的 WebGL 纹理加载?

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

在 WebGL 中衡量任何时间的唯一方法是计算出您在一定时间内可以完成多少工作。选择一个目标速度,比如 30fps,使用 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) 或更慢(low-end hd-dpi 显示器)。

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

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

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

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

  4. 不要假设不同的 types/sizes 纹理会成比例 速度变化。

    不同事物的驱动因素。例如,某些 GPU 可能不支持 除了 RGBA 纹理之外的任何东西。如果您上传 LUMINANCE 纹理 driver 会将其扩展为 RGBA。所以,如果你定时使用 RGBA 纹理 并假设将上传相同尺寸的 LUMINANCE 纹理 快 4 倍你就错了

    同样不要假设不同大小的纹理会上传到 速度与它们的大小成正比。 drivers 的内部缓冲区 和其他限制意味着不同的尺寸可能需要不同的 路径。

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

  5. 请注意,即使这样也不能保证 real-world 结果

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

    因为平铺 GPU 最后做所有这意味着如果你继续上传 数据到相同的纹理并在每次上传之间绘制 在绘制之前必须保留所有纹理的副本。 在内部,它可能会刷新并 在再次缓冲之前绘制它的内容。

    即使是台式机 driver 也想通过管道上传,所以您可以上传 内容到纹理B,绘制,上传新内容到纹理B, 画。如果 driver 正在绘制第一张图 它不想等待 GPU,因此它可以替换内容。 相反,它只是想将新内容上传到其他地方 不被使用然后当它可以将纹理指向新的 内容。

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

    重点是您可能会进行基准测试并被告知需要 5 毫秒 上传纹理但实际上只需要 3 毫秒,你只需 管道多次停滞,这超出了您的基准 不太可能发生。