Pergunta

Com que frequência devo chamar funções OpenGL como glEnable() ou glEnableClientState() e seus correspondentes glDisable homólogos?Eles devem ser chamados uma vez no início do aplicativo ou devo mantê-los desativados e ativar apenas os recursos necessários imediatamente para desenhar algo?Existe uma diferença de desempenho?

Foi útil?

Solução

"Depende".

Se o aplicativo inteiro usa apenas uma combinação de estados de ativação/desativar, então, por todos os meios, basta configurá -lo no início e ir.

A maioria dos aplicativos do mundo real precisa se misturar, e então você é forçado a ligar glEnable() Para ativar algum estado (s) em particular, faça as chamadas de sorteio, então glDisable() eles novamente quando terminar de "limpar o palco".

Estado, rastreamento estatal e muitos esquemas de otimização decorrem disso, pois a troca de estado às vezes é cara.

Outras dicas

Se você descobrir que está verificando o valor das variáveis ​​de estado com frequência e subsequentemente chamando glEnable/glDisable, poderá limpar um pouco as coisas usando a pilha de atributos (glPushAttrib / glPopAttrib).

A pilha de atributos permite isolar áreas do seu código e de forma que as alterações no atributo em uma seção não afetem o estado do atributo em outras seções.

void drawObject1(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);    

  /* Isolated Region 1 */

  glPopAttrib();
}        

void drawObject2(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_FOG);
  glEnable(GL_GL_POINT_SMOOTH);    

   /* Isolated Region 2 */

  glPopAttrib();
}    

void drawScene(){
  drawObject1();
  drawObject2();
}

Embora GL_LIGHTING e GL_DEPTH_TEST são definidos em drawObject1, seu estado não é preservado em drawObject2.Na ausência de glPushAttrib, este não seria o caso.Além disso - observe que não há necessidade de chamar glDisable no final das chamadas de função, glPopAttrib faz o trabalho.

No que diz respeito ao desempenho, a sobrecarga devida às chamadas de função individuais para glEnable/glDisable é mínima.Se você precisar lidar com muitos estados, provavelmente precisará criar seu próprio gerenciador de estados ou fazer inúmeras chamadas para glGetInteger...e então agir de acordo.O maquinário adicionado e o fluxo de controle poderiam tornar o código menos transparente, mais difícil de depurar e mais difícil de manter.Esses problemas podem dificultar outras otimizações mais frutíferas.

A pilha de atribuição pode ajudar a manter camadas de abstração e criar regiões de isolamento.

Página de manual glPushAttrib

Primeiramente, qual versão do OpenGL você usa?E qual geração de hardware gráfico seu grupo-alvo possui?Saber disso tornaria mais fácil dar uma resposta mais correta.Minha resposta assume OpenGL 2.1.

OpenGL é uma máquina de estado, o que significa que sempre que um estado é alterado, esse estado se torna "atual" até ser alterado novamente explicitamente pelo programador com uma nova chamada de API OpenGL.Existem exceções a esta regra, como chamadas de matriz de estado do cliente que tornam a cor do vértice atual indefinida.Mas essas são as exceções que definem a regra.

"uma vez no início da aplicação" não faz muito sentido, porque há momentos em que você precisa destruir seu contexto OpenGL enquanto o aplicativo ainda está em execução.Presumo que você queira dizer logo após a criação de cada janela.Isso funciona para um estado que você não precisa alterar mais tarde.Exemplo:Se todas as suas chamadas de desenho usarem os mesmos dados de matriz de vértices, você não precisará desativá-las com glDisableClientState posteriormente.

Há muitos estados de ativação/desativação associados ao antigo pipeline de função fixa.A redenção fácil para isso é:Use sombreadores!Se você tiver como alvo uma geração de placas com no máximo cinco anos de idade, ela provavelmente imitará o pipeline de função fixa com shaders.Ao usar shaders você tem controle mais ou menos total do que está acontecendo durante os estágios de transformação e rasterização, e pode criar seus próprios "estados" com uniformes, que são muito baratos para alterar/atualizar.

Saber que o OpenGL é uma máquina de estado como eu disse acima deve deixar claro que devemos nos esforçar para manter as mudanças de estado no mínimo, desde que seja possível.No entanto, provavelmente há outras coisas que afetam muito mais o desempenho do que ativar/desativar chamadas de estado.Se você quiser saber sobre eles, leia.


A despesa do estado não associado às antigas chamadas de estado de função fixa e que não é um simples estado de ativação/desativação, pode diferir amplamente em custo.Notavelmente, vincular shaders e vincular nomes ("nomes" de texturas, programas, objetos de buffer) geralmente são bastante caros.É por isso que muitos jogos e aplicativos costumavam classificar a ordem de desenho de suas malhas de acordo com a textura.Dessa forma, eles não precisaram unir a mesma textura duas vezes.Hoje em dia, porém, o mesmo se aplica aos programas shader.Você não deseja vincular o mesmo programa de shader duas vezes se não for necessário.Além disso, nem todos os recursos de uma versão específica do OpenGL são acelerados por hardware em todas as placas, mesmo que os fornecedores dessas placas afirmem que são compatíveis com OpenGL.Estar em conformidade significa que eles seguem as especificações, não que necessariamente executem todos os recursos com eficiência.Algumas das funções como glHistogram e glMinMax do GL__ ARB __imaging devem ser lembradas a esse respeito.


Conclusão:A menos que haja uma razão óbvia para não fazê-lo, use shaders!Isso evita muitas chamadas estaduais desnecessárias, já que você pode usar uniformes.Os shaders OpenGL já existem há cerca de seis anos, você sabe.Além disso, a sobrecarga de alterações de estado de ativação/desativação pode pode ser um problema, mas geralmente há muito mais a ganhar com a otimização de outras mudanças de estado mais caras, como glUseProgram, glCompileShader, glLinkprogram, glBindBuffer e glBindTexture.

P.S:O OpenGL 3.0 removeu as chamadas de ativação/desativação do estado do cliente.Eles estão implicitamente habilitados, pois desenhar matrizes é a única maneira de desenhar nesta versão.O modo imediato foi removido.As chamadas gl..Pointer também foram removidas, já que na verdade só é necessário glVertexAttribPointer.

Uma regra prática que fui ensinada disse que quase sempre é mais barato apenas habilitar/desativar à vontade, em vez de verificar o estado atual e mudar apenas se necessário.

Dito isto, a resposta de Marc é algo que definitivamente deve funcionar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top