我听说很多从事VR的人都在谈论扫描线赛车,它应该有助于改善运动到光子的延迟。但是,我不清楚如何使用OpenGL完成此操作。有人可以解释一下scanline race的工作原理,以及如何在现代GPU上实现它。

#1 楼

当您的GPU在屏幕上显示新帧时,它会通过称为“扫描”的过程通过HDMI电缆(或任何种类)传输图像。像素以线性顺序发送,通常是从左到右和从上到下。该过程是定时的,因此需要刷新间隔的大部分时间来执行此操作。例如,在60Hz时,一帧为〜17 ms。每次扫描大约需要15-16毫秒,中间需要1-2毫秒的vblank(具体值取决于显示和视频模式而有所不同)。

传统上,渲染是双缓冲的,这意味着GPU内存中存储了两个缓冲区:一个正在被扫描出(“前缓冲区”),另一个正在被渲染(“后缓冲区”)。每个帧都被交换。 GPU永远不会渲染到被扫描出的同一缓冲区,以防止由于可能看到不完整帧的某些部分而造成伪影。但是,这样做的副作用是增加了延迟,因为每个帧在开始被扫描之前可能会在缓冲区中停留数毫秒。

VR对延迟非常敏感,因此这并不敏感理想的。另一种方法是直接渲染到前缓冲区,但是要非常小心地超时,以便在扫描输出到达之前不久就渲染图像的每一行。这就是所谓的“扫描线赛车”或“赛车横梁”(“光束”回溯到昔日的CRT时代)。这或多或少要求您以扫描线顺序(即,像素被扫描出的顺序)渲染图像。从字面上看,不必一次绘制一行,它可以以几像素高的细条形式呈现,但是必须按顺序完成,因为您无法返回并编辑已经存在的像素已被扫描出。

这种方法有很多缺点。它具有非常严格的性能要求,必须非常谨慎地对vsync进行计时,并且使渲染过程变得非常复杂。但是从原则上讲,它可以减少毫秒级的延迟,这就是为什么VR人员对此感兴趣的原因。

评论


$ \ begingroup $
所以我的问题是我们如何在现代GPU上做到这一点?我认为没有任何方法可以查询扫描结果,在我看来,您真的不能提交每条扫描线的绘制调用。即使您可以-您有什么保证可以保证抽奖将在扫描之前到达那里?
$ \ endgroup $
– Mokosha
15年8月5日,16:10

$ \ begingroup $
@Mokosha正确,无法直接通过AFAIK查询扫描结果。充其量,您可以找出vsync的时间(通过某些OS信号),并通过相对于该时间的定时来估计扫描输出的位置(了解视频模式的详细信息)。对于渲染,您可以尝试找出在glFlush和渲染完成之间通常需要多长时间,并据此做出一些猜测。最终,如果出现错误(例如,在扫描之前保持2-3毫秒),您必须在时间上留一些余地,并接受偶尔可能出现伪像的情况。
$ \ endgroup $
–内森·里德(Nathan Reed)
2015年8月5日在20:39



$ \ begingroup $
延迟增加的结果是由于vsync引起的,它导致前缓冲区和后缓冲区交换与监视器的vblank同步。双缓冲本身并不会单独导致此问题,并且有助于最大程度地减少闪烁,因为像素在前缓冲中只能更改一次。
$ \ endgroup $
–莫里斯·拉沃(Maurice Laveaux)
15年8月6日,0:29

$ \ begingroup $
我想出了一种无需扫描线查询就能准确预测栅格的方法,请参见下面的答案。
$ \ endgroup $
–马克·雷洪(Mark Rejhon)
18 Mar 27 '18 at 14:24

#2 楼

伟大的事情是,我们最终可以在不访问每个扫描线查询的情况下最终预测扫描线的精确光栅精度:

https://www.youtube.com/watch?v=OZ7Loh830Ec

我想出了精确的微秒精度公式作为VSYNC偏移量,以预测撕裂线的位置。 VSYNC OFF期间的泪痕始终是精确的栅格,因此您可以通过重复的VSYNC OFF缓冲区交换在条带级“模拟的前缓冲区渲染”期间将其移出可见性。

注意论坛主题- -不断增加一些开源代码-https://forums.blurbusters.com/viewtopic.php?f=10&p=32002

#3 楼

如果有兴趣的话,Dreamcast可以使用“竞赛光束”渲染模式,从而可以将相对较小的内存专用于帧缓冲像素(例如64条扫描线),并且可以依次渲染32行,与显示更新。但是,这仅用于节省内存。我怀疑有人会为显示器的后半部分生成“修改的”几何图形。