Obtendo o número de fragmentos que passaram no teste de profundidade

8

Em ambientes "modernos", a extensão "NV Occlusion Query" fornece um método para obter o número de fragmentos que passaram no teste de profundidade. No entanto, no iPad / iPhone usando o OpenGL ES, a extensão não está disponível.

Qual é a abordagem de melhor desempenho para implementar um comportamento semelhante no shader de fragmento?

Algumas das minhas idéias:

  • Renderize o objeto completamente em branco, depois conte todas as cores usando um sombreador de duas passagens, onde primeiro uma linha vertical é renderizada e, para cada fragmento, o sombreador calcula a soma em toda a linha. Então, um único vértice é renderizado, cujo fragmento soma todas as somas parciais da primeira passagem. Não parece ser muito eficiente.

  • Renderize o objeto completamente em branco sobre um fundo preto. Reduza a amostra recursivamente, abusando da interpolação linear do hardware entre as texturas até atingir uma resolução razoavelmente pequena. Isso leva a fragmentos que possuem um nível de escala de cinza, dependendo do número de pixels brancos em sua região correspondente. Isso é preciso o suficiente?

  • Use mipmaps e simplesmente leia o pixel no nível 1x1. Novamente, a questão da precisão e se é possível usar texturas que não sejam de duas.

O problema com essas abordagens é que o pipeline fica parado, o que resulta em grandes problemas de desempenho. Portanto, estou procurando uma maneira mais eficiente de alcançar meu objetivo.

Usando a extensão EXT_OCCLUSION_QUERY_BOOLEAN

A Apple apresentou EXT_OCCLUSION_QUERY_BOOLEAN no iOS 5.0 para iPad 2.

"4.1.6  Occlusion Queries

Occlusion queries use query objects to track the number of fragments or 
samples that pass the depth test. An occlusion query can be started and 
finished by calling BeginQueryEXT and EndQueryEXT, respectively, with a 
target of ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.

When an occlusion query is started with the target 
ANY_SAMPLES_PASSED_EXT, the samples-boolean state maintained by the GL is
set to FALSE. While that occlusion query is active, the samples-boolean 
state is set to TRUE if any fragment or sample passes the depth test. When 
the occlusion query finishes, the samples-boolean state of FALSE or TRUE is
written to the corresponding query object as the query result value, and 
the query result for that object is marked as available. If the target of 
the query is ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, an implementation may 
choose to use a less precise version of the test which can additionally set
the samples-boolean state to TRUE in some other implementation dependent 
cases."

A primeira frase sugere um comportamento exatamente o que estou procurando: obter o número de pixels que passaram no teste de profundidade de maneira assíncrona, sem muita perda de desempenho. No entanto, o restante do documento descreve apenas como obter resultados booleanos.

É possível explorar esta extensão para obter a contagem de pixels? O hardware o suporta para que possa haver API oculta para obter acesso à contagem de pixels?

Outras extensões que poderiam ser exploradas seriam recursos de depuração, como o número de vezes que o shader de fragmento foi chamado (PSInvocations no DirectX - não tenho certeza se algo semelhante está disponível no OpenGL ES). No entanto, isso também resultaria em uma paralisação do pipeline.

Etan
fonte
Qual é o efeito final que você está tentando alcançar?
Tetrad
Preciso da contagem de pixels não para um efeito de renderização, mas para computação. Eu quero usá-lo para calcular pesos de partículas em um filtro de partículas.
Etan
A apple suporta AMD_performance_monitor? Se sim, você poderá encontrar o contador que mostra os pixels passados. Observe que isso é muito, muito específico do dispositivo, mesmo que você o faça funcionar.
precisa
O problema com o AMD_performance_monitor seria que ele não é assíncrono, portanto a perda de desempenho também estaria presente, pois tenho que esperar entre os quadros para saber que as invocações do próximo quadro já não terão efeito nos contadores de desempenho.
Etan 27/11
Além disso, o AMD_performance_monitor não está disponível.
Etan

