Auteur Sujet: Compute shaders, quelques questions  (Lu 6867 fois)

0 Membres et 1 Invité sur ce sujet

Bonsoir à tous,

Je viens de commencer à m'intéresser aux computes shaders, et comme j'ai jamais trop fait de programmation parallèle sur GPU, je sais pas trop comment faire pour optimiser le code/exécution du code. D'où pleins de questions :)

(J'utilise DirectCompute, donc j'utiliserai sa dénomination, je ne connais pas celles de OpenGL/OpenCL/CUDA  :-[ ).

Tout d'abord, comment choisir le nombre de thread groups que l'ont va utiliser (paramètres de Dispatch() quoi)? Est-ce que par exemple si j'ai 80 shader cores sur ma AMD HD5470 (oui, c'est du très bas de gamme :-° ), je dois distribuer sur 80 groupes?

Dans le même genre, comment choisir le nombre de threads par groupe? A ce que je crois savoir (mais je sais pas trop en fait) lorsque un thread est bloqué par l'attente de l'arrivée de données pas dans le cache local, le gpu passe à un autre thread (j'ai vu le terme wavefront souvent, mais je ne sais plus ce que c'est). Donc il faudrait en mettre un certain nombre, mais combien?

Mon but final serait de faire un compute shader pour gérer la mise à jour de particules, puis qu'il fasse un tri selon la profondeur des particules (car ces particules sont ensuite étendues en des cubes, et je veux minimiser le pixel overdraw). Quelqu'un a déjà fait dans le truc et aurait des conseils spécifiques?

Merci pour votre aide :)

Hum, je suis pas spécialiste du hardware alors je vais p'têt dire des conneries quant au nombre de thread optimum mais a priori, si tu es certain d'avoir 80 shader cores, c'est donc normalement le nombre de threads que tu peux utiliser.

De toute manière, dans un CS DX11 le nombre de threads par groupe est limité à 1024.
Tu peux les répartir comme tu veux selon les dimensions pour traiter ton problème, genre [16,16,4] ou [32, 32, 1] ou même [1024,1,1].
Dans ton cas [20,2,2], [80,1,1], etc.

Par contre, le nombre de groupe est libre ('fin, limité quand même à 65536) et c'est normal car ça correspond juste au nombre de fois où tu vas lancer ton groupe de threads pour voracement attaquer un bout de ton problème (en l'occurrence, ton buffer de particules)... Vois ça comme une découpage en tiles d'un buffer: la taille de tes tiles c'est les threads, le nombre de tiles (i.e. groupes) c'est la taille de ton buffer / nombre de threads...


L'intérêt principal d'un CS c'est surtout de faire collaborer les threads entre elles avec du groupsharedmemory et ce genre de trucs. Si tu veux simplement faire évoluer des particules sans qu'elles aient d'interaction entre elles alors il vaut mieux que tu fasses du pixel shader.

Ton tri, par contre, effectivement tu peux le faire en CS avec une routine maline genre tes threads lisent le Z de la particule dans un group shared memory, se sync entre elles, la moitié d'entre elles vont procéder à des inversions conditionnelles des Z 2 à 2, ensuite sync, ré-inversent les nouveaux groupes, etc.
Mais comme chuis nul en tri je peux pas trop t'aider, renseigne-toi sur le bitonic sort pour te faire une idée (et si t'as un code qui le fait, je suis preneur ! ^^)

Hello,

Pour les updates des particules je trouve aussi que c'est plus simple à réaliser avec des pixels shaders.

Pour le tri j'avais commencé à regarder le bitonic sort dont j'ai compris le principe, mais après je suis resté bloquer sur l'implémentation en compute shader (première fois que j'essayait de m'en servir).
Je vais essayer de m'y remettre au mois d'aout vu que j'aurais du temps.

Si tu trouve des trucs interressants la dessus ça m'interresse grandement.

Ok merci pour les précisions :)

Pour les particules, j'aimerais qu'elles interagissent, juste pour voir :) Et puis c'est aussi pour des raisons pédagogiques.

