鉴于 GPU 有任务队列并且是异步的,计算 FPS 的正确方法是什么?

2024-04-13

我始终认为计算 FPS 的正确方法是简单地计算绘制循环迭代所需的时间。互联网上的大部分内容似乎都是一致的。

But!

现代显卡被视为异步服务器,因此绘制循环会发出 GPU 上已有的顶点/纹理/等数据的绘制指令。这些调用不会阻塞调用线程,直到 GPU 上的请求完成为止,它们只是添加到 GPU 的任务队列中。那么“传统”(而且相当普遍)的方法肯定只是测量呼叫调度时间吗?

促使我问的是,我已经实现了传统方法,并且它始终提供荒谬的高帧速率,即使渲染的内容导致动画变得不稳定。重新阅读我的 OpenGL SuperBible 让我想到了 glGenQueries,它允许我对渲染管道的各个部分进行计时。

总而言之,计算 FPS 的“传统”方法是否在(几乎)现代显卡中完全失效了?如果是这样,为什么 GPU 分析技术相对不为人所知?


测量 fps 很困难。事实上,想要测量 fps 的不同人不一定想要测量相同的东西,这使得事情变得更加困难。所以问问自己这个问题。为什么你想要 fps 数字?

在我继续深入探讨所有陷阱和潜在解决方案之前,我确实想指出,这绝不是“现代显卡”特有的问题。如果说有什么不同的话,那就是过去的情况更糟,对于 SGI 类型的机器,渲染实际上发生在可能远离客户端的图形 Susb 系统上(如物理远程)。 GL1.0实际上是根据客户端-服务器来定义的。

无论如何。回到手头的问题。

fps,意思是每秒帧数,实际上是试图用一个数字来表达应用程序性能的粗略概念,这个数字可以与屏幕刷新率等直接相关。对于第一级的性能近似值,它做得还不错。一旦你想深入研究更细粒度的分析,它就会完全崩溃。

问题实际上是,就应用程序的“流畅感”而言,最重要的是您绘制的图片何时出现在屏幕上。第二件事也很重要,那就是从触发一个动作到其效果显示在屏幕上之间需要多长时间(总延迟)。

当应用程序绘制一系列帧时,它会在 s0、s1、s2、s3... 的时间提交它们,并最终在 t0、t1、t2、t3... 的时间显示在屏幕上。

为了感觉顺畅,您需要满足以下所有条件:

  1. tn-sn 不太高(延迟)
  2. t(n+1)-t(n) 很小(低于 30ms)
  3. 模拟增量时间也有一个严格的限制,我将在稍后讨论。

当您测量渲染的 CPU 时间时,您最终会测量 s1-s0 以近似 t1-t0。事实证明,这,一般,与事实相差不远,因为客户端代码永远不会“走得太远”(这是假设您一直在渲染帧。其他情况请参阅下文)。事实上,当 GL 试图走得太远时,它最终会阻塞 CPU(通常在 SwapBuffer 时间)。该阻塞时间大致是 GPU 相对于 CPU 在单帧上花费的额外时间。

如果您确实想测量 t1-t0,正如您在自己的帖子中提到的那样,查询更接近它。但是……事情从来没有那么简单。第一个问题是,如果您受 CPU 限制(意味着您的 CPU 不够快,无法始终为 GPU 提供工作),那么 t1-t0 时间的一部分实际上是 GPU 空闲时间。这不会被查询捕获。您遇到的下一个问题是,根据您的环境(显示合成环境、垂直同步),查询实际上可能只测量应用程序渲染到后台缓冲区所花费的时间,这不是完整的渲染时间(因为显示尚未被渲染)。当时就更新了)。它确实可以让您粗略地了解渲染需要多长时间,但也不会很精确。进一步注意,查询还受到图形部分的异步性的影响。因此,如果您的 GPU 在部分时间处于空闲状态,则查询可能会错过该部分。 (例如,假设您的 CPU 需要很长时间(100 毫秒)来提交帧。GPU 在 10 毫秒内执行完整帧。您的查询可能会报告 10 毫秒,即使总处理时间接近 100 毫秒...)。

现在,关于“基于事件的渲染”,而不是我到目前为止讨论的连续渲染。对于这些类型的工作负载,fps 没有多大意义,因为目标不是每秒绘制尽可能多的 f。 GPU 性能的自然指标是 ms/f。也就是说,这只是图片的一小部分。什么really重要的是从您决定要更新屏幕到发生更新所花费的时间。不幸的是,这个数字很难找到:它通常在您收到触发该过程的事件时开始,并在屏幕更新时结束(您只能使用捕获屏幕输出的相机来测量......)。

