void ajoute( std::vector<int>& entree )
{
for(unsigned i= 0; i < entree.size(); i++)
entree[i]= entree[i] + 10;
}
à partir de quelle taille de tableau un compute shader
peut s'exécuter efficacement ?std430
... ce sera plus simple pour écrire
l'applicationrappel : utilisez les décorationsvoid ajoute( const int v, const std::vector<int>& entree, std::vector<int>& sortie )
{
sortie.resize(entree.size());
for(unsigned i= 0; i < entree.size(); i++)
sortie[i]= entree[i] + v;
}
readonly, writeonly
pour déclarer les buffers en lecture seule, ou en écriture seule...v
(par exemple) dans un tableau résultat. rappel : operations atomiques... cf la doc de glsl sur les buffers, et celle sur les compute shadersvoid filtre( const int v, const std::vector<int>& entree,
std::vector<int>& sortie
)
{
sortie.clear();
for(unsigned i= 0; i < entree.size(); i++)
if(entree[i] > v)
sortie.push_back(entree[i]);
}
atomicAdd(n, 1)
simultanement sur la variable n... et ca va être assez lent. shared
),
mais la mémoire partagée n'est visible / partagée que par les
threads d'un même groupe, pas par tous les groupes... par contre, si
on pouvait ne faire qu'un seul atomicAdd(n, ...) par groupe, on
accelererait pas mal le shader...glMultiDrawIndirect()
/ glMultiDrawIndirectCountARB()
pour tout dessiner d'un
coup. relisez la docAMD_DEBUG="cs noir nonir"
pour les radeons sous
linux avec mesa, ou INTEL_DEBUG="cs"
pour les
igpu intels sous mesa, cf la doc de mesa std::vector<float>
zbuffer(width*height);
glReadBuffer(GL_BACK);
glReadPixels(0, 0, width, height,
GL_DEPTH_COMPONENT, GL_FLOAT, zbuffer.data());
exercice 4 : c'est un peu lent non ?
tester tous les pixels de l'englobant image de chaque région est
long. comment faire plus rapide, et en temps constant ?
indications : l'idée est d'utiliser un zbuffer hiérarchique
et de faire le test dans la "bonne" résolution du zbuffer en
fonction des dimensions de l'englobant image. par exemple, on peut
choisir la resolution du zbuffer pour ne tester que 4 pixels... ou
16.
exemple : pour une région dont l'englobant image est
toute l'image, on peut choisir le zbuffer de resolution 1x1, 2x2
ou 4x4 et ne faire que 1, 4, ou 16 tests.
pour des englobants plus petits, qui n'occuppent pas toute l'image, il est aussi possible de choisir une resolution du zbuffer qui permette de ne tester que quelques pixels.
choisir cette resolution est un compromis, existe-t-il des cas ou
il serait souhaitable de faire un test plus précis ?
quel est le probleme avec les englobants qui occuppent toute
l'image ?
quel est le problème avec les englobants qui sont partiellement
derrière la camera, le plan near ?
pour chaque pixel d'un mipmap du zbuffer, on peut construire
l'intervalle de profondeur des pixels du zbuffer pleine
resolution. est-il nécessaire de conserver les 2 bornes de
l'intervalle ?
construisez le zbuffer hiérarchique. et vérifiez que le test
d'occultation hiérarchique fonctionne correctement.
exercice 5 : maintenant que le test d'occultation est en
place, il ne reste plus qu'à l'utiliser pour dessiner les régions
de la scène.
Mais pour que ce soit interressant, il faut un zbuffer pour
tester la visibilite des régions avant de les dessiner... L'idée
présentée dans le tp précédent est de dessiner les régions
considérées visibles lors de l'image précédente pour construire /
initialiser le zbuffer, puis de tester les régions pour lesquelles
on a pas encore établi la visibilité. et bien sur de conserver
cette information pour initialiser l'image suivante...
exercice 6 : c'est quand meme lent de relire le zbuffer
dans l'application... comment faire le test avec un compute shader
?
l'idée est toujours la meme, le compute shader fera le test de
visibilite et remplira un tableau de parametres pour
MultiDrawIndirect().
indications : commencez par construire le zbuffer
hiérarchique avec un compute shader...
utilisez imageLoad() / imageStore() pour lire et écrire les
zbuffers. relisez la
doc sur les storage images / textures.
les opérations atomiques min, max, addition, etc existent aussi
sur les images (en plus des buffers) elles sont documentées dans
la section glsl de la doc opengl, ou sur le wiki
opengl.org
comment paralléliser ce calcul ? combien de dispatch()
faudra-t-il faire ? 1 par resolution ?
peut-on grouper le calcul de plusieurs niveaux du zbuffer
hierarchique dans un seul compute shader ? comment ? pourquoi
vouloir faire ca ?
commencez par la version directe, 1 dispatch() + synchronisation
par resolution du zbuffer.
pour les curieux : oui, on peut gagner un peu de temps sur
le test d'occultation en utilisant textureGather() au lieu de
texture(), qui renvoie 4 valeurs de 4 pixels différents...
pour les tres curieux : construire un mipmap de maniere
très efficace est décrit sur gpuopen. les
commentaires sur la technique sont dispo
(video)