Каков наилучший способ отладки OpenGL? - PullRequest
60 голосов
/ 06 февраля 2009

Я обнаружил, что в большинстве случаев OpenGL будет показывать вам, что он потерпел неудачу, ничего не рисуя. Я пытаюсь найти способы отладки программ OpenGL, проверяя стек матрицы преобразования и так далее. Каков наилучший способ отладки OpenGL? Если код выглядит и чувствует, что вершины находятся в нужном месте, как вы можете быть уверены, что они верны?

Ответы [ 10 ]

29 голосов
/ 06 февраля 2009

Прямого ответа нет. Все зависит от того, что вы пытаетесь понять. Поскольку OpenGL является конечным автоматом, иногда он не выполняет то, что вы ожидаете, так как требуемое состояние не установлено или тому подобное.

В общем, используйте такие инструменты, как glTrace / glIntercept (для просмотра трассировки вызовов OpenGL), gDebugger (для визуализации текстур, шейдеров, состояния OGL и т. Д.) И бумага / карандаш :). Иногда это помогает понять, как вы настроили камеру и где она смотрит, что вырезано и т. Д. Я лично больше полагался на последние, чем на предыдущие два подхода. Но когда я могу утверждать, что глубина неправильна, это помогает взглянуть на след. gDebugger также единственный инструмент , который можно эффективно использовать для профилирования и оптимизации вашего приложения OpenGL.

Помимо этого инструмента, в большинстве случаев математика ошибается, и ее невозможно понять с помощью какого-либо инструмента. Публикуйте в новостной группе OpenGL.org комментарии к коду, и вы никогда не будете разочарованы.

10 голосов
/ 06 февраля 2009

GLIntercept - ваш лучший выбор. С их веб-страницы:

  • Сохранение всех вызовов функций OpenGL в текстовом или XML-формате с возможностью записи отдельных кадров.
  • Бесплатная камера. Облетайте геометрию, отправляемую на видеокарту, и включайте / отключайте каркас / отбраковку лицевой стороны / просмотр рендера усеченного
  • Сохранить и отслеживать списки отображения. Сохранение буфера фрейма OpenGL (цвет / глубина / трафарет) до и после вызовов рендеринга. Возможность сохранения «различий» до и после изображений также доступна.
8 голосов
/ 17 февраля 2014

Apitrace - относительно новый инструмент от некоторых людей в Valve, но он прекрасно работает! Попробуйте: https://github.com/apitrace/apitrace

7 голосов
/ 23 апреля 2017

Каков наилучший способ отладки OpenGL?

Без учета дополнительных и внешних инструментов (что уже делают другие ответы).

Тогда общий способ - экстенсивно позвонить glGetError(). Однако лучшей альтернативой является использование Вывод отладки ( KHR_debug , ARB_debug_output ). Это дает вам возможность настроить обратный вызов для сообщений различной степени серьезности.

Чтобы использовать выходные данные отладки, контекст должен быть создан с флагом WGL/GLX_DEBUG_CONTEXT_BIT. Для GLFW это можно установить с помощью подсказки GLFW_OPENGL_DEBUG_CONTEXT .

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

Обратите внимание, что если контекст не является контекстом отладки, то получение всех или даже любых сообщений не гарантируется.

Независимо от того, есть ли у вас отладочный контекст или нет, его можно определить, установив GL_CONTEXT_FLAGS:

GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);

if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
    // It's a debug context

Затем вы можете указать обратный вызов:

void debugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
                  const GLchar *message, const void *userParam)
{
    // Print, log, whatever based on the enums and message
}

Каждое возможное значение для перечислений можно увидеть здесь . Особенно не забудьте проверить серьезность, так как некоторые сообщения могут быть просто уведомлениями, а не ошибками.

Теперь вы можете сделать заранее и зарегистрировать обратный вызов.

glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(debugMessage, NULL);

glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);

Вы даже можете вводить свои собственные сообщения, используя glDebugMessageInsert().

glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0,
                     GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Vary dangerous error");

