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


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

10 57

10 ответов:

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

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

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

  • сохранить все вызовы функций OpenGL в текстовом или XML формате с возможностью регистрации отдельных кадров.
  • свободная камера. Облетите геометрию, отправленную на графическую карту, и включите / отключите каркас / backface-culling/view frustum render
  • сохранение и отслеживание списков отображения. Сохранение буфера кадров OpenGL (цвет / глубина / трафарет) до и после вызова рендеринга. Возможность сохранения "разница" до и после картинки тоже имеются.

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

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

каков наилучший способ отладки 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() завершится null.


вы также можете пойти немного более экстремальным и использовать несколько макросов отладки в сборке отладки. Таким образом, используя 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() после всего, что вы хотите, и в случае ошибок он сообщит вам точный файл и строку, в которой он был обнаружен.

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

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

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

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

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

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

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

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

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());