问题是,两者之间,CPU 和 GPU 处理之间可能存在重叠,或者没有重叠(甚至 CPU 停止提交命令和 GPU 开始执行命令之间存在一些延迟)。这完全取决于实施情况来决定。您能做的最好的事情就是在渲染结束时调用 glFinish 来确定 GPU 已完成处理您发送的命令,并测量 CPU 上的时间。该解决方案确实会降低 CPU 端的整体性能,如果您打算在...之后立即提交下一个事件,则可能还会降低 GPU 端的整体性能。

最后讨论“模拟增量时间的硬约束”:

典型的动画使用帧之间的增量时间来向前移动动画。主要问题是,对于完全平滑的动画,您确实希望在 s1 提交帧时使用的增量时间为 t1-t0 (这样当 t1 显示时,前一帧实际花费的时间确实是 t1 -t0)。当然,问题是您在提交 s1 时不知道 t1-t0 是什么……所以您通常使用近似值。许多人只使用 s1-s0,但这可能会崩溃 - 例如SLI 类型系统在不同 GPU 之间的 AFR 渲染中可能会出现一些延迟。您还可以尝试通过查询使用 t1-t0(或更可能是 t0-t(-1))的近似值。犯这个错误的结果很可能是在 SLI 系统上出现微卡顿。

最可靠的解决方案是“锁定到 30fps,并始终使用 1/30s”。它也是在内容和硬件上允许最小余地的一种,因为你have确保您的渲染确实可以在 33 毫秒内完成...但这就是一些控制台开发人员选择做的事情(固定硬件使其变得更简单)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

