我正在使用SDL制作多人游戏,但是,在某些时候我已经停止同时运行它的两个实例了。第一个实例运行没有问题,但是,一旦第二个实例启动,它的渲染线程就会挂起。它表现为系统范围的图形冻结,例如我无法再移动鼠标,屏幕上的任何内容都不会在SDL窗口内部或外部更新。几秒钟后,渲染线程只会暂时恢复冻结。如果我发送并退出,SDL会设法捕获退出事件。然后,更新程序stdout的终端窗口(我可以假设更新线程正常运行,有一个很大的间隔,只有调试信息存在)。
通过从渲染过程中删除一段代码,我能够确定这三个未注释的SDL调用是导致延迟的原因:
void Renderer::render() {
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
// for (auto target : targets) {
// target->render(this);
// // std::cout << "rendered object with sceneId " << target->target->sceneId << std::endl;
// }
// auto targetCopy = newTargets;
// for (auto newTarget : targetCopy) {
// targets.push_back(newTarget);
// // std::cout << "adding render target" << std::endl;
// }
// newTargets.clear();
SDL_RenderPresent(sdlRenderer);
}
可能导致此行为的原因是什么?
这是SDL初始化代码,用于获取更多信息,也可以在没有加速的情况下尝试:
SDL_Init(SDL_INIT_VIDEO);
int fullscreenType = 0; // SDL_WINDOW_FULLSCREEN_DESKTOP;
int windowFlags = fullscreenType | SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS |
SDL_WINDOW_ALLOW_HIGHDPI;
int rendererFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
SDL_Window *window =
SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
1000, 1000, windowFlags);
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(window, -1, rendererFlags);
SDL_RenderSetLogicalSize(sdlRenderer, 1000, 1000);
IMG_Init(IMG_INIT_PNG);
我在Wayland上使用GNOME运行Manjaro。 Acer Swift 3. glxinfo | grep OpenGL
的输出:
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) HD Graphics 620 (Kaby Lake GT2)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 17.3.5
OpenGL core profile shading language version string: 4.50
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 3.0 Mesa 17.3.5
OpenGL shading language version string: 1.30
OpenGL context flags: (none)
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 17.3.5
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:
在X.Org上,这种行为略有不同(我可以移动鼠标,但一切都没有响应),但存在相同的潜在冻结问题。
答案 0 :(得分:4)
狂野一个受过教育的猜测,主要基于这样一个事实,即你在英特尔图形上,将会发出没有适当的缓冲区交换命令。英特尔驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步表示队列。
我认为发生的事情是,渲染循环无节制地运行,并且每个显示刷新间隔推送很多帧。但是,如果你要求双缓冲窗口,为什么会发生这种情况呢?答案:Wayland。 Wayland模型(实际上很有意义!)是,客户端渲染到屏幕外表面,由合成器管理,合成器本身负责执行“组合”(因此得名),即将所有内容放在屏幕上并与显示屏同步。但是,为了实现这一点,在合成开始之前,客户端的渲染结果必须准备就绪。
显然,屏幕外表面不会交换,因此任何“缓冲交换”或同步请求都必须转发给合成器。如果这不能正常工作,麻烦就会开始。
只有一个过程不断推动帧,它有点受限;但是有几个进程填充队列,看起来大部分GPU时间都被客户端消耗掉了,而Compositor缺乏更改以插入可以刷新/同步表示队列的缓冲区交换。
要快速检查,请在usleep(20000)
之后添加SDL_RenderPresent
。