如何在窗口 SDL 应用程序中同步翻页和垂直回扫?
我目前正在编写一款极其复杂和狡猾的游戏,它会让您充满敬畏和惊叹 - 哦,好吧,这是 15 个谜题,我只是在熟悉 SDL。
我在窗口模式下运行,并使用 SDL_Flip 作为一般情况的页面更新,因为它会自动映射到窗口模式下完整窗口的 SDL_UpdateRect。这不是最佳方法,但考虑到这只是 15 个谜题……
无论如何,方块的移动速度快得离谱。 IOW,窗口模式下的 SDL_Flip 不包括与垂直回扫的任何同步。我在 Windows XP ATM 中工作,但我认为这对于 SDL 来说是正确的行为,并且也会在其他平台上发生。
切换到使用 SDL_UpdateRect 显然不会改变任何东西。据推测,我需要在自己的代码中实现延迟逻辑。但是一个简单的基于时钟的计时器可能会导致窗口半绘制时发生更新,从而导致可见的扭曲(我忘记了技术名称)。
编辑 此问题称为“撕裂”。
那么 - 在 SDL 的窗口模式游戏中,如何将翻页与垂直回扫同步?
编辑 在寻找解决方案时,我看到了一些说法,即不可能将页面翻转与窗口应用程序中的垂直回溯同步。至少在 Windows 上,这完全是错误的 - 我已经编写了执行此操作的游戏(我指的是与 15 谜题类似级别的游戏)。我曾经浪费了一些时间玩 Dark Basic 和 Dark GDK - 两者都基于 DirectX,并且都将页面翻转与窗口模式下的垂直回溯同步。
I'm currently writing a game of immense sophistication and cunning, that will fill you with awe and won- oh, OK, it's the 15 puzzle, and I'm just familiarising myself with SDL.
I'm running in windowed mode, and using SDL_Flip as the general-case page update, since it maps automatically to an SDL_UpdateRect of the full window in windowed mode. Not the optimum approach, but given that this is just the 15 puzzle...
Anyway, the tile moves are happening at ludicrous speed. IOW, SDL_Flip in windowed mode doesn't include any synchronisation with vertical retraces. I'm working in Windows XP ATM, but I assume this is correct behaviour for SDL and will occur on other platforms too.
Switching to using SDL_UpdateRect obviously won't change anything. Presumably, I need to implement the delay logic in my own code. But a simple clock-based timer could result in updates occuring when the window is half-drawn, causing visible distortions (I forget the technical name).
EDIT This problem is known as "tearing".
So - in a windowed mode game in SDL, how do I synchronise my page-flips with the vertical retrace?
EDIT I have seen several claims, while searching for a solution, that it is impossible to synchronise page-flips to the vertical retrace in a windowed application. On Windows, at least, this is simply false - I have written games (by which I mean things on a similar level to the 15-puzzle) that do this. I once wasted some time playing with Dark Basic and the Dark GDK - both DirectX-based and both syncronising page-flips to the vertical retrace in windowed mode.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
主要编辑
事实证明,我应该在提问之前花更多时间看看。来自 SDL 常见问题解答...
http://sdl.beuc.net/sdl.wiki/FAQ_Double_Buffering_is_Tearing< /a>
这似乎非常强烈地暗示 SDL 窗口模式应用程序不支持与垂直回扫同步。
但是...
基本技术在上可以在 Windows 上实现,并且我开始认为 SDL 在某种意义上可以做到这一点。只是还不太确定。
在 Windows 上,我之前说过,在窗口模式下将页面翻转同步到垂直同步一直可以追溯到使用 WinG 的 16 位时代。事实证明,这并不完全错误,而是具有误导性。我使用 WinG 挖出了一些旧的源代码,并且有一个计时器触发页面位块传送。 WinG 将以惊人的速度运行,正如我对 SDL 所做的那样感到惊讶 - 位图传输到屏幕的翻页操作不会等待垂直回扫。
进一步调查 - 当您在 WinG 中对屏幕执行 blit 时,blit 会排队等待稍后,并且调用退出。 blit 在下一个垂直回扫时执行,因此希望不会出现撕裂。如果您在回扫之前对屏幕(脏矩形)进行进一步的位图传输,它们将被合并。如果您在垂直回扫之前执行大量全屏位图传输,则您将渲染从未显示的帧。
WinG 中的 blit-to-screen 显然与 SDL_UpdateRect 类似。 SDL_UpdateRects 只是手动组合一些脏矩形的优化方法(并且确保它们可能应用于同一帧)。因此,也许(在可以进行垂直回溯的平台上)它是在 SDL 中完成的,类似于在 WinG 中 - 无需等待,但也无需撕裂。
好吧,我测试了使用计时器来触发帧更新,结果(在 Windows XP 上)不确定。我的旧笔记本电脑可能会出现非常轻微且偶尔的撕裂,但这可能不是 SDL 的错 - 可能是“光栅”超出了位块传输。这可能是我使用 SDL_Flip 而不是直接调用带有最小脏矩形的 SDL_UpdateRect 的错误 - 尽管我试图在这种情况下撕裂,看看我是否可以。
所以我仍然不确定,但窗口模式 SDL 可能与那些允许撕裂的平台一样不受撕裂影响。即使在我古老的笔记本电脑上,结果似乎也没有我想象的那么糟糕。
但是 - 谁能提供明确的答案?
Major Edit
It turns out I should have spent more time looking before asking. From the SDL FAQ...
http://sdl.beuc.net/sdl.wiki/FAQ_Double_Buffering_is_Tearing
That seems to imply quite strongly that synchronising with the vertical retrace isn't supported in SDL windowed-mode apps.
But...
The basic technique is possible on Windows, and I'm beginning the think SDL does it, in a sense. Just not quite certain yet.
On Windows, I said before, synchronising page-flips to vertical syncs in Windowed mode has been possible all the way back to the 16-bit days using WinG. It turns out that that's not exactly wrong, but misleading. I dug out some old source code using WinG, and there was a timer triggering the page-blits. WinG will run at ludicrous speed, just as I was surprised by SDL doing - the blit-to-screen page-flip operations don't wait for a vertical retrace.
On further investigation - when you do a blit to the screen in WinG, the blit is queued for later and the call exits. The blit is executed at the next vertical retrace, so hopefully no tearing. If you do further blits to the screen (dirty rectangles) before that retrace, they are combined. If you do loads of full-screen blits before the vertical retrace, you are rendering frames that are never displayed.
This blit-to-screen in WinG is obviously similar to the SDL_UpdateRect. SDL_UpdateRects is just an optimised way to manually combine some dirty rectangles (and be sure, perhaps, they are applied to the same frame). So maybe (on platforms where vertical retrace stuff is possible) it is being done in SDL, similarly to in WinG - no waiting, but no tearing either.
Well, I tested using a timer to trigger the frame updates, and the result (on Windows XP) is uncertain. I could get very slight and occasional tearing on my ancient laptop, but that may be no fault of SDLs - it could be that the "raster" is outrunning the blit. This is probably my fault for using SDL_Flip instead of a direct call to SDL_UpdateRect with a minimal dirty rectangle - though I was trying to get tearing in this case, to see if I could.
So I'm still uncertain, but it may be that windowed-mode SDL is as immune to tearing as it can be on those platforms that allow it. Results don't seem as bad as I imagined, even on my ancient laptop.
But - can anyone offer a definitive answer?
您可以使用 SDL_gfx 的帧速率控制。
查看库的文档,您的流程应用程序将是这样的:
另外,您可以查看 源代码 创建您自己的帧速率控制。
You can use the framerate control of SDL_gfx.
Looking at the docs of library, the flow of your application will be like this:
Also, you may look at the source code to create your own framerate control.