X由于应用程序(使用C++、Qt、OpenGL)而挂起

X hangs up because of application (use C++, Qt, OpenGL)

本文关键字:Qt OpenGL 挂起 C++ 应用程序 使用      更新时间:2023-10-16

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

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

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

这些问题发生在Centos 6和Archlinux中,但当我在Ubuntu 12.10下运行应用程序时,它运行得很好!

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

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

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

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

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

2.6"图形重置恢复"

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

enum GetGraphicsResetStatusARB();

返回的符号常量指示GL上下文是否已在自上次调用以来的任何时间点的重置状态GetGraphicsResetStatusARB。NO_ERROR表示总账上下文具有自上次调用以来未处于重置状态。GUILTY_CONTEXT_RESET_ARB表示检测到重置可归因于当前GL上下文。无辜_文本_设置_ 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变得过时——它会为您检查每个调用。

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

gdb <executable file> <core dump file>

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