Ao escrever sombreadores não triviais (assim como ao escrever qualquer outro código não trivial), as pessoas cometem erros. [citation needed] No entanto, não posso simplesmente depurá-lo como qualquer outro código - você não pode simplesmente anexar o gdb ou o depurador do Visual Studio, afinal. Você não pode nem fazer depuração printf, porque não há forma de saída do console. O que geralmente faço é renderizar os dados que quero que sejam coloridos, mas essa é uma solução muito rudimentar e amadora. Tenho certeza que as pessoas apresentaram melhores soluções.
Então, como posso depurar um shader? Existe uma maneira de passar por um shader? Posso observar a execução do sombreador em um vértice / primitivo / fragmento específico?
(Esta pergunta é especificamente sobre como depurar código shader semelhante a como depurar código "normal", não sobre depurar coisas como alterações de estado.)
Respostas:
Até onde eu sei, não existem ferramentas que permitem percorrer o código em um sombreador (também, nesse caso, você precisaria selecionar apenas um pixel / vértice que deseja "depurar", é provável que a execução seja variar dependendo disso).
O que eu pessoalmente faço é uma "depuração colorida" muito hacky. Então ponho um monte de galhos dinâmicos com
#if DEBUG / #endif
guardas que basicamente dizemEntão você pode "observar" as informações de depuração dessa maneira. Eu costumo fazer vários truques, como ler ou misturar entre vários "códigos de cores" para testar vários eventos mais complexos ou coisas não binárias.
Nessa "estrutura", também acho útil ter um conjunto de convenções fixas para casos comuns, para que, se eu não precisar voltar constantemente e verificar qual a cor que associei a quê. O importante é ter um bom suporte para recarga a quente de código de sombreador, para que você possa quase interativamente alterar seus dados / eventos rastreados e ativar / desativar facilmente a visualização de depuração.
Se precisar depurar algo que você não pode exibir na tela com facilidade, sempre faça o mesmo e use uma ferramenta de analisador de quadros para inspecionar seus resultados. Eu listei alguns deles como resposta a essa outra pergunta.
Obviamente, é desnecessário dizer que, se eu não estiver "depurando" um sombreador de pixel ou sombreador de computação, passo essas informações "debugColor" por todo o pipeline sem interpolar (no GLSL com a
flat
palavra - chave)Novamente, isso é muito hacky e está longe de ser uma depuração adequada, mas é com isso que estou preso em não conhecer nenhuma alternativa adequada.
fonte
Há também GLSL-Debugger . É um depurador conhecido como "GLSL Devil".
O próprio Depurador é super útil não apenas para o código GLSL, mas também para o próprio OpenGL. Você tem a capacidade de alternar entre as chamadas de compra e interromper os comutadores Shader. Também mostra mensagens de erro comunicadas pelo OpenGL de volta ao próprio aplicativo.
fonte
Existem várias ofertas de fornecedores de GPU, como o CodeXL da AMD ou o nSight / Linux GFX Debugger da NVIDIA, que permitem passar por shaders, mas estão ligados ao hardware do respectivo fornecedor.
Deixe-me notar que, embora eles estejam disponíveis no Linux, sempre tive muito pouco sucesso em usá-los lá. Não posso comentar sobre a situação no Windows.
A opção que tenho vindo a utilizar recentemente, é modularizar o meu código de shader via
#includes
e restringir o código incluído para um subconjunto comum de GLSL e C ++ & glm .Quando encontro um problema, tento reproduzi-lo em outro dispositivo para ver se o problema é o mesmo, o que sugere um erro lógico (em vez de um problema no driver / comportamento indefinido). Há também a chance de passar dados errados para a GPU (por exemplo, buffers incorretamente ligados etc.), os quais eu geralmente descarto depurando a saída como na resposta CIFZ ou inspecionando os dados via apitrace .
Quando se trata de um erro lógico, tento reconstruir a situação da GPU na CPU chamando o código incluído na CPU com os mesmos dados. Então eu posso passar por isso na CPU.
Com base na modularidade do código, você também pode tentar escrever de forma mais unida para ele e comparar os resultados entre uma execução de GPU e uma CPU. No entanto, você deve estar ciente de que existem casos em que o C ++ pode se comportar de maneira diferente do GLSL, fornecendo falsos positivos nessas comparações.
Por fim, quando não é possível reproduzir o problema em outro dispositivo, você pode apenas começar a descobrir de onde vem a diferença. As unittests podem ajudá-lo a diminuir onde isso acontece, mas no final você provavelmente precisará escrever informações adicionais de depuração do shader, como na resposta cifz .
E para lhe dar uma visão geral, aqui está um fluxograma do meu processo de depuração:
Para finalizar, aqui está uma lista de prós e contras aleatórios:
pró
vigarista
fonte
Embora não pareça possível realmente percorrer um sombreador OpenGL, é possível obter os resultados da compilação.
O seguinte é retirado da Amostra de papelão do Android .
Se o seu código compilar corretamente, você terá poucas opções, a não ser tentar uma maneira diferente de comunicar o estado do programa a você. Você pode sinalizar que uma parte do código foi alcançada, por exemplo, alterando a cor de um vértice ou usando uma textura diferente. O que é estranho, mas parece ser o único caminho por enquanto.
EDIT: Para o WebGL, estou olhando para este projeto , mas eu o encontrei ... não posso atestar.
fonte
Esta é uma cópia e colar da minha resposta para a mesma pergunta no StackOverflow .
Na parte inferior desta resposta, há um exemplo de código GLSL que permite gerar o
float
valor total como cor, codificando IEEE 754binary32
. Eu usá-lo como segue (este trecho dá ayy
componente da matriz de modelagem):Depois de obtê-lo na tela, você pode escolher qualquer seletor de cores, formatar a cor como HTML (acrescentando
00
aorgb
valor se você não precisar de maior precisão e fazendo uma segunda passagem para obter o byte mais baixo, se necessário), e você obtém a representação hexadecimal dofloat
IEEE 754binary32
.Aqui está a implementação real de
toColor()
:fonte
A solução que funcionou para mim é a compilação de código de sombreador para C ++ - como mencionado por Nobody. Ele provou ser muito eficiente ao trabalhar em um código complexo, mesmo que exija um pouco de configuração.
Tenho trabalhado principalmente com HLSL Compute Shaders para os quais desenvolvi uma biblioteca de prova de conceito disponível aqui:
https://github.com/cezbloch/shaderator
Ele demonstra em um Compute Shader a partir de amostras do DirectX SDK, como habilitar C ++ como depuração HLSL e como configurar testes de unidade.
A compilação do sombreador de computação GLSL para C ++ parece mais fácil que o HLSL. Principalmente devido a construções de sintaxe no HLSL. Eu adicionei um exemplo trivial de teste de unidade executável em um rastreador de raios GLSL Compute Shader, que você também pode encontrar nas fontes do projeto Shaderator no link acima.
fonte