J'ai vu qu'il y a un exemple de bitonic sort dans le directx sdk de juin 2010, je vais le regarder et le modifier pour qu'il supporte des entrées dont la taille n'est pas une puissance de deux si possible (soit à la bourrin en ajoutant la valeur max jusqu'à atteindre une puissance de deux, soit en faisant un truc mieux).

Je suis curieux de connaître l’équivalent OpenGL de « Compute Shader ». Probablement le GS ?

@skypers : Compute Shader :) https://www.opengl.org/wiki/Compute_Shader
GS c'est le Geometry Shader

Spécifiquement par rapport a D3D11, cette présentation "DirectCompute Performance" de AMD recommande pas mal de choses pour maximiser l'utilisation du GPU. Je dois avouer que ce n'est vraiment pas evident de trouver une seule info a un endroit sur ce sujet. Parfois tu peux trouver des astuces optims, comme par exemple récemment une série de tweets de Nick Thibieroz GCN Performances Tips

Tout d'abord, comment choisir le nombre de thread groups que l'ont va utiliser (paramètres de Dispatch() quoi)? Est-ce que par exemple si j'ai 80 shader cores sur ma AMD HD5470 (oui, c'est du très bas de gamme :-° ), je dois distribuer sur 80 groupes?

A priori, un shader core peut prendre en charge plusieurs thread group, mais pour l'instant, un thread group ne peut a se repartir entre plusieurs shader core (ca pourrait changer a l'avenir).

Dans le même genre, comment choisir le nombre de threads par groupe? A ce que je crois savoir (mais je sais pas trop en fait) lorsque un thread est bloqué par l'attente de l'arrivée de données pas dans le cache local, le gpu passe à un autre thread (j'ai vu le terme wavefront souvent, mais je ne sais plus ce que c'est). Donc il faudrait en mettre un certain nombre, mais combien?

Cela dépend beaucoup du hardware (et pareil, les nouvelles générations type GCN de AMD peuvent aussi changer la donne), mais jusqu’à présent, la règle était d'utiliser un multiple de 32 threads pour NVidia et 64 threads pour AMD. J'ai plus souvent utilise 256, voire 512. A chaque fois, idéalement, il faudrait que tu testes cela sur different HW, quitte même a avoir different config pour different HW, et supreme ideal, d'avoir un systeme qui mesure les options en bootstrap avant de selectionner la version optimale pour l'HW en cours d'utilisation.

Mon but final serait de faire un compute shader pour gérer la mise à jour de particules, puis qu'il fasse un tri selon la profondeur des particules (car ces particules sont ensuite étendues en des cubes, et je veux minimiser le pixel overdraw). Quelqu'un a déjà fait dans le truc et aurait des conseils spécifiques?

J'ai fait juste un petit moteur de particules en D3D11, avec update et tri en compute shaders, et l'affichage des particules en utilisant le GS juste pour afficher des quads a partir des positions des particules. Pour l'update, il est possible qu'une version PS soit plus efficace, mais je trouve ca tellement pratique de pouvoir utiliser une struct sans avoir a jongler avec plusieurs MRT que je n'ai pas passe du temps a optimiser cette partie. Pour le sorting, j'ai utilise un custom algo de bitonic sort, a posteriori assez similaire a celui du DirectX SDK, ptet un peu plus performant tout en évitant la transposition, mais peut etre qu'en utilisant la transposition en plus, j'aurais pu gagner un peu plus (de mémoire des résultats, tri de 1 millions de particules autour 7-8ms sur une GTX 560). Meme en utilisant une struct pour la particule, il faut essayer de packer les fields et a occuper un minimum de place (idéalement inférieur a 64 bytes de ce que j'avais pu lire qq part? ), ce qui oblige souvent a utiliser des halfs et a packer les infos dans des ints.

Dans tous les cas, il faut vraiment mesurer les perfs a chaque étapes de l'algo et voir ou tu perds du temps (en utilisant des query timestamp GPU pour avoir des chiffres un peu plus precis que juste du time per frame). Utiliser des outils comme NVidia NSight pour diagnostiquer comment les threads se dispatchent aide beaucoup.

@skypers : Compute Shader :) https://www.opengl.org/wiki/Compute_Shader
GS c'est le Geometry Shader
Ah putain ouais c’est carrément nouveau ! Je connais VS / TCS / TES / GS / FS, mais CS ?! Je vais lire ça :)

