【问题标题】:Running a second instance of an SDL program causes a system-wide freeze运行 SDL 程序的第二个实例会导致系统范围的冻结
【发布时间】:2018-03-03 19:28:32
【问题描述】:

我正在使用 SDL 制作多人游戏,但是,在某些时候,我无法同时运行它的两个实例。第一个实例运行没有问题,但是,一旦启动第二个实例,它的渲染线程就会挂起。它表现为系统范围的图形冻结,例如我无法再移动鼠标,并且屏幕上的任何内容都不会在 SDL 窗口内部或外部更新。几秒钟后,渲染线程恢复只是暂时再次冻结。如果我已发送退出事件并退出,SDL 确实设法捕捉到退出事件。然后,带有程序标准输出的终端窗口被更新(这就是我可以假设更新线程运行正常的方式,只有它的调试信息存在的间隔很大)。

通过从渲染过程中删除一段代码,我能够确定这三个未注释的 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 上,此行为略有不同(我可以移动鼠标,但一切都没有响应),但存在相同的潜在冻结问题。

【问题讨论】:

  • 一个疯狂的问题,主要基于这样一个事实,即您使用的是英特尔显卡,将是,没有发出适当的缓冲区交换命令。英特尔驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步表示队列。我猜想发生的是,您的渲染循环正在不受限制地运行,并且每个显示刷新间隔推送几帧。只需一个进程执行此操作,它的速率就会受到限制。如需快速检查,请在SDL_RenderPresent 之后添加usleep(20000)
  • Alco 你能试试如果你(可靠地)从图片中删除 Wayland 会发生什么吗?也许您启动的 X 服务器只是作为 Xwayland 客户端运行。由于明显的原因,屏幕外表面(如 Wayland 客户端使用)没有“缓冲区交换”的合理定义,因此这些将不会看到呈现队列同步事件。
  • @datenwolf 这是一个幸运的疯狂猜测,哈哈
  • @datenwolf 你能把它作为答案发布吗?也是的,我用 X 试过了,看看我的编辑,发生了类似的事情
  • @datenwolf 另一个您可能感兴趣的事实是我启用了 SDL 的垂直同步,我认为它会做同样的事情。知道为什么会发生这种情况吗?

标签: opengl graphics sdl


【解决方案1】:

一个狂野一个有根据的猜测,主要基于这样一个事实,即您使用的是英特尔显卡,将是,没有发出适当的缓冲区交换命令。英特尔驱动程序有点烦人,因为它们完全依赖缓冲区交换来刷新和同步呈现队列。

我想正在发生的事情是,您的渲染循环运行不受限制,并在每个显示刷新间隔推送 很多 帧。但是,如果您要求双缓冲窗口,为什么会发生这种情况?答案:韦兰。 Wayland 模型(实际上很有意义!)是,客户端渲染到屏幕外的表面,由合成器管理,合成器本身负责进行“合成”(因此得名),即将它们全部放在屏幕上并与显示同步。但是,要使其正常工作,客户端的渲染结果必须在合成开始之前准备好。

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

只有一个进程不断推帧,它的速率会受到限制;但是由于有多个进程填充队列,看起来大部分 GPU 时间都被客户端消耗了,合成器渴望进行更改以插入可以刷新/同步呈现队列的缓冲区交换。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多