每帧分配一个新缓冲区以防止屏幕撕裂

Posted

技术标签:

【中文标题】每帧分配一个新缓冲区以防止屏幕撕裂【英文标题】:Allocating a new buffer per each frame to prevent screen tearing 【发布时间】:2015-06-01 22:22:11 【问题描述】:

当我使用 SDL 库设置内存中的像素值并更新屏幕时,只要更新太快就会出现屏幕撕裂。我对 SDL 内部了解不多,但我的理解是:

    更新函数在通知图形硬件从(比如)buffer1 读取像素数据后立即返回。 在buffer2上绘制下一帧,再次调用update,但是太快了,从buffer1读取还没有完成; 我的程序对硬件一无所知,并假定可以在 buffer1 中再次绘制,同时将此缓冲区发送到监视器。 屏幕被撕裂了。

当待绘制对象的速度不太快时,这不是一个大问题。屏幕仍然会流泪,但人眼几乎看不到它,但如果根本不发生这种流泪,我仍然会很高兴。我不喜欢垂直同步,因为它每帧都会产生一致的延迟。

我的想法是,可能每个要绘制的帧都分配一个新的屏幕缓冲区。当监视器想要显示某些东西时,它应该从最新的缓冲区中读取。

这是一种已经在实践中使用的可能方式吗?如果我确实想测试我的想法,我可以使用什么样的低级和跨平台库或 API? SDL? OpenGL?

【问题讨论】:

与缓冲区无关,与更新屏幕的确切时间有关。谷歌“sdl 垂直同步”,你不能错过 SDL_RENDERER_PRESENTVSYNC。 可能吗?是的。可能? 没有。通常你会看到使用双 (2) 或三 (3) 缓冲。缓冲区是预先分配的。 @HansPassant 我知道我总是可以进行垂直同步,我在原帖中提到过我想避免它的一致延迟。 如果你在刷新的时候改变屏幕内容,你会被撕裂的。避免它的唯一方法是接受延迟。我希望有一种方法可以在等待同步时利用多个缓冲区,以便只使用最新的准备好的缓冲区,而您不会等待。 【参考方案1】:

您认为更新屏幕的速度比人眼看到的速度快吗?如果您真的必须让您的引擎 100% 独立于回溯,请使用三重缓冲系统。一个缓冲区显示,2 个缓冲区来回更新,直到屏幕准备好下一个缓冲区。 Triple 与您需要的一样高,就好像您填充了第二个后备缓冲区一样,您可以改写现在已失效的第一个后备缓冲区。没有 GPU 延迟,只有 3 个缓冲区。

Here 是一个很好的链接,描述了这种技术以及一些关于在现代 GPU 上使用它的警告......

【讨论】:

你的链接回答了我所有的问题!

以上是关于每帧分配一个新缓冲区以防止屏幕撕裂的主要内容,如果未能解决你的问题,请参考以下文章

避免linux + QT中的屏幕撕裂

如何频繁更新顶点缓冲区数据(每帧)opengl [重复]

在具有 DWM 合成的窗口上使用 GDI 绘图时是不是可以防止撕裂伪影?

调整缓冲区大小时 OpenGL 失败

每帧调用 glGetUniformLocation()

什么是 realloc() 的 C++ 版本,用于分配新缓冲区并从旧缓冲区复制内容?