X зависает из-за приложения (используйте С++, Qt, OpenGL)
Мое приложение получает данные из сети и рисует их на сцене (сцена использует ручной движок OpenGL).
Он работает в течение нескольких часов. Когда я не использую свой рабочий стол, мой монитор, из-за того, что Display Power Manager Signaling (dpms) отключается. И затем, когда я касаюсь мыши или клавиатуры, монитор включается, и приложение зависает (X тоже зависает).
Если я это сделаю xset -dmps
операционная система не использует dpms, и приложение работает стабильно.
Эти проблемы возникают в Centos 6 и Archlinux, но когда я запускаю приложение под Ubuntu 12.10, он отлично работает!
Я пробовал разные драйверы NVidia. Без эффекта.
Я попытался использовать ssh для удаленного входа и подключиться к процессу с помощью gdb.
После включения монитора я не могу найти приложение в таблице процессов.
Как диагностировать проблему? Что происходит (в среде OpengGL), когда монитор выключается/включается? Ubuntu делает что-то особенное при использовании dpms?
У нас есть предположение по причинам!
Когда монитор выключен, мы теряем контекст OpenGL. Когда монитор просыпается, приложение зависает (нет контекста).
И разница в поведении в зависимости от операционной системы связана с различными подключениями монитора: Монитор для Kubuntu подключен к VGA-кабелю. И поэтому (возможно) это не влияет на поведение X.
Ответы
Ответ 1
Вы можете начать с просмотра журналов X, обычно расположенных /var/log/, и ~/.xsession-errors.
Не исключено, что OpenGL делает что-то нехорошее, поэтому, если ваше приложение имеет какой-либо журнал, включите его.
Включите дампы ядра, запустив ulimit -c unlimited
. Вы можете проанализировать дамп, открыв его в gdb следующим образом:
gdb <executable file> <core dump file>
Посмотрите, если это принесет что-нибудь полезное, тогда исследуйте все, что есть.
Ответ 2
Вы пытались добавить поддержку устойчивости своей реализации OpenGL, используя GL_ARB_robustness?
2.6 "Графика Reset Восстановление"
Некоторые события могут привести к Reset контекста GL. Такой resetприводит к потере всех состояний контекста. Восстановление от таких событий требует восстановления всех объектов в затронутом контексте. текущее состояние графического состояния Reset возвращается
enum GetGraphicsResetStatusARB();
Возвращаемая символьная константа указывает, был ли контекст GL a Reset в любой точке с момента последнего вызова GetGraphicsResetStatusARB. NO_ERROR указывает, что контекст GL имеет не был в состоянии Reset со времени последнего вызова. GUILTY_CONTEXT_RESET_ARB указывает, что обнаружен Reset, который объясняется текущим контекстом GL. INNOCENT_CONTEXT_RESET_ARB указывает, что обнаружен Reset, который не относится к текущий контекст GL. UNKNOWN_CONTEXT_RESET_ARB указывает обнаруженный графика Reset причина которого неизвестна.
Кроме того, убедитесь, что у вас есть контекст отладки при инициализации вашего контекста и используйте расширение 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
устаревшей - она проверяет для вас каждый вызов.