我一直在玩游戏循环和物理。前几天,我添加了一些调试语句,以查看游戏循环的每一帧花费了多少时间。正如预期的那样,结果在16毫秒的范围内。然而,我尝试禁用vsync,但这些结果没有改变。显然vsync仍在发生。我评论掉了SFML显示调用,果不其然,帧加速了。
好吧,那么为什么vsync一直处于开启状态呢?起初,我认为这一定是DSFML(D语言的SFML绑定)中的一个错误。我用C++创建了一个简单的测试用例,它直接使用SFML,性能特性完全相同!
我的系统如下:
$inxi-SMG
系统:主机:c7内核:3.16.4-1-ARCH x86_64(64位)桌面:i3 4.8 Distro:ARCH Linux机器:系统:谷歌产品:Parrot v:1.0
Mobo:N/A型号:N/A Bios:coreboot v:4.0-4744-gac16405脏日期:2013年10月23日
图形:卡:英特尔第二代核心处理器系列集成图形控制器
显示服务器:X.Org 1.16.1驱动程序:intel分辨率:1366x768@60.02hz
GLX渲染器:Mesa DRI Intel Sandybridge Mobile 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。但后来我想知道为什么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,这是一个测试用例,正如预期的那样,帧时间在0ms范围内!因此,SFML实现vsync的方式在我的系统上是有缺陷的,而SDL似乎处理得很好。
导致这种不同行为的两个库在实现上的差异是什么?它能得到解决吗?我该如何使用SFML获得正确的行为?
这是一个有缺陷的驱动程序。glXSwapIntervalMESA有效。为glXSwapIntervalSGI返回的指针是有效的,因此如果不采取类似SDL的方法,SFML就无法检测到这个问题。