Когда дело доходит до шейдеров и программ, вы всегда хотите проверять GL_COMPILE_STATUS, GL_LINK_STATUS и GL_VALIDATE_STATUS. Если кто-то из них обнаружит, что что-то не так, то дополнительно всегда проверяйте glGetShaderInfoLog() / glGetProgramInfoLog().

GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

if (!linkStatus)
{
    GLchar *infoLog = new GLchar[infoLogLength + 1];
    glGetProgramInfoLog(program, infoLogLength * sizeof(GLchar), NULL, infoLog); 

    ...

    delete[] infoLog;
}

Строка, возвращаемая glGetProgramInfoLog(), будет оканчиваться нулем.


Вы также можете пойти немного дальше и использовать несколько макросов отладки в сборке отладки. Таким образом, используя функции glIs*(), можно проверить, является ли ожидаемый тип фактическим.

assert(glIsProgram(program) == GL_TRUE);
glUseProgram(program);

Если выходные данные отладки недоступны, и вы просто хотите использовать glGetError(), тогда вы, конечно, можете это сделать.

GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
    printf("OpenGL Error: %u\n", err);

Поскольку числовой код ошибки не очень полезен, мы можем сделать его более понятным для человека, сопоставив числовые коды ошибок с сообщением.

const char* glGetErrorString(GLenum error)
{
    switch (error)
    {
    case GL_NO_ERROR:          return "No Error";
    case GL_INVALID_ENUM:      return "Invalid Enum";
    case GL_INVALID_VALUE:     return "Invalid Value";
    case GL_INVALID_OPERATION: return "Invalid Operation";
    case GL_INVALID_FRAMEBUFFER_OPERATION: return "Invalid Framebuffer Operation";
    case GL_OUT_OF_MEMORY:     return "Out of Memory";
    case GL_STACK_UNDERFLOW:   return "Stack Underflow";
    case GL_STACK_OVERFLOW:    return "Stack Overflow";
    case GL_CONTEXT_LOST:      return "Context Lost";
    default:                   return "Unknown Error";
    }
}

Затем проверяем это так:

printf("OpenGL Error: [%u] %s\n", err, glGetErrorString(err));

Это все еще не очень полезно или, лучше сказать, интуитивно, как если бы вы высыпали несколько glGetError() здесь и там. Тогда поиск того, кто из них зарегистрировал ошибку, может быть проблематичным.

Снова на помощь приходят макросы.

void _glCheckErrors(const char *filename, int line)
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
        printf("OpenGL Error: %s (%d) [%u] %s\n", filename, line, err, glGetErrorString(err));
}

Теперь просто определите макрос следующим образом:

#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)

и вуаля теперь вы можете звонить glCheckErrors() после всего, что вы хотите, и в случае ошибок он сообщит вам точный файл и строку, в которой он был обнаружен.

7 голосов
/ 02 декабря 2012

Я обнаружил, что вы можете проверять с помощью glGetError после каждой строки кода ваш подозреваемый будет ошибаться, но после этого код выглядит не очень чистым, но он работает.

4 голосов
/ 17 сентября 2013

gDebugger - отличный бесплатный инструмент, но больше не поддерживается. Однако AMD взялась за разработку, и этот отладчик теперь известен как CodeXL . Он доступен как в виде отдельного приложения, так и в виде плагина Visual Studio - работает как для собственных приложений C ++, так и для приложений Java / Python, использующих привязки OpenGL, как на графических процессорах NVidia, так и на AMD. Это чертовски инструмент.

4 голосов
/ 09 февраля 2009

Для тех, кто работает на Mac, отличное дополнение к отладчику OpenGL. Он позволяет вам проверять буферы, состояния и помогает находить проблемы с производительностью.

2 голосов
/ 09 февраля 2009

Существует также бесплатный glslDevil: http://www.vis.uni -stuttgart.de / glsldevil /

Позволяет широко отлаживать шейдеры glsl. Он также показывает неудачные вызовы OpenGL.

Однако отсутствуют функции для проверки текстур и закадровых буферов.

0 голосов
/ 12 ноября 2017

Обновление заголовка окна динамически удобно для меня.

Пример (используйте GLFW, C ++ 11):

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());
0 голосов
/ 02 сентября 2016

Nsight - хороший инструмент для отладки, если у вас есть карта NVidia.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...