2

我一直在玩游戏循环和物理。前几天,我添加了一些调试语句来查看我的游戏循环的每一帧花费了多少时间。正如预期的那样,结果在 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
Mobo:N/A 型号:N /A BIOS:coreboot v:4.0-4744-gac16405-dirty 日期:10/23/2013
显卡:卡:英特尔第二代核心处理器系列集成显卡控制器
显示服务器:X.Org 1.16.1 驱动程序:英特尔分辨率: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 获得正确的行为?

4

1 回答 1

0

这是一个有缺陷的驱动程序。glXSwapIntervalMESA 有效。为 glXSwapIntervalSGI 返回的指针是有效的,因此如果不采取类似于 SDL 的方法,SFML 就无法检测到这个问题。

于 2014-10-21T22:33:33.117 回答