1

来自对 OpenGL 编程的基本了解,所有必需的绘图操作都按顺序执行,每帧重绘一次。硬件的性能基本上决定了这种情况发生的速度。据我了解,游戏将尝试尽快绘制,因此重绘操作基本上包含在一个 while 循环中。然后将优化图形操作(图形引擎)以确保应用程序可以接受帧速率。

但是,支持垂直同步的图形硬件会将帧速率锁定到显示速率。第一个问题是图形引擎应该如何与硬件同步进行交互?这甚至可能还是渲染器以最大速度工作并且硬件有选择地调用最新帧,丢弃所有未使用的先前帧..?

这个问题的动机不是我立即打算编写一个图形引擎,而是正在调试现有系统的问题,其中移动场景的图形在屏幕上似乎结结巴巴。症状上,当 VSync 关闭时,口吃很轻微,当它打开时,要么有明显的周期性口吃,要么完全解决了口吃。对于正在发生的事情或原因,我有些抓不住,想了解更多有关图形系统的背景信息。

总而言之,问题在于人们应该如何与硬件重绘事件进行交互,以及这是否可能。但是,欢迎提供任何其他信息。

4

2 回答 2

1

第一个问题是图形引擎应该如何与硬件同步进行交互?

为了避免闪烁,现代渲染系统使用双缓冲,即有两个颜色平面缓冲区,在完成绘制到一个之后,显示读出指针设置为完成的缓冲区平面。此缓冲区交换可以同步或非同步发生。启用垂直同步后,缓冲区交换将同步,渲染线程会阻塞,直到缓冲区交换发生。

由于双缓冲要求缓冲区交换,这隐含地引入了同步机制。这就是交互式渲染系统锁定显示刷新的方式。

症状上,当 VSync 关闭时,口吃很轻微,当它打开时,要么有明显的周期性口吃,要么完全解决了口吃。

这听起来像是一个写得很糟糕的动画循环,它假设帧速率比显示刷新间隔更快,并且可以及时发出缓冲区交换以发生下一次回溯,从而假设帧速率锁定在显示刷新率上。

处理垂直同步的唯一可靠方法是实际测量帧渲染之间的时间并将渲染循环提前该时间量。

于 2013-04-12T13:57:30.810 回答
0

这是一个猜测,但是:

问题不在于垂直同步

我不知道您正在使用什么操作系统,但是有多种方法可以获取有关显示器的信息以及屏幕刷新的速度(出于此答案的目的,我们假设您的显示器是最新的并重绘以 60 Hz 的速率,或每秒 60 次,或每 16.66666... 毫秒一次)。

渲染器通常与应用程序的“逻辑”端配对:输入、ui 计算、模拟运行等。看起来应用程序的逻辑端运行得足够快,但渲染端 - 即Draw Callas它通常总结为 - 限制了您的应用程序的速度。

垂直同步可能会加剧这种情况,因为如果您的 Draw Call 每 16.66666 毫秒发生一次 - 但它需要的时间比 16.666666 毫秒长得多 - 那么您会感觉到帧速率下降(即帧会“卡顿”,因为它们花费的时间太长生成单帧)。VSync - 以及启用或禁用它 - 不会成为您代码的瓶颈:它只是说“嘿,由于硬件每 16.666666 毫秒只会从我们这里获取 1 帧,为什么要进行比每 16.66666 毫秒更多的绘制调用? ? 只要我们每次经过一次绘制调用,我们的应用程序就会看起​​来尽可能流畅,而且我们不必浪费时间进行更多调用!”

问题在于它假设您的代码运行速度足够快,可以在 16.6666 毫秒内完成。如果没有,卡顿、滞后、视觉伪影、冻结帧和其他事情会在屏幕上显现出来。

当您关闭 VSync 时,您是在告诉您的渲染调用尽可能频繁、尽可能快地被调用。这可能会在 Logic 调用旁边给它一些额外的摆动空间来渲染帧,这样当硬件说“我现在要拍照并把它放在屏幕上!”时 一切都被美化了,及时,进入姿势并说cheese!(尽管你说的话,它几乎没有做到)。

该怎么办:

首先分析您的代码。找出哪些功能花费的时间最多。从口吃来看,您的代码中的某些内容花费的时间比预期的要长,并且给您带来了不良的性能。确保首先进行概要分析以找到您正在消耗时间的关键部分,并弄清楚如何保持正确 使其尽可能快。您可能想弄清楚在渲染调用中调用了什么,并具体分析完成一个周期所需的时间。然后为逻辑调用计时,并查看执行这些调用需要多长时间。然后,砍掉。

祝你好运!

于 2013-04-12T11:56:39.610 回答