【问题标题】:X hangs up because of application (use C++, Qt, OpenGL)X 因应用程序而挂起(使用 C++、Qt、OpenGL)
【发布时间】:2013-12-07 07:12:13
【问题描述】:

我的应用程序从网络获取数据并在场景中绘制(场景使用手工制作的 OpenGL 引擎)。

它可以工作几个小时。当我不使用我的桌面时,我的显示器会因为显示电源管理器信号 (dpms) 而关闭。然后,当我触摸鼠标或键盘时,显示器打开,应用程序挂起(X 也挂起)。

如果我这样做 xset -dmps 操作系统不使用dpms,应用运行稳定。

这些问题出现在 Centos 6 和 Archlinux 中,但是当我在 Ubuntu 12.10 下运行该应用程序时,它运行良好!

我尝试了不同的 NVidia 驱动程序。没有效果。

我尝试使用 ssh 远程登录并使用 gdb 附加到进程。 打开监视器后,我在进程表中找不到应用程序。

如何诊断问题?当显示器关闭/打开时(在 OpenGL 环境中)会发生什么? Ubuntu 在使用 dpms 时会做一些特别的事情吗?

我们猜测问题的原因! 当监视器关闭时,我们会丢失 OpenGL 上下文。当监视器唤醒时,应用程序挂起(没有上下文)。 取决于操作系统的行为差异是因为不同的显示器连接:Kubuntu 的显示器是用 VGA 电缆连接的。因此(可能)它对 X 行为没有影响。

【问题讨论】:

  • Archlinux 是一种滚动发行的发行版,CentOS 是一个面向服务器的发行版,如果您想要良好的多媒体支持和 OpenGL 功能而不需要太多努力,那么您可能走错了方向。 Archlinux 有点像 Debian Sid(Debian 测试有时甚至更差),而且每次我接触这 2 个发行版时,我的 GPU 驱动程序都有几乎相同的问题,主要是因为内核和 X 总是更新到最新版本和 GPU司机落后了。
  • 如果进程不再在进程表中,它可能已经崩溃。如果您使用 ulimit(在 bash 中)或 limit(在 csh 中)允许转储核心转储文件,您也许可以使用该核心文件来调试问题。
  • 看来是X服务器的问题,我想其他虚拟终端在这种情况下仍然可以工作,上一个并使用进程监视器查看X是否使用100%的CPU。我提到这一点是因为我以前遇到过这个麻烦。发生这种情况的唯一可解释方式是因为 X 中的一个错误,它不应该因为无效输入而在无限循环上运行。如果这是问题,您可以做的最好的事情是降级您的 X 版本。如果不是这样,请在您的应用程序上尝试 valgrind。
  • 如果确定 X 服务器已挂起,我将对 X 服务器进程进行 3 次核心转储,间隔大约 1 分钟,以确定它挂起的原因。
  • 可能是关键字或鼠标抓取的问题,可能与窗口管理器有关..

标签: c++ linux qt opengl nvidia


【解决方案1】:

您是否尝试过使用 GL_ARB_robustness 为您的 OpenGL 实现添加健壮性支持?

2.6“显卡重置恢复”

某些事件可能会导致 GL 上下文重置。这样的重置 导致所有上下文状态丢失。从此类事件中恢复 需要重新创建受影响上下文中的所有对象。这 图形重置状态的当前状态由

返回
enum GetGraphicsResetStatusARB();

返回的符号常量指示 GL 上下文是否已在 自上次调用以来的任何时间点的重置状态 GetGraphicsResetStatusARB。 NO_ERROR 表示 GL 上下文有 自上次调用以来未处于重置状态。 GUILTY_CONTEXT_RESET_ARB 表示检测到复位 归因于当前的 GL 上下文。 INNOCENT_CONTEXT_RESET_ARB 表示已检测到不可归因于 当前的总帐上下文。 UNKNOWN_CONTEXT_RESET_ARB 表示检测到 原因不明的图形重置。

此外,请确保在初始化上下文时具有调试上下文,并使用 ARB_debug_output 扩展名接收日志输出。

void DebugMessageControlARB(enum source,
                            enum type,
                            enum severity,
                            sizei count,
                            const uint* ids,
                            boolean enabled);

