Obtenir le nombre de fragments qui ont réussi le test de profondeur

8

Dans les environnements "modernes", l' extension "NV Occlusion Query" fournit une méthode pour obtenir le nombre de fragments qui ont réussi le test de profondeur. Cependant, sur l'iPad / iPhone utilisant OpenGL ES, l'extension n'est pas disponible.

Quelle est l'approche la plus performante pour implémenter un comportement similaire dans le shader de fragments?

Certaines de mes idées:

  • Rendez l'objet complètement en blanc, puis comptez toutes les couleurs ensemble à l'aide d'un shader à deux passes où une ligne verticale est d'abord rendue et pour chaque fragment, le shader calcule la somme sur toute la ligne. Ensuite, un seul sommet est rendu dont le fragment additionne toutes les sommes partielles de la première passe. Ne semble pas très efficace.

  • Rendez l'objet complètement en blanc sur un fond noir. Sous-échantillonner récursivement, en abusant de l'interpolation linéaire matérielle entre les textures jusqu'à atteindre une résolution raisonnablement petite. Cela conduit à des fragments qui ont un niveau de gris en fonction du nombre de pixels blancs dans leur région correspondante. Est-ce même assez précis?

  • Utilisez des mipmaps et lisez simplement le pixel au niveau 1x1. Encore une fois, la question de la précision et s'il est même possible d'utiliser des textures sans puissance de deux.

Le problème avec ces approches est que le pipeline est bloqué, ce qui entraîne des problèmes de performances majeurs. Par conséquent, je recherche un moyen plus performant pour atteindre mon objectif.

Utilisation de l'extension EXT_OCCLUSION_QUERY_BOOLEAN

Apple a introduit EXT_OCCLUSION_QUERY_BOOLEAN dans iOS 5.0 pour 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."

La première phrase fait allusion à un comportement qui est exactement ce que je recherche: obtenir le nombre de pixels qui ont réussi le test de profondeur de manière asynchrone sans beaucoup de perte de performances. Cependant, le reste du document décrit uniquement comment obtenir des résultats booléens.

Est-il possible d'exploiter cette extension pour obtenir le nombre de pixels? Le matériel le prend-il en charge afin qu'il puisse y avoir une API cachée pour accéder au nombre de pixels?

D'autres extensions qui pourraient être exploitables seraient le débogage de fonctionnalités comme le nombre de fois où le shader de fragment a été invoqué (PSInvocations dans DirectX - je ne sais pas si quelque chose de similaire est disponible dans OpenGL ES). Cependant, cela entraînerait également un blocage du pipeline.

Etan
la source
Quel est l'effet final que vous essayez d'atteindre?
Tetrad
J'ai besoin du nombre de pixels non pas pour un effet de rendu, mais pour le calcul. Je veux l'utiliser pour calculer le poids des particules dans un filtre à particules.
Etan
Apple prend-il en charge AMD_performance_monitor? Si oui, vous pourrez peut-être trouver le compteur qui affiche les pixels passés. Notez que cela est très, très spécifique à l'appareil même si vous le faites fonctionner.
Jari Komppa
Le problème avec AMD_performance_monitor serait qu'il n'est pas asynchrone, donc la perte de performances serait également là car je dois attendre entre les trames pour savoir que les appels de la trame suivante n'auront pas déjà d'effet sur les compteurs de performances.
Etan
De plus, AMD_performance_monitor n'est pas disponible.
Etan

Réponses:

1

Est-il possible d'exploiter cette extension pour obtenir le nombre de pixels? Le matériel le prend-il en charge afin qu'il puisse y avoir une API cachée pour accéder au nombre de pixels?

Non et non. Eh bien, je supposais que si vous dessinez une série de triangles d'un pixel dans l'espace fenêtre, vous pourriez compter le nombre de valeurs booléennes que vous obtenez. Mais cela nécessiterait une requête distincte pour chaque pixel. Probablement pas la chose la plus rapide au monde.

S'il y a une "API cachée", vous n'y aurez pas accès (car elle est cachée), donc cela n'a pas d'importance. De plus, la nature de l'extension suggère déjà qu'il n'y en a pas. Après tout, si le matériel avait le nombre réel de fragments, pourquoi ne pas simplement l'exposer directement, comme le fait OpenGL de bureau? Si le matériel le supportait, ils auraient pu prendre ARB_occlusion_query et l'utiliser.

Mais ils ne l'ont pas fait. Ce qui suggère fortement qu'ils ne pouvaient pas.

Nicol Bolas
la source
Merci d'avoir répondu! L'approche avec des triangles d'un pixel peut être améliorée en rendant simplement des points ou de petites lignes, et elle pourrait même être améliorée par une mise à l'échelle logarithmique où une ligne qui renvoie "vrai" est simplement divisée au milieu, puis les deux parties vérifiées à nouveau. Je ne suis pas encore sûr des performances car les modèles n'auront pas plus de 100-200 sommets. Le raisonnement pour l'inexistence de "l'API cachée" est également valable. Existe-t-il d'autres moyens de récupérer les données du GPU vers le CPU de manière asynchrone sans blocage de pipeline (également de manière hacky s'il vous plaît)?
Etan
0

Les résultats sont retournés dans un GLuint, (peut également être GLint pour un appel différent) malheureusement, le résultat est toujours un 0 ou un 1, peut-être qu'ils le changeront pour enregistrer des frags à l'avenir.

il semble également qu'aucune personne sur Internet n'ait posté sur ces nouvelles extensions ... alors ici, elles sont correctement configurées ... ce qui n'est pas documenté nulle part pour autant que je sache ... vous pouvez imaginer comment elles irait dans votre code à partir de ce petit code sudo ici:

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
la source
Ce GLintn'est pas parce que le type dit que c'est un nombre entier du nombre de fragments qui passent. La spécification QUERY_RESULT_EXTindique clairement que l' état est une valeur booléenne; vous l'interrogez simplement comme un entier. C'est GL_FALSEs'il a échoué et non GL_FALSEs'il a réussi.
Nicol Bolas
Je venais d'implémenter le code et j'ai trouvé que c'était juste un vrai ou un faux et j'ai changé ma réponse avant de voir votre commentaire ... car c'est une gluint, peut-être qu'ils ajouteront des états à l'avenir, espérons-le.
honjj
par ailleurs, il semble y avoir un bogue dans GKKit, où si vous utilisez self.effect2 = [[GLKBaseEffect alloc] init]; type de code GLKit pour rendre un objet, plutôt qu'un pipeline GLES2.0 normal, les requêtes ne vous donneront pas la bonne réponse ... (jamais masquée) bien que j'aie testé un objet pipeline masquant un objet GLKBaseEffect, donc il il pourrait y avoir un bug mélangeant simplement les deux, je n'ai pas encore testé plus loin ...
honjj
Les extensions sont expliquées avec des exemples dans les vidéos WWDC qui peuvent être trouvées sur le site Apples avec un compte de développeur actif.
Etan