鉴于 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 的正确方法是什么? 的相关文章

  • 多个进程可以共享一个 CUDA 上下文吗?

    这个问题是 Jason R 的后续问题comment https stackoverflow com questions 29964392 multiple cuda contexts for one device any sense co
  • VBO - 没有指数化的指数化

    我正在尝试将 VBO 与元素数组缓冲区一起用于我的三角形 如下所示 glBindBuffer GL ARRAY BUFFER g Buffer 0 glVertexPointer 3 GL FLOAT 0 BUFFER OFFSET 0 g
  • 是否可以在GPU中实现Huffman解码?

    我们有一个用霍夫曼编码编码的数据库 这里的目的是将其及其关联的解码器复制到 GPU 上 然后在 GPU 上对数据库进行解码 并在解码后的数据库上执行操作 而无需将其复制回 CPU 上 我还远远不是霍夫曼专家 但我所知道的少数人表明 它似乎是
  • 对 VBO 中的特定三角形使用不同的纹理

    我有 9 个由三角形组成的四边形 如下所示 我在用着VBO存储有关它们的数据 它们的位置和纹理坐标 我的问题是 是否可以仅使用一个来使四边形 5 具有与其余四边形不同的纹理VBO and shader 绿色代表纹理 1 黄色代表纹理 2 到
  • 使用 openGL、SOIL 加载图像

    我尝试了很多使用 SOIL 在 openGL 中加载和显示图像的示例 运行下面的源代码时 它仅显示一个没有图像的白色四边形 我尝试打开一个名为 foto 的图像 我将图像文件放在程序的文件夹中 bool keyStates new bool
  • 退出 glutFullScreen()

    我不明白为什么当我按 f 时它进入全屏但不退出全屏 在这个方法的开头我已经设置了bool fullscreen false 这是我的切换代码 case f toggle screenmode if fullscreen glutFullSc
  • DirectX 世界视图矩阵乘法 - GPU 或 CPU 的地方

    我是 directx 的新手 但令我惊讶的是 我看到的大多数示例中 世界矩阵和视图矩阵都是作为顶点着色器的一部分相乘 而不是与 CPU 相乘并将结果传递给着色器 对于刚性对象 这意味着您为对象的每个顶点将相同的两个矩阵相乘一次 我知道 GP
  • 三角形未在 OSX 上的 OpenGL 2.1 中绘制

    我正在学习有关使用 OpenGL 在 Java 中创建游戏引擎的教程 我正在尝试在屏幕上渲染一个三角形 一切运行良好 我可以更改背景颜色 但三角形不会显示 我还尝试运行作为教程系列的一部分提供的代码 但它仍然不起作用 教程链接 http b
  • 法线在 openGL 中表现得很奇怪

    我一直在为 openGl 编写一个 obj 加载器 几何体加载得很好 但法线总是混乱的 我尝试在两个不同的程序中导出模型 但似乎没有任何效果 据我所知 这就是将法线放入 GL TRIANGLES 的方法 glNormal3fv norm1
  • QOpenGLFunctions 缺少重要的 OpenGL 函数

    QOpenGLFunctions 似乎缺少重要的函数 例如 glInvalidateFramebuffer 和 glMapBuffer 据我了解 QOpenGLFunctions 加载桌面 OpenGL 函数和 ES 函数的交集 如果是这样
  • iOS 上的 OpenCV - GPU 使用情况?

    我正在尝试开发一个 iOS 应用程序 可以对来自相机的视频执行实时效果 就像 iPad 上的 Photobooth 一样 我熟悉 OpenCV 的 API 但如果大多数处理是在 CPU 上完成而不是在 GPU 上完成 我担心 iOS 上的性
  • Firebug 分析问题:“没有要分析的活动”

    我想用一些 javascript jQuery 尝试一些不同的选项 看看哪个是最快的 但是我无法让分析正常工作 这是我要测试的代码 this keypress function e console profile test retrieve
  • 我的绘图存在坐标/glortho 问题

    I have made a bit of a change to my code in the last couple of hours as everything was messy with my grid so I made it i
  • “分页文件太小,无法完成此操作”尝试训练 YOLOv5 对象检测模型时出错

    我有大约 50000 个图像和注释文件用于训练 YOLOv5 对象检测模型 我在另一台计算机上仅使用 CPU 训练模型没有问题 但需要太长时间 因此我需要 GPU 训练 我的问题是 当我尝试使用 GPU 进行训练时 我不断收到此错误 OSE
  • 如何离线分析使用 pstats.dump_stats(filename) 创建的文件?

    我基本上做了以下工作 import cProfile pstats StringIO pr cProfile Profile pr enable my code did something pr disable s StringIO Str
  • 为什么我的 FPS 相机一劳永逸地滚动?

    如果我忽略四元数代数的肮脏细节 我想我理解了旋转和平移变换背后的数学 但仍然不明白我做错了什么 为什么我的相机一劳永逸地滚动 更具体地说 我应该如何从相机的方向 旋转矩阵 计算相机视图矩阵 我正在用 Python 编写一个简约的 3d 引擎
  • 使用 perf 查找线程瓶颈并优化挂机时间

    对 cpu 周期进行采样perf record如果核心利用率大致恒定 则对于寻找优化候选非常有用 但对于具有并行性不同的多个阶段的代码 计算 cpu 周期将重点强调并行阶段 而低估影响挂机时间的顺序或有限并行阶段 简而言之 天真的 perf
  • OpenGL 着色器不与着色器程序链接

    我正在尝试使用 GLFW GLEW 添加着色器 我收到一个错误 指出着色器已加载 但它们没有有效的对象代码 这是我用于加载着色器的代码 class SHADER public void LoadShaders const char vert
  • 超出 CreateConstantBufferView 处虚拟地址的末尾

    我正在遵循 使用 DirectX12 进行游戏编程 ch 6 代码 但在 ID3DDevice CreateConstantBufferView 中 我发现 D3D12 错误 D3D12 错误 ID3D12Device CreateCons
  • 为什么 OpenGL 给对象提供句柄而不是指针?

    OpenGL 的传统是让用户使用 unsigned int 句柄来操作 OpenGL 对象 为什么不直接给出一个指针呢 与指针相比 唯一 ID 有何优点 TL DR OpenGL ID 不会双射映射到内存位置 单个 OpenGL ID 可能

随机推荐

  • 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