void DebugMessageInsertARB(enum source,
                           enum type,
                           uint id,
                           enum severity,
                           sizei length, 
                           const char* buf);

void DebugMessageCallbackARB(DEBUGPROCARB callback,
                             const void* userParam);

uint GetDebugMessageLogARB(uint count,
                           sizei bufSize,
                           enum* sources,
                           enum* types,
                           uint* ids,
                           enum* severities,
                           sizei* lengths, 
                           char* messageLog);

void GetPointerv(enum pname,
                 void** params);

例如:

// Initialize GL_ARB_debug_output ASAP
if (glfwExtensionSupported("GL_ARB_debug_output"))
{
    typedef void APIENTRY (*glDebugMessageCallbackARBFunc)
            (GLDEBUGPROCARB callback, const void* userParam);
    typedef void APIENTRY (*glDebugMessageControlARBFunc)
            (GLenum source, GLenum type, GLenum severity,
             GLsizei count, const GLuint* ids, GLboolean enabled);
    auto glDebugMessageCallbackARB = (glDebugMessageCallbackARBFunc)
            glfwGetProcAddress("glDebugMessageCallbackARB");
    auto glDebugMessageControlARB = (glDebugMessageControlARBFunc)
            glfwGetProcAddress("glDebugMessageControlARB");
    glDebugMessageCallbackARB(debugCallback, this);
    glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE,
            GL_DEBUG_SEVERITY_LOW_ARB, 0, nullptr, GL_TRUE);
}

...

std::string GlfwThread::severityString(GLenum severity)
{
    switch (severity)
    {
    case GL_DEBUG_SEVERITY_LOW_ARB: return "LOW";
    case GL_DEBUG_SEVERITY_MEDIUM_ARB: return "MEDIUM";
    case GL_DEBUG_SEVERITY_HIGH_ARB: return "HIGH";
    default: return "??";
    }
}

std::string GlfwThread::sourceString(GLenum source)
{
    switch (source)
    {
    case GL_DEBUG_SOURCE_API_ARB: return "API";
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "SYSTEM";
    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "SHADER_COMPILER";
    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "THIRD_PARTY";
    case GL_DEBUG_SOURCE_APPLICATION_ARB: return "APPLICATION";
    case GL_DEBUG_SOURCE_OTHER_ARB: return "OTHER";
    default: return "???";
    }
}

std::string GlfwThread::typeString(GLenum type)
{
    switch (type)
    {
    case GL_DEBUG_TYPE_ERROR_ARB: return "ERROR";
    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return "DEPRECATED_BEHAVIOR";
    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "UNDEFINED_BEHAVIOR";
    case GL_DEBUG_TYPE_PORTABILITY_ARB: return "PORTABILITY";
    case GL_DEBUG_TYPE_PERFORMANCE_ARB: return "PERFORMANCE";
    case GL_DEBUG_TYPE_OTHER_ARB: return "OTHER";
    default: return "???";
    }
}

// Note: this is static, it is called from OpenGL
void GlfwThread::debugCallback(GLenum source, GLenum type,
                               GLuint id, GLenum severity,
                               GLsizei, const GLchar *message,
                               const GLvoid *)
{
    std::cout << "source=" << sourceString(source) <<
                 " type=" << typeString(type) <<
                 " id=" << id <<
                 " severity=" << severityString(severity) <<
                 " message=" << message <<
                 std::endl;
    AssertBreak(type != GL_DEBUG_TYPE_ERROR_ARB);
}

您几乎可以肯定地在一个不错的 OpenGL 实现中使用了这两个扩展。他们有帮助,很多。调试上下文对所有内容进行验证并向日志抱怨。他们甚至在一些 OpenGL 实现的日志输出中给出了性能建议。使用 ARB_debug_output 会使检查 glGetError 过时 - 它会为您检查每次调用。

【讨论】:

    【解决方案2】:

    您可以先查看 X 的日志,通常位于 /var/log/ 和 ~/.xsession-errors。 OpenGL 正在做一些奇怪的事情并不是不可能的,所以如果您的应用程序有任何日志记录,请打开它。 通过运行ulimit -c unlimited 启用核心转储。您可以通过在 gdb 中打开它来分析转储,如下所示:

    gdb <executable file> <core dump file>
    

    看看这是否会产生任何有用的东西,然后研究任何有用的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多