Han mais t'as codé un bitonic et tu l'as même pas partagé alors que t'avais promis dans je sais plus quelle autre thread où on en parlait ? T'es une sorte de grosse ordure en fait ! ;D
Comme ça fait la 2ème fois qu'on parle du bitonic du SDK de Direct X, je vais y jeter un oeil...



Sinon j'ai une mauvaise nouvelle vis-à-vis des CS : j'ai écrit un code que le compilo a pas su générer correctement.
Pourtant c'est pas un code méga-complexe, il fait pas intervenir de synchros entre threads, pas de groupshared memory, rien. Chaque tread fait son p'tit bouzin, indépendamment des autres, elle s'occupe de son p'tit business et écrit le résultat dans sa target, pas de scatter rien. En gros, c'est quasiment l'équivalent d'un PS...

D'ailleurs pour preuve, j'ai passé ce même code, aux quelques modifs près (utiliser SV_POSITION au lieu de SV_GROUPTHREADID), en PS et ça donne le bon résultat.

J'en conclus que le compilateur de CS peut générer du code daubé dans certaines conditions, et ça me rassure pas des masses !

Han mais t'as codé un bitonic et tu l'as même pas partagé alors que t'avais promis dans je sais plus quelle autre thread où on en parlait ? T'es une sorte de grosse ordure en fait ! ;D
Rhaf, désolé, c vrai que j'ai pas pris le temps, y'a tellement de truc a explorer et de choses a dire sur les choses que l'on a exploré, qu'a un certain moment, on partage moins que l'on explore, et ça s’amoncèle malheureusement...  :-[

Sinon j'ai une mauvaise nouvelle vis-à-vis des CS : j'ai écrit un code que le compilo a pas su générer correctement.
Pourtant c'est pas un code méga-complexe, il fait pas intervenir de synchros entre threads, pas de groupshared memory, rien. Chaque tread fait son p'tit bouzin, indépendamment des autres, elle s'occupe de son p'tit business et écrit le résultat dans sa target, pas de scatter rien. En gros, c'est quasiment l'équivalent d'un PS...
Bizarre pour quelques chose d'aussi direct... avec quelle version de fxc? Si tu prends le compilo du SDK de Windows 8, ils ont corriges quelques bugs du style dans les CS (ca doit etre d3dcompiler_46.dll). Celui du DirectX June 2010 (_44) commence a dater...

Oui c'est effectivement le compilo du SDK de juin 2010...

Heu, question de noob mais comment on update ce putain de SDK ? Ou tout du moins le compilateur de shaders ?

Heu, question de noob mais comment on update ce putain de SDK ? Ou tout du moins le compilateur de shaders ?

Il te faut installer le Windows 8 SDK et tu trouveras ensuite les fxc.exe et autre d3dcompiler_46.dll dans les sous répertoires. A la difference du DirectX June 2010, tu peux/dois redistribuer d3dcompiler_46.dll avec ton appli (ou la partie qui compile si c du offline).

Okay merci. Ca me fait un peu peur d'installer un truc qui a un quelconque rapport avec Windows 8 à vrai dire... (je suis resté sur l'impression que c'est une méga grosse daube ;D)

@xoofx:
Merci bien, je vais potasser tout ça :)

Je partagerai quand j'aurai fait tout ça (update+culling+sort) pour voir si vous trouvez des trucs à dire sur mon code. Dans deux semaines ou un truc du genre.

@patapom:
J'utilise le SDK Win8 pour directx avec VS2012, et ça marche super bien :) Par contre il y a plus de pix, c'est dans visual studio maintenant (mais mieux).

Mon passage préféré de la discussion :

Han mais t'as codé un bitonic et tu l'as même pas partagé alors que t'avais promis dans je sais plus quelle autre thread où on en parlait ? T'es une sorte de grosse ordure en fait ! ;D

:-D