Respostas:

1

É possível explorar esta extensão para obter a contagem de pixels? O hardware o suporta para que possa haver API oculta para obter acesso à contagem de pixels?

Não e não. Bem, eu suponho que se você desenhar uma série de triângulos do tamanho de um pixel no espaço da janela, poderá contar quantos valores booleanos obtém. Mas isso exigiria uma consulta separada para cada pixel. Provavelmente não é a coisa mais rápida do mundo.

Se houver uma "API oculta", você não terá acesso a ela (uma vez que está oculta), por isso não importa. Além disso, a natureza da extensão já sugere que não existe. Afinal, se o hardware tinha a contagem real de fragmentos, por que não apenas expô-lo diretamente, como o OpenGL da área de trabalho? Se o hardware o suportasse, eles poderiam apenas pegar o ARB_occlusion_query e usá-lo.

Mas eles não fizeram. O que sugere fortemente que eles não poderiam.

Nicol Bolas
fonte
Obrigado pela resposta! A abordagem com triângulos do tamanho de um pixel pode ser aprimorada simplesmente renderizando pontos ou pequenas linhas, e pode até ser aprimorada por uma escala logarítmica em que uma linha que retorna "true" é simplesmente dividida no meio e depois as duas partes são verificadas novamente. Ainda não tenho certeza do desempenho, pois os modelos não terão mais de 100-200 vértices. O raciocínio para a inexistência da "API oculta" também é válido. Existem outros meios de obter os dados da GPU de volta para a CPU de maneira assíncrona, sem uma interrupção no pipeline (também formas invasivas, por favor)?
Etan
0

Os resultados são retornados em um GLuint (também pode ser GLint para uma chamada diferente), infelizmente, o resultado é sempre 0 ou 1, talvez eles o alterem para registrar frags no futuro.

também parece que nenhuma pessoa em toda a Internet postou sobre essas novas extensões ... então aqui elas estão configuradas corretamente ... o que não está documentado em nenhum lugar, tanto quanto eu saiba ... você pode imaginar como elas iria no seu código a partir deste pequeno código sudo aqui:

import UIKit/UIKit.h

import GLKit/GLKit.h

import "GLProgram.h"

GLuint testBox,hasBeenTested,theParams;

//...

glGenQueriesEXT(1, &testBox);

glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, testBox);


//... draw an object .......

glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);

glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_AVAILABLE_EXT, &hasBeenTested);

if (hasBeenTested) glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_EXT, &theParams);

glDeleteQueriesEXT(1, &testBox);

if (!theParams)  object is hidden;  don't draw next time;
honjj
fonte
Só porque o tipo diz GLintnão significa que é uma contagem inteira do número de fragmentos que passam. A especificação é bastante clara de que o QUERY_RESULT_EXTestado é um valor booleano; basta consultá-lo como um número inteiro. É GL_FALSEse falhou e não GL_FALSEse passou.
Nicol Bolas
Eu tinha acabado de implementar o código e descobri que era apenas verdadeiro ou falso e mudei minha resposta antes de ver seu comentário ... como é uma cola, talvez eles adicionem estados no futuro.
honjj
a propósito, parece haver um bug no GKKit, onde se você usar self.effect2 = [[GLKBaseEffect aloc] init]; tipo de código GLKit tipo de código para renderizar um objeto, em vez de um pipeline GLES2.0 normal, as consultas não fornecerão a resposta correta ... (nunca ocultas), embora eu tenha testado um objeto pipeline que oculta um objeto GLKBaseEffect, por isso poderia estar lá é um bug apenas misturar os dois, eu não ainda mais um teste ...
honjj
As extensões são explicadas com exemplos nos vídeos da WWDC, que podem ser encontrados no site da Apple com uma conta de desenvolvedor ativa.
Etan