我使用SDL2在C++中拼凑了一个非常基本的游戏循环,但我注意到每隔几秒钟,即使什么也没有发生,SDL_PollEvent似乎异常缓慢。
我在每次循环时将我的deltaTime发送到控制台,当SDL_PollEvent滞后时,其差异约为100毫秒。我已经确认这是该函数的问题,通过移动我的计时器来确认,但我不确定在哪里进一步诊断问题。
我的循环:
while (!quit) {
uint32_t startTime = SDL_GetTicks();
while (SDL_PollEvent(&e) != 0) {
std::cout << "Event: "<< e.type << std::endl; // Added later, read update
if (e.type == SDL_QUIT) {
quit = true;
}
}
if (engine.AllowUpdate()) { // Restricts updates to every 20ms
GameState::Update();
}
engine.rMan.BeginRender();
//^v Literally just SDL_RenderClear and SDL_RenderPresent
engine.rMan.FinishRender();
engine.deltaTime = SDL_GetTicks() - startTime;
std::cout << std::setw(10) << engine.deltaTime;
}
我也发现即使我不在调试,这个问题还是会出现,并且至少有另一台机器没有此问题。希望能提出任何建议。
编辑1:尝试将通过队列进行的所有事件打印到控制台,以查看是否存在导致该问题的事件。已将打印行添加到上面的代码中。似乎在出现延迟的时间内没有事件触发,而我也处于空闲状态。
编辑2:根据要求,提供了一些可运行的代码,在VS2017上使用C++14和SDL2-2.0.9构建:
#include <iostream>
#include <SDL.h>
void InitSDL();
void BuildWindow();
void BuildRenderer();
SDL_Window* window;
SDL_Renderer* renderer;
int main(int argc, char* args[]) {
InitSDL();
BuildWindow();
BuildRenderer();
bool quit = false;
uint32_t deltaTime = 0;
while (!quit) {
uint32_t startTime = SDL_GetTicks();
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
deltaTime = SDL_GetTicks() - startTime;
std::cout << deltaTime << std::endl;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
return 0;
}
void InitSDL() {
Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS;
SDL_Init(flags);
}
void BuildWindow() {
window = SDL_CreateWindow
("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 600, NULL);
}
void BuildRenderer() {
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
}
在组装这个内容的过程中,我注意到了一些东西:
1. 没有 SDL_RenderPresent 就不会出现卡顿。 经过再次检查,这似乎并不是事实,但是 SDL_RenderPresent 受到了卡顿的影响。
与卡顿同时发生的 deltaTime 增加似乎发生在 SDL_PollEvent 的某个地方,正如 deltaTime 被赋值的位置所示。
第一个 deltaTime 总是更长,尽管我怀疑这与某些默认事件在启动时触发有关。
编辑3:深入挖掘了一下。试图将我的 delta 赋值移到 SDL_RenderPresent 之外。
示例片段:
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
std::cout << "Event: "<< e.type << std::endl;
if (e.type == SDL_QUIT) {
quit = true;
}
}
uint32_t startTime = SDL_GetTicks();
//SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
//SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
deltaTime = SDL_GetTicks() - startTime;
std::cout << deltaTime << std::endl;
编辑4: 更多数据。看起来卡顿几乎每3000毫秒发生一次。我让控制台只输出大于50毫秒的增量。图像格式为:游戏循环周期数| deltaTime | SDL_GetTicks()
我也考虑过这可能是硬件问题,因为在另一台电脑上没有这个问题,而且我也下载了一些其他的开源SDL游戏,体验到了相同的卡顿,间隔为3000毫秒。我也在Windows 10和Windows 7上的相同硬件上看到了同样的问题。除非有人认为有必要,否则我不会发布我的规格,但我已经通过从我的GPU中删除该游戏运行时看到完全相同的问题来排除了我的专用GPU有问题的可能性。
编辑5: 看起来延迟与USB设备有关。SDL每3000ms左右进行所有设备的查找吗?
把GPU重新放回机器后,我注意到延迟显著下降,而且我发现之前和之后唯一的区别是我的USB耳机不再插入。
出于一时的冲动,我再次运行了循环,这次观察任何大于3ms的deltaTime。当我移除设备时,我观察控制台以寻找变化:
真可喜!有点意外。没有插入USB设备,deltaTime一直保持在低于3ms的范围内。我测试的第二台机器是笔记本电脑,因此没有插入USB设备。我回去用同样的USB鼠标进行测试,如预期的那样,我看到每3000毫秒有明显的卡顿。
所以当前的问题是:USB设备如何导致这种卡顿?SDL每3000毫秒做什么与(a) USB设备和(b) SDL_RenderPresent()有关?
SDL_WINDOW_FULLSCREEN
模式更改全屏,而不是桌面大小的无边框窗口),而不是窗口,是否会有任何变化? - genpfault