运行 SDL 程序的第二个实例导致系统范围的冻结
Running a second instance of an SDL program causes a system-wide freeze
我正在使用 SDL 制作多人游戏,但是,在某些时候我无法同时 运行 它的两个实例。第一个实例 运行 没有问题,但是,一旦启动第二个实例,它的渲染线程就会挂起。它表现为系统范围内的图形冻结,例如我不能再移动鼠标,屏幕上的任何内容都不会在 SDL window(s) 内部或外部更新。几秒钟后,渲染线程恢复只是暂时再次冻结。如果我发送并退出,SDL 确实设法捕捉到退出事件。然后,终端的 window 和程序的 stdout 被更新(这就是我如何假设更新线程是 运行ning 好的,有一个很大的间隔,只有它的调试信息存在)。
通过从渲染过程中删除一段代码,我能够确定这三个未注释的 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。宏碁 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 上,此行为略有不同(我可以四处移动鼠标,但一切都没有响应),但存在相同的潜在冻结问题。
一个狂野的一个有教养的猜测,主要基于你使用的是英特尔显卡这一事实,那就是,没有发出正确的缓冲区交换命令。 Intel 驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步演示队列。
我想发生的事情是,您的渲染循环 运行 不受限制,并且每个显示刷新间隔推送 很多 帧。但是,如果您要求双缓冲 window,为什么会发生这种情况?答案是:韦兰。 Wayland 模型(实际上很有意义!)是,客户端渲染到 off-screen 表面,由合成器管理,合成器本身负责执行 "composition"(因此名称),即把它们全部放在屏幕上并与显示器同步。但是,要使其正常工作,必须在合成开始之前准备好客户端的渲染结果。
显然 off-screen 表面不会交换,因此任何 "buffer swap" 或同步的请求都必须转发给合成器。如果这不能正常工作,麻烦就开始了。
只有一个进程不断地推送帧,它有点速率受限;但是随着多个进程填充队列,看起来大部分 GPU 时间都被客户端消耗掉了,合成器急需更改以插入缓冲区交换,这可能 flush/sync 演示队列。
为了快速检查,在 SDL_RenderPresent
之后添加 usleep(20000)
。
我正在使用 SDL 制作多人游戏,但是,在某些时候我无法同时 运行 它的两个实例。第一个实例 运行 没有问题,但是,一旦启动第二个实例,它的渲染线程就会挂起。它表现为系统范围内的图形冻结,例如我不能再移动鼠标,屏幕上的任何内容都不会在 SDL window(s) 内部或外部更新。几秒钟后,渲染线程恢复只是暂时再次冻结。如果我发送并退出,SDL 确实设法捕捉到退出事件。然后,终端的 window 和程序的 stdout 被更新(这就是我如何假设更新线程是 运行ning 好的,有一个很大的间隔,只有它的调试信息存在)。
通过从渲染过程中删除一段代码,我能够确定这三个未注释的 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。宏碁 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 上,此行为略有不同(我可以四处移动鼠标,但一切都没有响应),但存在相同的潜在冻结问题。
一个狂野的一个有教养的猜测,主要基于你使用的是英特尔显卡这一事实,那就是,没有发出正确的缓冲区交换命令。 Intel 驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步演示队列。
我想发生的事情是,您的渲染循环 运行 不受限制,并且每个显示刷新间隔推送 很多 帧。但是,如果您要求双缓冲 window,为什么会发生这种情况?答案是:韦兰。 Wayland 模型(实际上很有意义!)是,客户端渲染到 off-screen 表面,由合成器管理,合成器本身负责执行 "composition"(因此名称),即把它们全部放在屏幕上并与显示器同步。但是,要使其正常工作,必须在合成开始之前准备好客户端的渲染结果。
显然 off-screen 表面不会交换,因此任何 "buffer swap" 或同步的请求都必须转发给合成器。如果这不能正常工作,麻烦就开始了。
只有一个进程不断地推送帧,它有点速率受限;但是随着多个进程填充队列,看起来大部分 GPU 时间都被客户端消耗掉了,合成器急需更改以插入缓冲区交换,这可能 flush/sync 演示队列。
为了快速检查,在 SDL_RenderPresent
之后添加 usleep(20000)
。