【发布时间】:2014-10-18 06:47:07
【问题描述】:
我一直在玩游戏循环和物理。 前几天,我添加了一些调试语句来查看我的游戏循环的每一帧花费了多少时间。 正如预期的那样,结果在 16 毫秒范围内。 但是,我尝试禁用 vsync,这些结果并没有改变。 显然 vsync 仍在发生。我注释掉了 SFML 显示调用,果然帧加速了。
好的,那为什么 vsync 会卡住呢?起初我认为这一定是 DSFML(D 语言的 SFML 绑定)中的一个错误。我用C++创建了一个直接使用SFML的简单测试用例,性能特征完全一样!
我的系统如下:
$ inxi -SMG
系统:主机:c7 内核:3.16.4-1-ARCH x86_64(64 位) 桌面:i3 4.8 发行版:Arch Linux 机器:系统:Google 产品:Parrot v:1.0
主板:不适用 型号:不适用 BIOS:coreboot v:4.0-4744-gac16405-脏日期:2013 年 10 月 23 日
显卡:卡:英特尔第二代核心处理器系列集成显卡控制器
显示服务器:X.Org 1.16.1 驱动程序:英特尔分辨率:1366x768@60.02hz
GLX 渲染器:Mesa DRI 英特尔 Sandybridge 移动 GLX 版本:3.0 Mesa 10.3.1
SFML vsync 测试用例如下,vsync 开启:
#include <chrono>
#include <iostream>
#include "SFML/Graphics.hpp"
int main()
{
auto* window = new sf::RenderWindow(sf::VideoMode(640, 480), "test",
sf::Style::Titlebar | sf::Style::Close);
window->setVerticalSyncEnabled(true);
auto firstTime = std::chrono::high_resolution_clock::now();
while(window->isOpen())
{
//print frame timing
{
auto secondTime = std::chrono::high_resolution_clock::now();
using dMsecs = std::chrono::duration<double, std::chrono::milliseconds::period>;
auto elapsed = dMsecs(secondTime - firstTime);
firstTime = secondTime;
std::cout << elapsed.count() << '\n';
}
//event handler
{
sf::Event e;
while(window->pollEvent(e))
{
if(e.type == sf::Event::EventType::Closed)
window->close();
}
}
//render
{
window->clear();
window->display();
}
}
}
谷歌搜索这个问题,结果表明显卡驱动程序正在强制开启垂直同步。 但后来我想知道为什么 vsync 对我系统上的其他程序有效?
我编写了另一个测试用例,这次使用 SDL2:
#include <chrono>
#include <iostream>
#include "SDL2/SDL.h"
int main()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
auto firstTime = std::chrono::high_resolution_clock::now();
auto quit = false;
while(!quit)
{
//print frame timing
{
auto secondTime = std::chrono::high_resolution_clock::now();
using dMsecs = std::chrono::duration<double, std::chrono::milliseconds::period>;
auto elapsed = dMsecs(secondTime - firstTime);
firstTime = secondTime;
std::cout << elapsed.count() << '\n';
}
//event handler
{
SDL_Event e;
while(SDL_PollEvent(&e))
{
if(e.type == SDL_QUIT) quit = true;
}
}
//render
{
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
}
}
现在我禁用 vsync 是这个测试用例,并看到 0 毫秒范围内的帧时间,正如预期的那样! 因此,SFML 实现 vsync 的方式在我的系统上存在问题,而 SDL 似乎可以正确处理它。
导致这种不同行为的两个库之间的实现有什么区别,可以解决吗?我将如何使用 SFML 获得正确的行为?
【问题讨论】:
-
虽然理论上 SFML 中的某个地方可能存在一些仅在非常特殊的情况下才会发生的错误,但这听起来确实更有可能是某种驱动程序问题(或者它确实是一些奇怪的比赛条件或一些奇怪的导致一些错误发生的库星座)。您是否尝试过分析您的最小示例以查看花费/等待最多的时间?