鉴于 GPU 有任务队列并且是异步的,计算 FPS 的正确方法是什么? 的相关文章

  • Prolog内存问题

    我想找到一种方法来分析我在序言中编写的谓词 一个巨大的谓词 的内存使用情况 我目前正在运行它swi http www swi prolog org and yap http www dcc fc up pt vsc Yap document
  • Glew+GLFW Win32 无依赖项 Visual Studio

    是否可以在不将文件复制到 C 的情况下构建并链接 Glew 和 GLFW 我找不到任何说明如何在不将 DLL 复制到 C 上的 Visual Studio 目录的情况下使用这些库的文档 我只想包含项目目录中所需的所有 dll 和 lib 文
  • 将 nvidia 运行时添加到 docker 运行时

    我正在运行虚拟机GCP配备特斯拉 GPU 并尝试部署一个PyTorch基于应用程序使用 GPU 加速 我想让 docker 使用这个 GPU 可以从容器访问它 我设法在主机上安装了所有驱动程序 并且该应用程序在那里运行良好 但是当我尝试在
  • 存储 OpenGL 状态

    假设我正在尝试用 C 制作某种小型 opengl 图形引擎 我读过通过访问 opengl 状态glGet 函数可能非常昂贵 虽然访问 opengl 状态似乎是一个经常操作 并且强烈建议将 opengl 状态的副本存储在具有快速读 写访问权限
  • OpenGL 3.1 中已弃用 glLineStipple

    glLineStipple在最新的 OpenGL API 中已被弃用 它被替换成什么 如果不更换 怎样才能达到类似的效果呢 我当然不想使用兼容性配置文件 抱歉 它还没有被任何东西取代 我想到的第一个模拟它的想法是几何着色器 您向几何着色器提
  • 在 OpenGL 中只使用纹理的 Alpha 通道?

    嘿 我正在尝试将恒定颜色绘制到帧缓冲区 并使用 RGBA 纹理中的 Alpha 通道将其混合 我一直在研究 glBlendFunc 和 glBlendColor 但似乎无法找到忽略纹理中的 RGB 值的方法 我想我必须自己提取 alpha
  • OpenGL,如何独立旋转对象?

    到目前为止我的代码 void display void glClear GL COLOR BUFFER BIT GL DEPTH BUFFER BIT Clear Screen And Depth Buffer glLoadIdentity
  • OpenSSL HMAC 函数中的意外复杂性

    SSL 文档分析 这个问题与 OpenSSL 中 HMAC 例程的使用有关 由于 Openssl 文档在某些领域有点薄弱 分析表明使用 unsigned char HMAC const EVP MD evp md const void ke
  • 如何从横滚、俯仰和偏航获取相机向上矢量?

    我需要从滚动角 俯仰角和偏航角 以度为单位 获取相机的向上矢量 以获得正确的外观 我已经尝试了几个小时不同的事情 但没有运气 这里的任何帮助将不胜感激 横滚 俯仰和偏航定义 3 轴旋转 从这些角度 您可以构建一个 3x3 变换矩阵来表达该旋
  • 纹理映射 C++ OpenGL

    我已经阅读了相关内容 包括 Nehe 和此处的解决方案 但我找不到具体的答案 我正在尝试加载一张名为stars jpg 的照片 我想通过使用 uv 坐标映射它来使其成为场景的背景 方法是 glBegin GL QUADS glTexCoor
  • 帧缓冲区/颜色缓冲区?

    有人可以指出我两者是否相同吗 我的意思是我一直在阅读有关它的信息 这里的红皮书说 颜色缓冲区本身可以由多个子缓冲区组成 系统上的帧缓冲区包含所有这些缓冲区 here http glprogramming com red chapter10
  • 如何在 GLSL 1.3 和 OpenGL 2.1 中使用位运算

    我正在尝试编写一个使用许多位操作的着色器 事实上 从 glsl 1 30 开始就支持它们 但我只使用 OpenGL 2 1 有没有办法在我的 OpenGL 版本中使用位运算 所有 SM3 兼容 OpenGL 2 1 硬件支持limited整
  • 为什么 OpenGL 有远裁剪平面,以及使用什么惯用法来处理这个问题?

    我一直在学习 OpenGL 持续困扰我的一个话题是远裁剪平面 虽然我可以理解近剪裁平面和侧剪裁平面 它们永远不会产生任何实际效果 因为它们之外的对象无论如何都不会被渲染 背后的推理 但远剪裁平面似乎只是一个烦恼 由于 OpenGL 背后的人
  • 如何在GPU支持下运行python代码

    我创建了一个 Flask 服务 用于接受以相机 URL 作为参数的请求 用于在相机框架中查找对象 桌子 椅子等 我已经在 Flask 中编写了用于接受 POST 请求的代码 app route rest detectObjects meth
  • CoreAnimation 性能分析 - CAReplicatorLayer 与 CAShapeLayer

    我正在制作一个依赖 CoreAnimation 的应用程序 它有一个 CAReplicatorLayer 和一个 CAShapeLayer 作为子层 当进行 12 次复制 然后对路径进行动画处理 在 touchMoved 上更改它 时 一旦
  • 在 3D 场景中实现“抓取”相机平移工具

    在我的场景中 我有想要 抓取 的地形 然后在移动光标时让相机平移 其高度 视图向量 视野等全部保持不变 因此 最初的 抓取 点将是世界空间中的工作点 我希望在拖动时该点保留在光标下方 我当前的解决方案是获取前一个和当前的屏幕点 取消投影它们
  • 为什么GCC编译的应用程序总是包含_mcount符号?

    库并不总是包含 mcount 符号 但应用程序包含 您可以使用 gobjdump 或 nm 实用程序验证这一点 我读过 mcount 用于实现分析 但即使禁用分析并启用优化 O2 该符号仍然存在 它还有其他额外的用途吗 更新 我使用的是 S
  • 移动/调整大小期间 opengl 窗口冻结

    我正在使用 LWJGL 开发游戏 移动窗口时 计划将来添加调整大小代码 渲染循环冻结 我希望它在移动时继续以某种方式运行 LWJGL 不包括 glutMainLoop Display属于OpenGL 而不是Java 相关代码 regular
  • UnimplementedError:图形执行错误:在张量流上运行 nn

    我一直遇到这个错误 我不知道为什么 特别是因为我完全遵循某人的代码并且该人在运行此错误时没有错误 img shape 128 128 3 load pretrained model base model tf keras applicati
  • OpenGL:VAO 和 VBO 对于大型多边形渲染任务是否实用?

    如果您想渲染一次在视锥体中包含数千个多边形的大型景观 并且用户的视点不断变化 那么使用 VAO 或 VBO 是否实用 我的意思是 每次玩家的位置或摄像机旋转发生变化时 您都必须重新计算顶点数据 以便正确剔除不再可见的任何顶点或场景 以保持良

