Qual é a melhor maneira de depurar o OpenGL?

Acho que a maior parte do tempo, o OpenGL vai mostrar que falhou ao não desenhar nada. Estou tentando encontrar maneiras de depurar programas OpenGL, inspecionando a pilha de matriz de transformação e assim por diante. Qual é a melhor maneira de depurar o OpenGL? Se o código parece e parece que os vértices estão no lugar certo, como você pode ter certeza que eles estão?

Author: dreamlax, 2009-02-06

10 answers

Não há resposta directa. Tudo depende do que você está tentando entender. Uma vez que OpenGL é uma máquina de Estado, às vezes não faz o que você espera como o Estado requerido não é definido ou coisas assim.

Em geral, use ferramentas como o glTrace / glIntercept( para olhar para o traço de chamada OpenGL), gDebugger (para visualizar texturas, shaders, estado OGL, etc.) e papel / lápis:). Às vezes ajuda a entender como você configurou a câmera e onde ela está olhando, o que é a ser cortado, etc. Pessoalmente, confiei mais no último do que nas duas abordagens anteriores. Mas quando posso argumentar que a profundidade está errada, então ajuda a olhar para o traço. gDebugger também é a única ferramenta que pode ser usada eficazmente para a análise e optimização da sua aplicação OpenGL.

Além desta ferramenta, na maioria das vezes é a matemática que as pessoas erram e não pode ser entendida usando qualquer ferramenta. Publicação OpenGL.org grupo de notícias para comentários específicos de código, você irá nunca fiques desapontado.

 29
Author: Ketan, 2017-12-31 04:47:32

O GLIntercept é a tua melhor aposta. Da sua página web:

  • gravar todas as chamadas da função OpenGL para o formato de texto ou XML com a opção de registar as imagens individuais.
  • Câmara livre. Voe em torno da geometria enviada para a placa gráfica e Active/desactive o desenho de arames/backface-culling / view frustum render
  • gravar e seguir as listas de visualização. Gravação do buffer de imagens OpenGL (cor/profundidade/stencil) pré e pós-renderização das chamadas. A capacidade de salvar o "diff" de pre e post as imagens também estão disponíveis.
 10
Author: David S., 2009-02-05 21:56:55
O Apitrace é uma ferramenta relativamente nova de algumas pessoas da Valve, mas funciona muito bem! Experimenta. https://github.com/apitrace/apitrace
 8
Author: Foxor, 2014-02-16 23:30:56

Descobri que podes verificar usando {[[0]} depois de cada linha de código o teu suspeito estará errado, mas depois de o fazer, o código não parece muito limpo, mas funciona.

 7
Author: Frank Cheng, 2012-12-02 03:02:34
Qual é a melhor maneira de depurar o OpenGL?

sem considerar ferramentas adicionais e externas (o que outras respostas já fazem).

Então o modo geral é chamar extensivamenteglGetError(). No entanto, uma melhor alternativa é usar o resultado de depuração (Khr_ Dug, Arb_debug_ output ). Isto fornece-lhe a funcionalidade de definir uma chamada de resposta para mensagens de nível de gravidade variável.

Por ordem para usar o resultado de depuração, o contexto deve ser criado com a opção WGL/GLX_DEBUG_CONTEXT_BIT. com o GLFW isto pode ser definido com a dica GLFW_OPENGL_DEBUG_CONTEXT da janela .

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

Note que se o contexto não é um contexto de depuração, então receber todas ou mesmo quaisquer mensagens não são garantidas.

Se TEM ou não um contexto de depuração pode ser detectado se verificar GL_CONTEXT_FLAGS:

GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);

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

Você então iria em frente e especificar um callback:

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 possível para os enums pode ser visto aqui. Lembre-se especialmente de verificar a gravidade, como algumas mensagens podem ser apenas notificações e não Erros.

Agora podes fazer o que quiseres e registar a chamada.
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);

Pode mesmo injectar as suas próprias mensagens usando glDebugMessageInsert().

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

Quando se trata de shaders e programas você sempre quer estar verificando GL_COMPILE_STATUS, GL_LINK_STATUS e GL_VALIDATE_STATUS Se algum deles reflete que algo está errado, então adicionalmente sempre verificar 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;
}

o texto devolvido por glGetProgramInfoLog() será nulo terminado.


Você também pode ir um pouco mais extremo e utilizar algumas macros de depuração em uma compilação de depuração. Assim, usando as funções glIs*() para verificar se o tipo esperado é o tipo real também.

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

Se o resultado de depuração não estiver disponível e você só quiser usar {[[12]}, então você está livre para fazê-lo.

GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
    printf("OpenGL Error: %u\n", err);
Como um código de erro numérico não ajuda muito, poderia torná-lo um pouco mais legível ao mapear os códigos de erro numérico para uma mensagem.
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";
    }
}

Depois verificar assim:

printf("OpenGL Error: [%u] %s\n", err, glGetErrorString(err));
Isso ainda não é muito útil ou melhor dito intuitivo, como se tivesse aspergido alguns aqui e ali. Em seguida, localizar qual registrou um erro pode ser problemático. Mais uma vez macros vem em Socorro.
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));
}
Basta definir uma macro como esta:
#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)
E voila agora podes ligar depois tudo o que você quer, e em caso de erros ele vai dizer-lhe o arquivo exato e linha que foi detectado em.
 6
Author: Vallentin, 2018-09-23 13:51:51
Para os que estão no Mac, o buit no depurador OpenGL também é óptimo. Permite inspecionar buffers, estados e ajuda a encontrar problemas de desempenho.
 4
Author: Sijmen Mulder, 2009-02-09 13:12:49

O gDebugger é uma excelente ferramenta livre, mas já não é suportada. No entanto, AMD pegou seu desenvolvimento, e este depurador é agora conhecido como CodeXL. Ele está disponível tanto como uma aplicação autônoma ou como um plugin de estúdio Visual-funciona tanto para aplicações nativas de C++, ou aplicações Java/Python usando ligações OpenGL, tanto em Nvidia e AMD GPUs. É uma grande ferramenta.

 4
Author: axel22, 2013-09-16 22:26:44

Existe também o glslDevil livre: http://www.vis.uni-stuttgart.de/glsldevil/

Permite-te depurar os shaders glsl extensivamente. Também mostra chamadas OpenGL falhadas. No entanto, faltam características para inspeccionar texturas e buffers fora do ecrã.
 2
Author: heeen, 2009-02-09 13:04:33

A Nsight é uma boa ferramenta de depuração se tiver um cartão NVidia.

 0
Author: aedm, 2016-09-02 11:09:28

Actualizar o título da janela dinamicamente é conveniente para mim.

Exemplo (usar o GLFW, C++11):

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());
 0
Author: BaiJiFeiLong, 2017-11-12 19:58:06