glslangel: Uma Ferramenta de Depuração para a Linguagem GLSL - PDF
Download "glslangel: Uma Ferramenta de Depuração para a Linguagem GLSL"
Maria Fernanda Jardim Castro
1 UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL INSTITUTO DE INFORMÁTICA CURSO DE CIÊNCIA DA COMPUTAÇÃO BÁRBARA BELLAVER GONÇALVES glslangel: Uma Ferramenta de Depuração para a Linguagem GLSL Trabalho de Graduação Prof. Dr. Manuel Menezes de Oliveira Neto Orientador Porto Alegre, novembro de 2008.
2 UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL Reitor: Prof. Carlos Alexandre Netto Vice-Reitor: Prof. Rui Vicente Oppermann Pró-Reitora Graduação: Profa. Valquiria Link Bassani Diretor do Instituto de Informática: Prof. Flávio Rech Wagner Coordenador do CIC: Prof. Raul Fernando Weber Bibliotecária-Chefe do Instituto de Informática: Beatriz Regina Bastos Haro
3 AGRADECIMENTOS Agradeço primeiramente à Deus, por toda a luz. Ao meu orientador, Manuel Menezes de Oliveira Neto, pela paciência, pelos conselhos, pelas conversas, pela disponibilidade e por toda a experiência adquirida no desenvolvimento deste trabalho. Aos doutorandos Vitor Pamplona e Leandro Fernandes pela ajuda revisando o texto e assistindo minha apresentação várias vezes. Suas críticas e comentários foram bastante valiosos. Por fim, agradeço minha família pelo carinho e apoio.
4 SUMÁRIO LISTA DE ABREVIATURAS E SIGLAS... 6 LISTA DE FIGURAS... 7 LISTA DE TABELAS... 8 RESUMO... 9 ABSTRACT INTRODUÇÃO O PIPELINE GRÁFICO Sumário A LINGUAGEM GLSL Shaders Evolução da programação de shaders Cg HLSL GLSL Sumário EVOLUÇÃO E O ESTADO DA ARTE EM HARDWARE GRÁFICOS Sumário REQUISITOS DE UM DEPURADOR Depuração em CPUs e GPUs Sumário TRABALHOS RELACIONADOS Depuradores de Programas OpenGL Depuradores e/ou editores de shaders Que não consideram o programa OpenGL hospedeiro Que consideram o programa OpenGL hospedeiro Sumário IMPLEMENTAÇÃO Biblioteca de funções Instrumentação do código Parser GLSL Interface Inicialização da Ferramenta Depuração Apenas do Shader Depuração do Programa OpenGL e do Shader... 49
5 7.4 Compilando o Shader Sumário RESULTADOS A Ferramenta Construída Exemplo de Execução Depuração do Programa OpenGL Hospedeiro Limitações Sumário CONCLUSÃO REFERÊNCIAS APÊNDICE A - Funções Inseridas na GLTrace... 67
6 LISTA DE ABREVIATURAS E SIGLAS ARB CPU GPU GUI SDK SLI Architecture Review Board Central Processing Unit Graphics Processing Unit Graphic User Interface Software Development Kit Scalable Link Interface
7 LISTA DE FIGURAS FIGURA 2.1: DIAGRAMA LÓGICO DA ARQUITETURA BÁSICA DA OPENGL 2.0 [ROS05] FIGURA 2.2:ENTRADAS E SAÍDAS DO PROCESSADOR DE VÉRTICES [ROS04] FIGURA 2.3: ENTRADAS E SAÍDAS DO PROCESSADOR DE FRAGMENTOS [ROS04] FIGURA 3.1: CENA DO JOGO CRYSIS FIGURA 3.2: PROCESSO DE COMPILAÇÃO DE UM PROGRAMA EM LINGUAGEM CG FIGURA 3.3:PROCESSO DE COMPILAÇÃO DE UM PROGRAMA EM LINGUAGEM GLSL FIGURA 4.1: IMAGEM EM TEMPO REAL COM O USO DA PLACA NVIDIA GEFORCEGTX280 [TWE08] FIGURA 4.2: IMAGEM EM TEMPO REAL COM O USO DA PLACA ATI RADEON HD4870X2 [AMD08] FIGURA 4.4:NVIDIA GEFORCEGTX FIGURA 5.1:REPRESENTAÇÃO DA VISUALIZAÇÃO DA DEPURAÇÃO DE QUATRO PROPRIEDADES DIFERENTES DE UM SHADER ESCRITO EM CG [DNB05A] FIGURA 6.1: INTERFACE DA FERRAMENTA SPYGLASS [MAG02] FIGURA 7.1: FLUXOGRAMA EM ALTO NÍVEL DA APLICAÇÃO FIGURA 7.2:FUNÇÕES ADICIONADAS AO CÓDIGO DA BIBLIOTECA NO INÍCIO DA EXECUÇÃO FIGURA 7.3: FUNÇÕES ADICIONADAS AO CÓDIGO DA BIBLIOTECA A CADA RENDERIZAÇÃO DA CENA FIGURA 7.4: FUNÇÕES ADICIONADAS AO CÓDIGO DA BIBLIOTECA AO INICIAR A EXECUÇÃO DO PROGRAMA FIGURA 7.5: FUNÇÕES ADICIONADAS AO CÓDIGO DA BIBLIOTECA A CADA RENDERIZAÇÃO DA CENA FIGURA 7.6: PASSOS NECESSÁRIOS PARA A CRIAÇÃO DE UM SHADER [FER06] FIGURA 7.7: EXEMPLO DE CASO ONDE DEVE SER INCLUÍDA A FUNÇÃO GL_POSITION (SUPERIOR) E DE QUANDO ELA NÃO DEVE SER INSERIDA (INFERIOR) FIGURA 7.9: VERSÃO RECEBIDA DA INTERFACE NOS PASSOS 1 E 2 DE EXECUÇÃO, RESPECTIVAMENTE.. 43 FIGURA 7.8: CÓDIGO FONTE ORIGINAL DO VERTEX SHADER FIGURA 7.10: VERSÃO DEVOLVIDA PARA A INTERFACE APÓS O PASSO FIGURA 7.11: VERSÃO DEVOLVIDA PARA A INTERFACE APÓS O PASSO FIGURA 7.12: VERSÃO DO FRAGMENT SHADER QUE É GERADA NOS PASSOS 1 E FIGURA 7.13: CÓDIGO ALTERADO PARA DEPURAÇÃO DE UM FRAGMENT SHADER FIGURA 7.14: INTERFACE DA FERRAMENTA FIGURA 7.15: FLUXOGRAMA SIMPLIFICADO DA EXECUÇÃO DO DEPURADOR FIGURA 7.16: CÓDIGO FONTE ORIGINAL (SUPERIOR) E CÓDIGO GERADO PELA INTERFACE NO TERCEIRO PASSO DA EXECUÇÃO (INFERIOR) FIGURA 8.1: INTERFACE GRÁFICA DA FERRAMENTA CONSTRUÍDA FIGURA 8.2: RESULTADO DO PASSO 1 DA DEPURAÇÃO. VALOR DA VARIÁVEL DO SHADER FIGURA 8.3: RESULTADO DO PASSO 1 DA DEPURAÇÃO. VALOR DA VARIÁVEL PRÉ-DEFINIDA GL_POSITION FIGURA 8.4: RESULTADO DO PASSO 2 DA DEPURAÇÃO. VALOR DA VARIÁVEL DO SHADER FIGURA 8.5: DEPURAÇÃO DO SHADER E PROGRAMA OPENGL HOSPEDEIRO FIGURA 9.1: PROPOSTA DE INTERFACE SHADER DESIGNER FIGURA 9.2: PROPOSTA DE INTERFACE COM OVISUAL STUDIO... 61
8 LISTA DE TABELAS TABELA 4.1: EVOLUÇÃO DAS PLACAS GRÁFICAS... 27
9 RESUMO Com a recente evolução das placas gráficas, suas arquiteturas passaram a apresentar alto grau de paralelismo e flexibilidade de programação. Os programas desenvolvidos para esta classe de hardware programável são chamados de shaders. As linguagens de programação de shaders também evoluíram, passando de Assembly para linguagens de mais alto nível, como Cg, HLSL e GLSL. Cg e HLSL são linguagens proprietárias bastante similares. Já GLSL, é uma extensão de OpenGL, que constitui um padrão aberto. Comparando as ferramentas existentes para depuração e análise de código destas linguagens, percebe-se que as ferramentas de GLSL ainda requerem aprimoramento para que a linguagem possua as mesmas facilidades de programação de linguagens de propósitos gerais ou mesmo das demais linguagens de programação de shaders. Isto faz com que desenvolvedores de software ainda gastem uma grande quantidade de tempo localizando e depurando erros de programação. Assim, o objetivo deste trabalho é desenvolver uma ferramenta que permita ao usuário depurar tanto o shader quanto o programa hospedeiro, facilitando o desenvolvimento integrado da aplicação. Para isto, foram desenvolvidos: (i) uma biblioteca de funções para interceptar as chamadas OpenGL durante a execução do programa, (ii) um parser de GLSL para criar uma representação intermediária, e, (iii) uma interface gráfica para controlar a execução da aplicação e do shader alvo. Uma vez que o depurador tenha sido finalizado, pretende-se, como trabalho futuro, integrar esta ferramenta com outras existentes permitindo ao usuário depurar, editar e visualizar o shader e, além disto, editar e compilar o programa OpenGL hospedeiro. Palavras-Chave: GLSL, depurador, shaders, edição e depuração de shaders.
10 glslangel: A Tool for Debugging OpenGL Shading Language ABSTRACT Due to the recent evolution of the graphic hardware, its architecture nowadays presents flexible programmability and it is highly parallel. Software developed for this class of programmable hardware is called shader. Shading languages also evolved, from Assembly to high level shading languages as Cg, HLSL and GLSL. Cg and HLSL are very similar proprietary languages. GLSL is an OpenGL extension. Comparing existent tools for debug and code analyses of shading languages, you notice that tools for GLSL still require improvement so that the language will have as many development facilities as general purpose languages or other shading languages. So, the developer still expend a lot of time tracking and debugging programming errors. Thus, the goal of this work is to develop a tool that allows the user to debug the shader and the host program, making the integrated development of applications easier. Therefore, it was developed: (i) an OpenGL wrapper to intercept OpenGL calls during the program execution, (ii) a GLSL parser to create an intermediate representation of the shader code, e, (iii) a graphic user interface to control the execution of the host application and the target shader. As future work, we intend to integrate this tool with other existent ones allowing the user not only to debug, but also edit and visualize the shader and, also, edit and compile the host program. Keywords: GLSL, debugger, shaders, edit and debug shaders.
11 11 1 INTRODUÇÃO Nos últimos anos a tecnologia das placas gráficas tem evoluído significativamente. Atualmente, sua arquitetura apresenta alto grau de paralelismo e flexibilidade de programação [GPU04]. Esta flexibilidade foi obtida através da substituição de alguns módulos fixos por outros programáveis em alguns pontos do pipeline de renderização [ROS04]. Tal evolução permitiu que algoritmos que antes eram determinados pela API utilizada pudessem ser implementados pelo desenvolvedor. Um exemplo destes algoritmos é o cálculo de iluminação, que a OpenGL permitia realizar apenas por vértices. Agora, é possível desenvolver um programa que realiza o cálculo por fragmento. Os programas escritos para explorar os recursos de programação desta classe de hardware são chamados de shaders. Inicialmente, os programas para GPUs eram escritos em linguagem Assembly, o que ocasionava uma baixa produtividade do processo de programação. Visando melhorar a produtividade dos programadores, linguagens de alto nível como Cg, HLSL e GLSL foram, então desenvolvidas. A base sintática e semântica destas linguagens é a linguagem de propósito geral C. As linguagens de programação de shaders apresentam alguns recursos característicos não presentes em linguagens de propósitos gerais, em virtude de serem voltadas para a implementação de algoritmos gráficos. Estes recursos visam facilitar a codificação e um maior aproveitamento do paralelismo presente nas placas gráficas. Entre eles, pode-se citar a definição de matrizes e vetores como primitivas da linguagem. Cg [MGA03] foi desenvolvida através de uma parceria entre NVIDIA e Microsoft. Cg e HLSL são basicamente a mesma linguagem. Porém, enquanto HLSL depende da interface de programação e só pode ser utilizado com Direct3D, Cg é independente. Assim, Cg pode ser utilizada tanto com Direct3D quanto com OpenGL [FER03]. Por fim, GLSL, cujo nome oficial é OpenGL Shading Language, é uma extensão da Application Programming Interface (API) OpenGL [ROS04]. OpenGL é um padrão aberto multiplataforma, por isto, a sua escolha como API considerada neste trabalho. Tanto Cg quanto GLSL podem ser utilizadas para desenvolvimento de shaders para OpenGL. Porém, optou-se por GLSL, pois esta apresenta algumas vantagens em relação à Cg. Como, por exemplo, o fato de que uma aplicação OpenGL existente e funcional pode ser facilmente adaptada para ser utilizada com shaders GLSL. O grande poder computacional das placas gráficas modernas, combinado com a facilidade destas linguagens de programação de alto nível, permite que algoritmos cada vez mais complexos sejam implementados em GPUs [SKE07]. Surge, então, a
12 12 necessidade de se dispor de melhores ambientes para desenvolvimento de shaders e programação de GPUs em geral. Fazendo uma analogia com a programação de CPUs, basta pensar no ganho em produtividade que se obtém com uso de ferramentas de depuração de código, às quais permitem ao programador examinar os valores das variáveis de um programa em qualquer instante de sua execução. A situação é similar na programação de shaders, e facilmente percebe-se a importância e os benefícios de ferramentas de depuração de shaders. Assim, o objetivo deste trabalho é desenvolver uma ferramenta de depuração para a linguagem GLSL. E, ser uma opção a mais para o usuário na hora do desenvolvimento. Apesar das semelhanças em termos de importância para o desenvolvimento de software, a implementação de ferramentas de depuração de shaders apresenta um grau de dificuldade consideravelmente maior que aquele associado à implementação de depuradores para programas que executam na CPU. Isto decorre do fato de que, como o depurador executa diretamente na CPU, este tem fácil acesso aos conteúdos das variáveis manipuladas pelo programa sendo depurado. Já no caso de depuração de shaders, enquanto o depurador executa na CPU, os shaders são executados por unidades processadoras autônomas (os processadores da GPU). Neste caso, a CPU não tem acesso direto aos conteúdos das variáveis manipuladas pela matriz de processadores que executam em paralelo na GPU. A CPU se comunica com a GPU por meio de um conjunto predefinido de mensagens disponibilizadas pelo driver da placa de vídeo e enviadas através do barramento (e.g., PCI Express). Além de ter que lidar com as restrições impostas pelas funções disponibilizadas pelo driver da placa para realização das trocas de mensagens, um depurador de shaders ainda precisa disponibilizar ao usuário os conteúdos das variáveis que caracterizam os estados dos programas em cada um dos vários processadores que executam em paralelo. Fica clara, assim, a maior dificuldade associada ao desenvolvimento de ferramentas para depuração de shaders. Com o objetivo de prover aos usuários ferramentas que facilitem o desenvolvimento de shaders, surgiram programas como o FXComposer 2.5 [NVI08], que fornece um ambiente para desenvolvimento e depuração de shaders em Cg e HLSL. Existem ainda outras ferramentas especificas para a depuração de shaders, como, por exemplo, a Apple OpenGL Shader Builder [APP02] que não considera o programa hospedeiro (por exemplo, escrito em OpenGL), e a Shadesmith [PS03] que considera o programa hospedeiro, porém, é necessário que o código fonte desta aplicação seja levemente alterado [SKE07]. Já programas como SpyGlass [MAG02], BuGLe [MER04] e gdebugger [GRA04] permitem a depuração da máquina de estados do OpenGL, mas não do shader. Até recentemente, não existiam ferramentas de depuração e análise de código da linguagem GLSL. A glsldevil [SKE07a], inspiração para o trabalho aqui descrito, foi a primeira ferramenta a depurar programas GLSL levando em conta o programa OpenGL hospedeiro sem a necessidade de recompilar ou mesmo de ter o código fonte deste programa hospedeiro. Ela intercepta os comandos da biblioteca de OpenGL para executar as novas funções instrumentadas com o código de depuração. Os dados extraídos dos comandos OpenGL podem então ser utilizados para depuração dos shaders ou análise do programa [SKE07a].
13 13 Neste trabalho desenvolvemos uma ferramenta de depuração para a linguagem GLSL similar à glsldevil, mas com algumas diferenças, como por exemplo, o suporte à edição e compilação de shaders. A razão para a implementação de um depurador é, principalmente, a possibilidade do aprendizado e de aprofundar o conhecimento em diferentes assuntos como, hardware gráfico programável, programação de shaders e criação de parsers de linguagens. Este trabalho encontra-se organizado da seguinte forma: os capítulos 2 à4 apresentam uma revisão sobre a arquitetura do pipeline gráfico da OpenGL, a linguagem GLSL, a evolução e o estado da arte em arquitetura de hardwares programáveis. Estes capítulos visam contextualizar o leitor. Por se tratar de uma ferramenta de depuração, o capítulo 5 apresenta a definição e os requisitos de um depurador. O capítulo 6 aborda as ferramentas relacionadas e desta forma, trará algumas das principais ferramentas de edição e depuração de programas OpenGL e shaders GLSL. No capítulo 7, será feita uma descrição detalhada do trabalho implementado. Os resultados obtidos e um exemplo de execução passo a passo serão demonstrados no capítulo 8. Finalmente, o capítulo 9 apresenta as conclusões e idéias para trabalhos futuros.
14 14 2 O PIPELINE GRÁFICO Este capítulo apresenta uma breve introdução ao pipeline gráfico, utilizando como base OpenGL. OpenGL é uma API multiplataforma padrão. Sua intenção é prover acesso às funcionalidades do hardware gráfico no mais baixo nível possível que ainda mantenha a independência de hardware. Pipeline gráfico é o nome dado a uma seqüência de operações que têm por objetivo gerar uma imagem 2D a partir de uma descrição de cena 3D. As operações de OpenGL são definidas para serem aplicadas em uma determinada ordem, assim, podemos ver OpenGL como um pipeline de processamento gráfico. Desde o lançamento da versão 1.0 de OpenGL, oito revisões da especificação foram lançadas, cada uma delas adicionando novas funcionalidades. A especificação da versão 3.0 já foi lançada em agosto de 2008 [OPE08], porém, a implementação atual suporta apenas a versão 2.1. Todas as versões anteriores a 2.0 eram baseadas em um pipeline fixo. O usuário controlava vários parâmetros, mas a funcionalidade intrínseca e a ordem de processamento eram fixas. A OpenGL 2.0 mudou isto. Foram acrescentadas funções que permitiam a programação dos processadores de vértices e de fragmentos, através do uso de uma linguagem de alto nível específica para este fim. Com esta versão, os desenvolvedores passaram a ter maior controle do pipeline de processamento e a desenvolver seus próprios algoritmos de renderização [ROS04]. Devido ao fato de ter sido projetada como uma máquina de estados de função fixa, antes da OpenGL 2.0 a programabilidade do hardware gráfico estava oculta e só era acessível através do uso de extensões. Atualmente existem mais de 400 extensões [OPE08]. A Figura 2.1 representa um diagrama lógico simplificado da OpenGL 2.0. A arquitetura básica da OpenGL não mudou desde a versão 1.1. A única diferença é que os processadores de vértices e de fragmentos eram módulos não programáveis, como indicados na Figura 2.1.
15 15 Figura 2.1: Diagrama lógico da arquitetura básica da OpenGL 2.0 [ROS05] Como pode ser visto na Figura 2.1, a entrada é a descrição de uma cena 3D representada na forma de primitivas geométricas (pontos, linhas, triângulos). Nos estágios seguintes, estas primitivas passam por uma série de operações que dão origem a uma representação 2D da cena. As descrições resumidas, a seguir, de cada um destes estágios foram baseadas em [ROS04, WOO99]. Memória da Aplicação - As formas primitivas de geometria suportadas pela OpenGL são pontos, linhas, polígonos e triângulos. Os dados sobre estas primitivas estão inicialmente armazenados em uma memória à qual a aplicação tem acesso. Processador de Vértices é um módulo programável onde ocorrem as operações sobre cada um dos vértices, como transformações, aplicação de cor e iluminação. Os shaders que executam neste módulo são chamados vertex shaders. Todas as funções realizadas pelo pipeline fixo devem estar contidas no código do shader. A Figura 2.2 representa as entradas e saídas possíveis do processador de vértices.
16 16 Figura 2.2:Entradas e saídas do Processador de Vértices [ROS04] Montagem de primitivas estágio onde os vértices são agrupados de acordo com o tipo primitivo da geometria. Processador de Geometria é um módulo programável que foi introduzido ao pipeline gráfico com o Shader Model 4.0 do DirectX [MIC08b]. O suporte para OpenGL é feito através do uso de uma extensão [NVI07]. A entrada deste módulo são os vértices transformados pelo processador de vértices. Diferentemente do processador de vértices que opera sobre um único vértice, o processador de geometria opera sobre todos os vértices de uma primitiva completa. Sua função principal é a geração de novas geometrias primitivas, que serão posteriormente processadas juntamente com as demais primitivas originais da aplicação [MIC08b]. Processamento de primitivas consiste nos processos de clipping [WOO99], projeção perspectiva, geração das coordenadas de janela e culling [WOO99]. Rasterização as primitivas são decompostas em partes menores correspondentes a um pixel no frame buffer. Cada uma destas partes é chamada de fragmento. Por exemplo, se uma linha (definida por dois vértices) cobre cinco pixels na tela, o processo de rasterização vai convertê-la em cinco fragmentos. Processador de fragmentos é um módulo programável. Depois dos fragmentos serem gerados pelo processo de rasterização, uma série de operações podem ser realizadas sobre eles, sendo que a mais importante provavelmente é o mapeamento de textura. Nesta operação, as coordenadas de textura associadas ao fragmento são utilizadas para acessar uma região da memória chamada memória de textura. Os shaders que executam neste módulo são chamados fragment shaders. Um shader não pode modificar as coordenadas (x,y) de um fragmento. O processador de fragmentos não substitui funcionalidades fixas, como por exemplo, testes de profundidade e operações
17 17 lógicas. A Figura 2.3: Entradas e saídas do Processador de Fragmentos [ROS04] apresenta os valores de entrada e saída do processador de fragmentos. Figura 2.3: Entradas e saídas do Processador de Fragmentos [ROS04] Operações por fragmento depois de processados, os fragmentos passam por uma série de operações simples, como por exemplo, teste de profundidade, para determinar a visibilidade do pixel de destino. Operações do Frame Buffer frame buffer é o conjunto de buffers do sistema. Assim, estas operações são responsáveis por controlar em quais buffers (front, back, left, etc) as primitivas serão desenhadas. O resumo destes estágios é que as primitivas definidas pela aplicação foram processadas, decompostas em partes menores (fragmentos), convertidas empixels no frame buffer e posteriormente, exibidas na tela. 2.1 Sumário Neste capítulo descrevemos brevemente o pipeline gráfico. Inicialmente foi apresentada a definição e o resumo da evolução da OpenGL. Em seguida foram descritos cada um dos estágios do pipeline gráfico. Assim, foram introduzidas noções relevantes para o entendimento do restante do trabalho, como as definições de vertex, geometry e fragment shader. No próximo capítulo serão apresentados o conceito de shaders e algumas de suas linguagens de programação, incluindo GLSL. O que permitirá ao leitor entender a importância do uso shaders e a necessidade de ferramentas que auxiliem seu desenvolvimento.
18 18 3 A LINGUAGEM GLSL Este capítulo apresenta o conceito de shaders e descreve, resumidamente, a evolução de suas linguagens de programação, incluindo a linguagem GLSL. Estes conceitos complementam o capítulo anterior fornecendo ao leitor as noções necessárias para a compreensão do trabalho. Além disto, permite ao leitor entender a importância do uso de shaders atualmente e, desta forma, a necessidade de ferramentas que auxiliem seu desenvolvimento. 3.1 Shaders Como dito anteriormente, shaders são programas desenvolvidos para executar nos processadores gráficos programáveis. Eles são os responsáveis pelos principais efeitos encontrados em aplicações gráficas atualmente. Dentre estes efeitos estão, por exemplo: (i) materiais mais realistas, como madeira e metal (ii) simulação de água, fogo e nuvens, (iii) iluminação de área, sombras suaves e (iv) sistemas de partículas e dinâmicas de fluídos. A Figura 3.1 [INC08] mostra, lado a lado, uma cena do jogo Crysis [CRY07] gerada sem o uso de shaders (esquerda) e com o uso de shaders (direita). Note que a imagem da direita apresenta mais realismo em função, por exemplo, da iluminação, das árvores mais encorpadas e principalmente dos reflexos e ondulações na superfície da água. Figura 3.1: Cena do jogo Crysis Sem shaders, o desenvolvedor está limitado às operações definidas pela API que está utilizando. Por exemplo, OpenGL suporta apenas iluminação pontual. Iluminação
19 19 por área, e, alguns dos efeitos mencionados no parágrafo anterior podem ser obtidos via software. Porém, isto acarreta em perda de desempenho, e em muitos casos, a execução não ocorre em tempo real. Existem três tipos de shaders: vertex shader, fragment shader e geometry shader. Um vertex shader realiza processamento de vértices e envolve as operações aplicadas a cada vértice, como transformações e iluminação. Por sua vez, um fragment shader é responsável pelo processamento de fragmentos e consiste nas operações realizadas sobre cada um deles como, por exemplo, iluminação por pixel. Um fragmento é uma estrutura de dados que contém todas as informações sobre um pixel após sua renderização, ou seja, é um candidato à pixel. Finalmente, um geometry shader, assim como o vertex shader, também é utilizado para processamento de vértices. Porém, ao invés de apenas processar as primitivas (pontos, linhas e triângulos) recebidas pela aplicação, ele é capaz de emitir novos vértices, gerando novas primitivas que serão processadas de forma equivalente às provenientes da aplicação [NVI07]. Um shader não executa sozinho, precisa estar ligado a um programa hospedeiro. É este programa que vai ser responsável pela ativação do shader e pode ser desenvolvido, por exemplo, utilizando APIs gráficas como OpenGL [OPE08] ou DirectX [MIC08]. A escolha da API gráfica utilizada pelo programa hospedeiro vai influenciar a escolha da linguagem a ser utilizada para a programação do shader. Se, por exemplo, a API escolhida para o programa hospedeiro for DirectX, o shader não poderá ser desenvolvido utilizando GLSL, pois a mesma só pode ser utilizada com OpenGL. Maiores detalhes sobre as linguagens de programação de shaders são apresentadas a seguir. 3.2 Evolução da programação de shaders O software RenderMan [UPS90] foi um dos primeiros a utilizar programas para realizar computação objetivando produzir efeitos individualizados a nível de pixel, sendo portanto um dos precursores da programação de shaders. A linguagem de programação utilizada neste software é a Renderman Shading Language e a execução dos programas desenvolvidos estava longe de ser em tempo real [ROS06]. O hardware gráfico evoluiu e passou a apresentar maior flexibilidade de programação. No entanto, as principais APIs existentes no início desta evolução (IrisGL, PEX, OpenGL, DirectX, etc.) não apresentavam suporte a estas funcionalidades. Assim, de um modo geral, os desenvolvedores utilizavam apenas funções fixas disponibilizadas por cada fabricante. Contudo, com a crescente demanda por efeitos mais sofisticados e que pudessem ser obtidos em tempo real, utilizar a possibilidade de programação disponível no hardware se tornou crucial e as APIs tiverem que se adaptar. Em OpenGL, esta adaptação ocorreu inicialmente na forma de extensões ao seu núcleo que eram disponibilizadas pelos fabricantes, de acordo com as necessidades apresentadas pelos desenvolvedores [ROS06]. Em 2002, o OpenGL Architecture Review Board (ARB) estabeleceu a ARB GPU Assembly Language como um conjunto padrão de instruções para programação de
20 20 GPUs [WIK08]. Nesta linguagem, toda programação é feita em baixo nível, o que consome muito tempo e dificulta o desenvolvimento de shaders. A solução natural para este problema seria utilizar linguagens de programação de alto nível. Atualmente, três das principais linguagens para desenvolvimento de shaders são Cg, HLSL e GLSL Cg Cg foi projetada para ser uma linguagem que pode ser utilizada tanto com DirectX quanto com OpenGL. Para isto, utiliza um módulo que traduz o código fonte do shader de Cg para programas em linguagem Assembly da respectiva API. A Figura 3.2 ilustra este processo. O tradutor fornecido pode ser utilizado com qualquer hardware que apresente suporte à DirectX ou OpenGL, porém, os shaders são compilados mais eficientemente para hardware NVIDIA. Mas, caso algum fabricante queira desenvolver seu próprio compilador, o código fonte está disponível para outras empresas [LOV05]. Aplicativo do usuário Fonte do shader Cg Tradutor de Cg NVIDIA Runtime Library Código Intermediário DirectX ou OpenGL API Cg Assembler DirectX ou OpenGL Código de máquina Hardware Gráfico Figura 3.2: Processo de compilação de um programa em linguagem Cg HLSL HLSL é uma linguagem proprietária da Microsoft que foi desenvolvida em parceria com a NVIDIA. Desta forma, é sintática e semanticamente similar à Cg. A principal diferença entre elas é que HLSL só pode ser utilizada com a API DirectX. Até o lançamento do DirectX 9, quando foi introduzida a HLSL, eram utilizadas linguagens Assembly diferentes para cada hardware gráfico de cada um dos principais fabricantes [PM03]. Certa dependência de hardware ainda existe, para que o código HLSL possa ser executado é necessário que o hardware suporte a versão do DirectX para o qual o
21 21 programa foi desenvolvido. A tradução do código fonte do shader para código de máquina segue os mesmos passos da tradução de Cg GLSL GLSL é uma linguagem de programação para GPUs introduzida na especificação 2.0 de OpenGL. Ela permite realizar a programação de processadores de vértices, de fragmentos, e de geometria. A GLSL possui suas raízes na linguagem C e desta forma, a estrutura básica dos programas desenvolvidos em ambas é a mesma. A primeira função executada em um shader é a função obrigatória main. Com o intuito de facilitar operações gráficas mais freqüentes, a linguagem apresenta tipos de dados que inclui o tipo matriz e o tipo vetor, o que resulta em um código mais conciso e legível, pois é possível realizar operações sobre estes tipos da mesma forma que se faria utilizando um escalar [OPE05]. Também foi adicionada uma primitiva sampler, que cria um mecanismo no qual shaders acessam a memória de textura, e os qualificadores attribute, uniform e varying, que especificam a entrada e saída de variáveis. Variáveis do tipo attribute indicam uma troca freqüente de valores entre a aplicação e o vertex shader, as do tipo uniform indicam uma troca pouco freqüente entre a aplicação e qualquer um dos shaders e as do tipo varying indicam interpolação entre os valores de um vertex shader para um fragment shader. A linguagem permite sobrecarga (overloading) de funções e declaração de variáveis em qualquer parte do código, e incluí suporte para laços, chamadas de subrotinas e expressões condicionais. A linguagem não suporta ponteiros, strings ou caracteres, nem operações baseadas nestes tipos. Não há limite para o tamanho do código de um shader escrito em GLSL [ROS04]. Atualmente, a GLSL encontra-se na versão 1.2. A versão faz parte da especificação da OpenGL 3.0, que, entre outras modificações, trás suporte para a diretiva #include [OPE08]. Os principais benefícios da linguagem GLSL são os seguintes [ROS04, WIK08b]: Foi projetada de tal forma que aplicações OpenGL existentes podem ser facilmente adaptadas para utilizá-la; A compilação ocorre em tempo de execução, assim, não requer alteração do código fonte para uso em plataformas diferentes; É uma linguagem de alto nível, portanto, é independente do código assembly específico de cada fabricante; É um padrão aberto multiplataforma; Permite a implementação de vários shaders simples ao invés de um único shader complexo; Tanto a linguagem quanto os requisitos necessários para a criação de um shader são parte da OpenGL. Não é preciso utilizar nenhuma biblioteca ou executável adicional. Diferentemente do que ocorre com Cg e HLSL, as funções de compilação e ligação são executadas diretamente pelo driver da placa de vídeo. Apenas o texto do
22 22 código fonte do shader é enviado para o driver OpenGL que irá então gerar o código objeto, compilar e linkar, gerando um programa em GLSL que será executado pelo pipeline gráfico. Sem uma camada de tradução de código intermediária, os fabricantes de hardware são livres para implementar e o otimizar o compilador GLSL da forma que melhor servir ao seu hardware. Além disto, se novas funcionalidades forem introduzidas ao hardware, basta apenas modificar o compilador GLSL no driver para fazer uso delas [LOV05]. Aplicativo do Usuário Fonte do shader API OpenGL Compilador GLSL GLSL Shader (programa) Compila o código do shader Ligador GLSL GLSL Shader (objeto) Código de Hardware Gráfico Figura 3.3:Processo de compilação de um programa em linguagem GLSL Segundo [ROS04], GLSL apresenta outras diferenças em relação à HLSL e Cg que podem ser vistas como vantagens de se utilizar GLSL: O uso de uma linguagem padrão que muda mais lentamente, mas que mantém a compatibilidade com as versões anteriores frente a uma linguagem proprietária que pode ou não manter tal compatibilidade; Foi projetada de tal forma que uma aplicação OpenGL existente e funcional, pode ser facilmente adaptada para utilizá-la; GLSL é compilada em tempo de execução pelo próprio driver do hardware gráfico, permitindo a geração de código de máquina otimizado para o hardware A descrição completa e detalhada da OpenGL Shading Language pode ser encontrada em [ROS04] e foge ao escopo deste trabalho.
23 Sumário Neste capítulo, foi dada uma breve introdução sobre o que são shaders, a evolução de suas linguagens de programação, e a Linguagem GLSL. Estes conceitos, juntamente com os apresentados no capítulo anterior, fornecem ao leitor as noções necessárias para o entendimento do trabalho. O próximo capítulo apresenta a evolução do hardware gráfico, desde o lançamento da primeira placa com aceleração 3D, até os dias atuais. Trás ainda imagens das arquiteturas do estado da arte em hardware gráfico. Permitindo ao leitor uma visão mais concreta, por exemplo, da localização dos processadores de shaders e do paralelismo das placas.
24 24 4 EVOLUÇÃO E O ESTADO DA ARTE EM HARDWARE GRÁFICOS Este capítulo apresenta alguns dos principais hardware gráficos e seu papel na evolução desta classe de hardware, desde o lançamento do primeiro hardware gráfico com aceleração 3D até o momento da escrita deste trabalho. Ao final do capítulo, a Tabela 4.1 resume o que foi dito apresentando as imagens e o ano de lançamento destas placas. Hardware gráfico ou GPU (Graphics Processing Unit) é um dispositivo para computadores pessoais, estações de trabalho ou consoles de jogos, que é especializado em renderização gráfica. As GPUs atuais são muito eficientes para manipulação e exibição de aplicativos de computação gráfica, e sua estrutura paralela faz com que sejam mais eficientes do que as CPUs para o processamento de uma vasta gama de algoritmos mais complexos que apresentam alto grau de paralelismo, baixa sincronização entre processadores e baixo acesso a memória [WIK08c]. Um hardware gráfico pode ser uma placa em separado ou estar integrado ao chipset da placa mãe, como é o caso, por exemplo, do Intel Graphics Media Accelerator (GMA) [INT08], atual linha de processadores gráficos integrados da Intel. Porém, neste trabalho, nos atemos às placas não integradas. A seguir, um histórico apresentando algumas das principais placas lançadas e relatando a evolução desta classe de hardware. A principal referência para a escrita deste histórico foi o artigo de Thomas Monk [MON06]. Um dos primeiros hardware gráficos de aceleração 3D a ser lançado foi a placa Voodoo, em outubro de 1996, pela 3Dfx. Antes disto, empresas como a NVIDIA já haviam lançado outros hardware gráficos, porém sem a capacidade de aceleração 3D, como o NV1, que apresentava como diferencial uma placa de som onboard e equações quadráticas para renderização, ao invés de polígonos [SUN06]. Com a introdução pela Microsoft do Direct3D, que utiliza polígonos, ao seu sistema operacional Windows, as placas NV1 se tornaram obsoletas e abriram espaço para placas como a Voodoo. A primeira concorrente da Voodoo foi a placa Rage II da ATi lançada em março de 1997, que, por apresentar desempenho apenas similar e não superior à rival, não fez muito sucesso. Performance superior foi apresentado apenas pela placa da NVIDIA Riva128, lançada em agosto de Este aumento no desempenho foi principalmente devido a um barramento de memória maior e as funções pré-definidas para DirectX. A Voodoo não apresentava suporte à DirectX, pois a 3Dfx havia desenvolvido sua própria API, a GLIDE. Tanto a Voodoo quanto a Rage II e a Riva 128 apresentavam suporte mínimo à OpenGL.
25 25 Em 1998, a 3Dfx lançou a sucessora da Voodoo, a Voodoo2. Este novo chipset apresentava duas unidades de processamento de texturas e um aumento na velocidade de clock que dobrou seu desempenho, além de permitir o uso de duas placas trabalhando em conjunto: SLI. SLI (Scalable Link Interface) permite que múltiplas GPUs trabalhem juntas para aumentar a performance. Quando duas placas gráficas estão conectadas via SLI, o driver reconhece esta configuração e trata as duas placas como se fossem apenas uma, fazendo com que seja transparente para a aplicação o fato de que mais de uma placa está sendo utilizada [NVI06]. Em março de 1999, a NVIDIA lançou a placa TNT2, apresentando cores de 32 bits, suporte à Z-buffer, boa qualidade de imagem e ótima performance. Ela foi responsável pelo fim do domínio de mercado da 3Dfx nesta área. Em agosto 1999, a NVIDIA lançou a GeForce256, primeira placa a realizar cálculos de transformações e de iluminação em hardware. Foi neste ano também que os fabricantes passaram a oferecer suporte completo à OpenGL e os chipsets gráficos passaram a ser tratados por GPU (Graphical Processing Unit). Em 2000, a 3Dfx lançou, entre outras, a Voodoo , que apresentava até quatro chipsets trabalhando em paralelo. Era o início da exploração do paralelismo nas placas. Apesar de rápida, esta abordagem requeria um aumento na quantidade de memória utilizada, o que fez com que o preço da placa se elevasse. Com o lançamento da GeForce2GTS, mais barata e com melhor desempenho, a NVIDIA dominou o mercado. Em fevereiro de 2001, com o lançamento da GeForce3, a NVIDIA revolucionou o mundo de desenvolvimento de jogos e aplicativos gráficos: Foi a primeira placa a apresentar módulos programáveis. Estes módulos foram chamados de Vertex Shader e Pixel Shader. O desenvolvedor podia agora programar seu chipset, permitindo a implementação de qualquer função especifica desejada. Ou seja, era o início da utilização de shaders (Vide capítulo Erro! Fonte de referência não encontrada.). Para competir com a NVIDIA, a ATi lançou em agosto de 2001, a Radeon8500, cujo principal diferencial era oferecer suporte ao DirectX 8.1, pois como a GeForce3 foi lançada em fevereiro e o DirectX 8.1 em junho, a GeForce3 só oferecia suporte ao DirectX 8.0. Além disto, a performance apresentada pela Radeon8500 era entre 10% e 20% superior à performance apresentada pela GeForce3. Nas famílias seguintes, GeForce4 e Radeon9700Pro, lançadas em 2002, além da possibilidade de programação do chipset, as placas ainda apresentavam 4 e 8 pipelines de renderização, respectivamente, funcionando em paralelo. E de lá para cá, muitas novas placas foram lançadas, mas sempre seguindo os paradigmas de flexibilidade de programação e paralelismo.atualmente, o que se percebe é uma corrida na busca pelo melhor desempenho visando obter imagens cada vez mais realistas. Um exemplo disto é a possibilidade de executar algoritmos de Ray tracing em tempo real. Ray tracing é uma técnica de geração de imagens a partir do traçado dos caminhos percorridos pelo raio de luz ao colidir ou passar por objetos em uma cena. Com esta técnica é possível obter imagens fotorealísticas, mas, os algoritmos necessários para produzir estas imagens são muito complexos e requerem grande poder computacional para os PCs existentes hoje, principalmente se desejar fazer isto em tempo real [ALT08]. No entanto, utilizando as placas NVIDIA GeForceGTX280 [ANA08a] e ATi RadeonHD4870x2 [ANA08], Ray tracing em tempo real é possível. Os resultados obtidos são as imagens fotorealísticas das Figura 4.1 e Figura 4.2 abaixo.
26 26 Figura 4.1: Imagem em tempo real com o uso da placa NVIDIA GeForceGTX280 [TWE08] Figura 4.2: Imagem em tempo real com o uso da placa ATi Radeon HD4870x2 [AMD08] A arquitetura destas placas apresenta dezenas de unidades de textura, centenas de processadores, bilhões de transistores e velocidade de clock em torno de 1GHz [ADR08, AMD08a]. Além da capacidade de utilização de SLI (Scalable Link Interface), o que aumenta ainda mais o desempenho destas placas. A Figura4.3 e a Figura 4.4 representam o estado da arte, no momento da escrita deste trabalho, no que diz respeito à arquitetura de hardware programáveis. Com estas imagens é possível ter uma noção mais clara, por exemplo, da localização dos processadores de shaders. O paralelismo dos módulos de processamento também é facilmente observável Figura 4.3: ATiRadeon 4870x2 Figura 4.4:NVIDIA GeforceGtx Sumário Este capítulo apresentou a evolução do hardware gráfico 3D. Apesar de não ser crucial para o entendimento do trabalho como um todo, conhecer esta evolução fornece ao leitor uma noção mais clara de tempo. Por exemplo, quando foram lançadas as primeiras placas a apresentarem módulos programáveis ao invés de fixos. E com esta noção é possível, por exemplo, comparar a evolução das placas e de suas linguagens de programação. E, verificar que as placas evoluíram muito mais rapidamente. No próximo capítulo serão apresentados os requisitos de um depurador. Desta forma, o leitor já terá uma idéia inicial sobre o que esperar de funcionalidades disponibilizadas pela ferramenta descrita neste trabalho.
27 27 Tabela 4.1: Evolução das placas gráficas Ano 3DFx NVIDIA ATi Voodoo NV Riva128 3D Rage Voodoo 2 Riva TNT Voodoo GeForce GeForce 3 Radeon GeForce4 Radeon GeForce FX280 Radeon 4800HD 2008
28 28 5 REQUISITOS DE UM DEPURADOR Depurar um programa é procurar por erros neste programa. Existem diferentes métodos de depuração como, por exemplo, imprimir o valor de uma variável na tela. Pode-se também, utilizar um depurador, que é um programa que auxilia a detectar, localizar e corrigir erros em outro programa. Quando o programa que está sendo depurado para em função de algum problema, o depurador apresenta a posição no código original. Ele permite ao desenvolvedor percorrer o processo de execução monitorando memória, variáveis e outros elementos do contexto. Também oferecem funções mais sofisticadas como percorrer o programa passo a passo e parar em uma determinada função para examinar o estado atual do processo através da inserção de pontos de parada [MIC08]. 5.1 Depuração em CPUs e GPUs A depuração de um programa depende da linguagem em que se está programando e as ferramentas disponíveis para esta linguagem. Ou seja, a existência ou não de ferramentas de depuração para a linguagem é um dos fatores determinante para a escolha do método de depuração. Para a linguagem Assembler, por exemplo, Tim Paterson, desenvolvedor do sistema operacional MS-DOS, incluiu ao sistema uma ferramenta chamada DEBUG, que entre outras funcionalidades permitia ao usuário executar sub-rotinas individualmente, percorrer interrupções uma a uma e converter instruções Assembler diretamente em código de máquina, evitando que o usuário tivesse que utilizar outra ferramenta para este fim [WIK08b]. Com o passar do tempo e surgimento de linguagens de mais alto nível como C++ e Java, por exemplo, foram desenvolvidos ambientes integrados de desenvolvimento que permitem ao usuário editar, compilar e depurar o programa que está sendo desenvolvido. Eclipse [ECL08], Microsoft Visual Studio [MIC08e] e MonoDevelop [GNO08] são exemplos destes ambientes. Quando a linguagem não possui ferramentas de depuração, uma técnica utilizada para fazer o rastreamento das funções executadas é imprimir em algum dispositivo de saída (tela ou arquivo, por exemplo) os valores de variáveis em certos pontos da execução do programa. Apesar de ser uma técnica típica de depuração de linguagens voltadas à programação de CPUs, até recentemente, era a única forma de depurar programas escritos para GPUs. Este processo requeria extensa modificação do código fonte tanto do programa hospedeiro como do shader e a técnica utilizada para exibir os valores na tela era a apresentação de imagens na tela com uma codificação de cores
29 29 representando os valores das variáveis a serem inspecionadas. Alternativamente, estes valores eram escritos nos canais RGBA das texturas. A Figura 5.1 apresenta um exemplo de quatro visualizações de depuração de um programa escrito em Cg, onde cores diferentes, por exemplo, representam valores diferentes de uma mesma propriedade. Estas visualizações podem ser obtidas com o uso da ferramenta descrita em [DNB05], que é uma ferramenta para depuração de programas escritos na linguagem Cg e que automatiza o processo de visualização, não sendo mais necessária a inserção de funções extras ao código. Figura 5.1:Representação da visualização da depuração de quatro propriedades diferentes de um shader escrito em Cg [DNB05a] De acordo com [OLG*07], um depurador de hardware gráfico programável deve apresentar capacidades similares aos depuradores tradicionais de CPU, definidas no parágrafo inicial deste capítulo. Deve permitir o acompanhamento das alteraçõesdos valores de variáveis, inserção de pontos de parada e execução passo a passo. Deve ser fácilmente utilizado com uma aplicação existente, deve interferir o mínimo possível no estado da GPU e deve executar o código do depurador na GPU e não via software. E, finalmente, um depurador de GPU deve suportar a maioria das APIs de programação de GPU e extensões específicas de cada fabricante. O depurador ideal automatiza a depuração estilo printf. Ou seja, ele automatiza a exibição dos dados de um conjunto de pixels sob a forma de uma imagem, deste modo, os valores de interesse podem ser visualizados mais facilmente do que se fossem exibidos como texto apenas. 5.2 Sumário Neste capítulo foram apresentado os requisitos gerais de um depurador. Além disto, foi traçado um paralelo entre a depuração em CPUs e GPUs. O que permitiu ao leitor verificar a importância das ferramentas de depuração para o desenvolvedor. Pois, estas permitem que erros sejam localizados mais facilmente, diminuindo o tempo gasto neste processo. Por fim, foram apresentados os requisitos específicos de um depurador para linguagens de programação de GPUs. No próximo capítulo serão apresentados os trabalhos relacionados. Serão descritas as principais ferramentas para edição/depuração de shaders GLSL. O final do próximo capítulo estará claro a deficiência de boas ferramentas para auxiliar o desenvolvimento de shaders em linguagem GLSL.
30 30 6 TRABALHOS RELACIONADOS Este capítulo apresenta os trabalhos relacionados a ferramentas de desenvolvimento de shaders. Existem várias ferramentas voltadas para a depuração e/ou edição de programas OpenGL e de shaders GLSL. Por possuírem características diferenciadas, podem ser divididos basicamente em três grupos: Depuradores de programas OpenGL ; Depuradores e/ou editores de shaders GLSL que não consideram o programa OpenGL hospedeiro; Depuradores e/ou editores de shaders GLSL que consideram o programa OpenGL hospedeiro. Neste capítulo serão descritas e comparados algumas destas ferramentas, dando ênfase ao suporte ou não das funcionalidades relevantes (i.e. depuração e edição de shaders e do programa OpengGL hospedeiro). 6.1 Depuradores de Programas OpenGL Com o crescimento da utilização de shaders, poucas ferramentas se limitam a depurar apenas ao programa OpenGL e, a maioria, são ferramentas simples que fornecem ao usuário poucas funcionalidades. A gdebugger [GRA04] era uma ferramenta mais sofisticada que em versões passadas depurava apenas o programa OpenGL. Porém, em sua versão atual também passou a oferecer suporte para a edição de shaders e assim, será descrita posteriormente. GLTrace [HAW05] é a mais simples delas. Esta ferramenta intercepta as chamadas OpenGL e gera um log em um arquivo texto relativo a estas chamadas. Suporta apenas a versão 1.1 da especificação OpenGL. Neste trabalho estendemos a GLTrace para a especificação 2.1 da OpenGL. A sessão 7.1 apresenta os detalhes desta extensão. SpyGlass [MAG02] desenvolvido para sistemas Unix, também intercepta as chamadas OpenGL. A principal diferença é que este apresenta uma interface gráfica e permite ao usuário não apenas gerar um log das chamadas, mas também depurar o programa. A Figura 6.1 apresenta esta interface, como se pode ver,não é um depurador sofisticado, permitindo basicamente apenas execução passo a passo e inserção de pontos de parada.
31 31 Figura 6.1: Interface da ferramenta SpyGlass [MAG02] BuGLe [MER04], também desenvolvido para sistemas Unix, é um depurador que permite visualizar as chamadas OpenGL, tirar um screenshot, capturar um vídeo do programa em execução, verificar erros a cada chamada, exibir estatísticas da execução (por exemplo, frame rate), forçar a renderização em modo wireframe e setar pontos de parada. Uma interface gráfica está em desenvolvimento. 6.2 Depuradores e/ou editores de shaders Que não consideram o programa OpenGL hospedeiro O grupo de ferramentas descrito anteriormente estava focado no programa OpenGL e não levava em consideração a existência ou não de shaders. Este grupo, por outro lado, foca no desenvolvimento de shaders e nem sequer necessita de um programa OpenGL hospedeiro. O shader é executado dentro da própria ferramenta, permitindo ao usuário obter o efeito desejado. A ferramenta Shader Designer [TYP07] foi desenvolvida pela TyphooonLabs para os sistemas operacionais Windows e Linux, tendo sido projetada com o objetivo de facilitar o desenvolvimento de shaders utilizando GLSL. Apresenta um ambiente de desenvolvimento integrado (IDE) com renderização em tempo real do shader, acesso a estados relevantes de OpenGL, compilação offline, validação do shader, múltiplos formatos de textura, entre outras características. Não apresenta suporte para depuração do shader. Esta ferramenta teve sua produção descontinuada pela TyphoonLabs, porém, ainda está disponível para download gratuitamente [WIK08b]. OpenGL Shader Builder [APP02] desenvolvida para o sistema Mac OS, provê uma IDE para o desenvolvimento e depuração de shaders GLSL. A janela principal engloba um editor, um depurador que permite visualizar o conteúdo das variáveis, execução passo a passo, reiniciar a execução e um gerenciador de recursos que exibe informações sobre texturas, variáveis temporárias, etc.. Assim como o anterior, permite a renderização e visualização em tempo real do resultado dos efeitos desenvolvidos aplicados a um objeto. RenderMonkey [AMD08] desenvolvida para o sistema Windows, sua principal diferença frente às anteriores é que ela não suporta apenas GLSL, mas também, HLSL. Outra diferença é a presença de interfaces diferenciadas para programadores e artistas.