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

Posted

技术标签:

【中文标题】以毫秒为单位测量 WebGL 纹理负载【英文标题】:Measure WebGL texture load in ms 【发布时间】:2015-04-23 09:53:34 【问题描述】:

如何?

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

【问题讨论】:

这对您有什么帮助?你会检查那里的机器和驱动程序的数百万种变化吗?例如,在运行 android 5.0.1 与 5.0.2 的 Nexus 5 与运行不同操作系统的三星 Galaxy Note 6 与 iPhone、iPad 的每个型号、每个操作系统以及 Mac 的每个型号上上传纹理需要多长时间操作系统,然后是所有具有不同 cpu、不同 gpus、不同驱动程序等的各种 windows 机器......我问是因为无论你试图解决什么问题,都不清楚在一台机器上测量上传时间会有什么帮助 这是我做的一项研究工作。我需要来自我构建的 webgl 测试应用程序的那种数据。 你还没有回答我的问题。这些数据有什么意义?如果你得到 1ms 的答案,这对你有什么帮助,因为它对其他机器毫无用处,并且 JavaScript 无法找出用户使用的是哪种机器。 测试在特定设备上运行。在 Canvas 和 WebGL 图形中对特定场景进行测量。将发出许多请求,上下文切换可能会成为 WebGL 的成本。这是我所做研究的一部分。对于我对 GPU 的测量的这个问题,了解研究的内容是无关紧要的。 这是相关的,因为答案对于所有用例的 99.999999% 来说都是无用的。您在浏览器中运行超过一百万种硬件组合。即使是原生游戏也不会这样做。他们只是让用户选择各种图形选项,因为变化太多,不知道是否会太慢。 【参考方案1】:

在 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);

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

注意事项

    不要假设 requestAnimationFrame 会是 60fps。

    有很多设备运行得更快 (VR) 或更慢(低端 hd-dpi 显示器)。

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

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

    var start = performance.now;         // WRONG!
    gl.someCommand(...);                 // WRONG!
    gl.flush(...);                       // WRONG!
    var time = performance.now - start;  // WRONG!
    

    实际使用资源。

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

    不要假设不同类型/大小的纹理会有比例 速度变化。

    不同事物的驱动力。例如,某些 GPU 可能不支持 除了 RGBA 纹理之外的任何东西。如果您上传 LUMINANCE 纹理 驱动程序会将其扩展为 RGBA。因此,如果您使用 RGBA 纹理进行计时 并假设将上传相同尺寸的 LUMINANCE 纹理 4 倍速度你会错的

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

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

    请注意,即使这样也不能保证真实世界的结果

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

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

    即使是桌面驱动程序也希望通过管道上传,所以您上传 内容到纹理 B,绘制,将新内容上传到纹理 B, 画。如果司机正在做第一次绘图 它不想等待 GPU 来替换内容。 相反,它只是想将新内容上传到其他地方 没有被使用,然后当它可以将纹理指向新的 内容。

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

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

【讨论】:

以上是关于以毫秒为单位测量 WebGL 纹理负载的主要内容,如果未能解决你的问题,请参考以下文章

/usr/bin/time --format 输出经过的时间,以毫秒为单位

System类

以毫秒为单位获取以毫秒为单位的午夜纪元时间

如何从以毫秒为单位的长度中找到以帧、字节和整数为单位的音符长度

如何在 PHP 中以毫秒为单位获取当前时间?

命令以毫秒为单位获取时间