运行SDL程序的第二个实例会导致系统范围冻结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运行SDL程序的第二个实例会导致系统范围冻结相关的知识,希望对你有一定的参考价值。

我正在使用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上,这种行为略有不同(我可以移动鼠标,但一切都没有响应),但存在相同的潜在冻结问题。

答案

狂野的 一个有根据的猜测,主要是基于这个事实,你在英特尔图形上,将是,没有发出适当的缓冲交换命令。英特尔驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步表示队列。

我认为发生的事情是,你的渲染循环没有节流运行,并且每个显示刷新间隔推送大量帧。但是,如果你要求双缓冲窗口,为什么会发生这种情况呢?答案:Wayland。 Wayland模型(实际上很有意义!)是,客户端渲染到屏幕外表面,由合成器管理,合成器本身负责执行“组合”(因此得名),即将所有内容放在屏幕上并与显示屏同步。但是,要使其工作,客户端的渲染结果必须在合成开始之前就绪。

显然,屏幕外表面不会交换,因此任何“缓冲交换”或同步请求都必须转发给合成器。如果这不能正常工作,麻烦就开始了。

只有一个过程不断推动帧,它有点受限;但是有几个进程填充队列,看起来大多数GPU时间都被客户端消耗掉了,而Compositor缺乏更改以插入可以刷新/同步表示队列的缓冲区交换。

要快速检查,请在usleep(20000)之后添加SDL_RenderPresent

以上是关于运行SDL程序的第二个实例会导致系统范围冻结的主要内容,如果未能解决你的问题,请参考以下文章

在 AVAssetReader 中设置时间范围会导致冻结

在 PyQt 的第二个线程中打开子对话框的正确方法是啥?

尝试运行我的应用程序的第二个目标时的 SIGABRT

脚本不适用于引用组件的第二个实例

为啥这个的第二个版本在指数时间内运行?

第二次构建后不再找到 Xcode 框架