¿Cuál es la mejor manera de depurar OpenGL?


Me parece que la mayoría de las veces, OpenGL le mostrará que falló al no dibujar nada. Estoy tratando de encontrar maneras de depurar programas OpenGL, mediante la inspección de la pila de matriz de transformación y así sucesivamente. ¿Cuál es la mejor manera de depurar OpenGL? Si el código se ve y se siente como los vértices están en el lugar correcto, ¿cómo puede estar seguro de que lo están?

Author: dreamlax, 2009-02-06

10 answers

No hay una respuesta directa. Todo depende de lo que estés tratando de entender. Dado que OpenGL es una máquina de estados, a veces no hace lo que espera, ya que el estado requerido no está establecido o cosas por el estilo.

En general, use herramientas como glTrace / glIntercept (para ver el seguimiento de llamadas de OpenGL), gDEBugger (para visualizar texturas, sombreadores, estado OGL, etc.) y papel / lápiz :). A veces ayuda a entender cómo ha configurado la cámara y dónde está mirando, qué está siendo recortado, etc. Personalmente he confiado más en el último que en los dos enfoques anteriores. Pero cuando puedo argumentar que la profundidad es incorrecta, entonces ayuda a mirar el rastro. gDEBugger también es la única herramienta que se puede usar de manera efectiva para crear perfiles y optimizar tu aplicación OpenGL.

Aparte de esta herramienta, la mayoría de las veces es la matemática que la gente se equivoca y no se puede entender usando ninguna herramienta. Publicar en el OpenGL.org grupo de noticias para comentarios específicos de código, usted será nunca decepcionada.

 29
Author: Ketan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-31 04:47:32

GLIntercept es tu mejor apuesta. De su página web:

  • Guarde todas las llamadas a funciones OpenGL en formato texto o XML con la opción de registrar fotogramas individuales.
  • Cámara libre. Vuele alrededor de la geometría enviada a la tarjeta gráfica y habilite/deshabilite wireframe/backface-culling / view frustum render
  • Guardar y rastrear listas de visualización. Guardar el búfer de marco de OpenGL (color/profundidad/plantilla) antes y después de las llamadas de renderizado. La capacidad de guardar el "diff" de pre y post imágenes también está disponible.
 10
Author: David S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-05 21:56:55

Apitrace es una herramienta relativamente nueva de algunas personas en Valve, ¡pero funciona muy bien! Pruébalo: https://github.com/apitrace/apitrace

 8
Author: Foxor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-16 23:30:56

He encontrado que puedes comprobar usando glGetError después de cada línea de código tu sospechoso estará equivocado, pero después de hacerlo, el código no se ve muy limpio pero funciona.

 7
Author: Frank Cheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-02 03:02:34

¿Cuál es la mejor manera de depurar OpenGL?

Sin considerar herramientas adicionales y externas(que otras respuestas ya hacen).

Entonces la manera general es llamar extensivamente glGetError(). Sin embargo, una mejor alternativa es utilizar Salida de depuración (KHR_debug, ARB_debug_output ). Esto le proporciona la funcionalidad de configurar una devolución de llamada para mensajes de diferente nivel de gravedad.

Para utilizar depurar la salida, el contexto debe ser creado con la bandera WGL/GLX_DEBUG_CONTEXT_BIT. Con GLFW esto se puede establecer con la sugerencia de ventana GLFW_OPENGL_DEBUG_CONTEXT .

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

Tenga en cuenta que si el contexto no es un contexto de depuración, entonces recibir todos o incluso cualquier mensaje no está garantizado.

Si tiene un contexto de depuración o no se puede detectar marcando GL_CONTEXT_FLAGS:

GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);

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

Entonces debería seguir adelante y especificar una devolución de llamada:

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
}

Cada valor posible para los enums puede ser visto aquí. Especialmente recuerde verificar la gravedad, ya que algunos mensajes pueden ser solo notificaciones y no errores.

Ahora puede hacer por adelantado y registrar la devolución de llamada.

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);

Incluso puede inyectar sus propios mensajes utilizando glDebugMessageInsert().

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

Cuando se trata de shaders y programas que siempre quieres estar comprobando GL_COMPILE_STATUS, GL_LINK_STATUS y GL_VALIDATE_STATUS. Si alguno de ellos refleja que algo está mal, entonces, además, siempre compruebe 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;
}

La cadena devuelta por glGetProgramInfoLog() será null terminated.


También puede ir un poco más extremo y utilizar algunas macros de depuración en una compilación de depuración. Así usando glIs*() funciones para comprobar si el tipo esperado es el tipo real también.

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

Si la salida de depuración no está disponible y solo desea usar glGetError(), entonces, por supuesto, es libre de hacerlo.

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

Dado que un código de error numérico no es tan útil, podría hacerlo un poco más legible para los humanos al asignar los códigos de error numéricos a un mensaje.

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";
    }
}

Entonces comprobándolo así:

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

Eso todavía no es muy útil o mejor dicho intuitivo, como si hubiera rociado algunos glGetError() aquí y allá. Luego, localizar cuál registró un error puede ser problemático.

De nuevo las macros vienen al rescate.

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));
}

Ahora simplemente define una macro como esta:

#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)

Y voila ahora puedes llamar glCheckErrors() después todo lo que quieras, y en caso de errores te dirá el archivo exacto y la línea en la que se detectó.

 6
Author: Vallentin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-23 13:51:51

Para aquellos en Mac, el buit en el depurador OpenGL también es genial. Le permite inspeccionar búferes, estados y ayuda a encontrar problemas de rendimiento.

 4
Author: Sijmen Mulder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-09 13:12:49

El gDEBugger es una excelente herramienta gratuita, pero ya no es compatible. Sin embargo, AMD ha retomado su desarrollo, y este depurador ahora se conoce como CodeXL. Está disponible como una aplicación independiente o como un plugin de Visual Studio-funciona tanto para aplicaciones nativas de C++, o aplicaciones Java / Python utilizando enlaces OpenGL, tanto en GPU NVidia y AMD. Es una herramienta increíble.

 4
Author: axel22,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-16 22:26:44

También está el glslDevil libre: http://www.vis.uni-stuttgart.de/glsldevil /

Le permite depurar sombreadores glsl extensivamente. También muestra llamadas OpenGL fallidas.

Sin embargo, le faltan características para inspeccionar texturas y búferes fuera de pantalla.

 2
Author: heeen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-09 13:04:33

Nsight es una buena herramienta de depuración si tienes una tarjeta NVidia.

 0
Author: aedm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 11:09:28

Actualizar el título de la ventana dinámicamente es conveniente para mí.

Ejemplo (use GLFW, C++11):

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());
 0
Author: BaiJiFeiLong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-12 19:58:06