随机推荐

  • Mac OSX:使用 dtruss?

    我正在尝试在 Mac OSX Catalina 中 dtruss 进程 但是 dtrace 报告错误 sudo dtruss whoami dtrace system integrity protection is on some feat
  • 如何调试 lxml.etree.XSLTParseError:无效的表达式错误

    我试图找出为什么 lxml 无法解析由带有各种内容的 根 文档组成的 XSL 文档xml includes 我收到错误 Traceback most recent call last File s py line 10 in
  • 使用 skimage 从多边形中提取图像片段

    我想获得通过剪切图像内的多边形而产生的子图像 我在 skimage 中有一个图像 在 matplotlib patches 中有一个多边形 怎么做 以下是我尝试过的 我不一定在寻找类似于下面的方法 我正在寻找最干净 最有效的实现 使用此代码
  • 如何卸载所有 Bower 软件包?

    有时 重建整个站点并强制 Bower 重新安装 Bower json 中所有软件包的新版本很有用 但是 似乎没有任何方法可以做到这一点 尝试 1 bower uninstall bower not installed 0 不 这只能在逐个包
  • gson:将 null 视为空字符串

    I use 谷歌 gson http code google com p google gson 将 Java 映射序列化为 JSON 字符串 它提供构建器处理空值 https sites google com site gson gson
  • 是否可以将 cacerts 的所有内容导入到 jssecacerts 文件中?

    使用 keytool 或其他方法 是否有一种简单的方法将 cacerts 的所有内容导入 jssecacerts 文件 基本上 我想定义自己的 jssecacerts 但我希望 jssecacerts 也包含 cacerts 文件的所有可信
  • iOS OneDrive (skydrive) 应用程序每次运行时都会显示权限对话框

    我正在开发一个 iOS 应用程序 让用户可以访问他们的 OneDrive SkyDrive 但我遇到了一个非常烦人的问题 用户第一次将应用程序链接到 OneDrive 时 一切都会按预期进行 他们必须输入用户 ID 和密码 然后他们必须同意
  • 如果 g(n) = sqrt(n)^sqrt(n),g(n) 的复杂度是否 = O(2^n)?

    If g n sqrt n sqrt n does the complexity of g n O 2n 任何帮助表示赞赏 比较两个指数函数时的一个有用技巧是让它们具有相同的底数 n n 2lg n n 2 n lg n Now you r
  • 在 C++ 中什么时候使用向量,什么时候使用数组?

    我通常不确定什么时候使用其中一种更好 一般来说 它们似乎都做同样的事情 但就其功能而言 向量是否更灵活 什么时候数组比较合适 通常总是更喜欢使用std vector
  • 所需示例:将 arrow() 与 ggplot2 一起使用

    我想创建一个 geom path 它的箭头指向路径中的下一个位置 我可以毫无问题地获取绘图路径 例如 df lt x 1 12 y 20 31 z 1 12 p lt ggplot df aes x x y y p geom point g
  • 如何在apache服务器中部署ember-cli项目

    我有以下问题 我使用 ember cli 创建了一个 ember 应用程序 该应用程序通过 url 在 nodejs 上运行良好http localhost 4200 运行命令时ember serve 我想在 apache httpd 服务
  • 如何最好地“合并”两个对象及其在 Rails 中的关联?

    这是我的情况 我有 2 个人员对象 人员 1 和人员 2 它们是从两个不同的外部数据源创建的 我使用的手动流程已确定 person1 和 person2 实际上指的是同一个人 因此我想要做的是将它们 合并 为一个人 并删除重复项 我对对象本
  • Nginx + phpFPM:PATH_INFO 始终为空

    我在 Debian 上配置了 nginx stable 1 4 4 PHP 使用 FastCGI php fpm 效果很好 location php fastcgi split path info php alias home 1 publ
  • 获取 .NET Web 应用程序中的当前目录

    所以我有一个网络项目 我试图使用c 方法获取网站的根目录Directory GetCurrentDirectory 我不想使用静态路径 因为文件位置将来会发生变化 此方法在我的 imageProcess aspx cs 文件中运行 但我认为
  • 如何在 RichTextBox 中附加 RTF 文本,Win C#

    我在 Win C 中有一个 RichTextBox 我想在 RichTextBox 中附加一些具有粗体效果的新文本 那么我该怎么做呢 I tried string str richTextBox Rtf my logic str rtf1
  • 通过 Oracle 连接

    这是一个示例表数据 Fruit Number Apple 1 Apple 2 Apple 3 Kiwi 6 Kiwi 10 我尝试连接表列值以获得以下内容 Fruit Number Apple 1 2 3 Kiwi 6 10 有没有办法查询
  • SQLException:oracle 中的协议冲突

    我收到 违反协议 的消息 我有一个在 RedHat Linux 上运行的应用程序 数据库和应用程序共同驻留在计算机上 使用的Oracle版本 Oracle 11g R2 11 2 0 3 0 使用的 JDBC 驱动程序 12 1 0 1使用
  • 无符号字符的格式说明符

    说我要打印unsigned char unsigned char x 12 哪个是对的 这 printf d x or this printf u x 事情在其他地方 所以我遇到了这样的讨论 即使 ch 更改为 unsigned char
  • 为什么这里除以零没有触发异常?

    这是一个后续问题为什么这个异常没有打印出来 为什么显示错误 https stackoverflow com questions 12130659 why is this exception is not printed why is it
  • 鉴于 GPU 有任务队列并且是异步的,计算 FPS 的正确方法是什么?

    我始终认为计算 FPS 的正确方法是简单地计算绘制循环迭代所需的时间 互联网上的大部分内容似乎都是一致的 But 现代显卡被视为异步服务器 因此绘制循环会发出 GPU 上已有的顶点 纹理 等数据的绘制指令 这些调用不会阻塞调用线程 直到 G