c'est gentil. Du coup ca m'a mis de bonne humeur et je continue
La seule chose qui n'est pas parallelisable c'est l'envoi de commandes vers opengl ou directx (bien que directx 11 sera multithreadé), et il serait dommage que pendant qu'on envoie des commandes opengl/directx il ne se passe rien. Voila donc, pour un quad-core, comment je verrais les choses :
- tu alloues 3 cores (en regle generale, n-1) core aux taches
- tu reserves un core au rendu
ensuite :
- tu effectues tes taches aussi vite que possible avec tes 3 cores
- la derniere tache consiste a copier ce que tu vas rendre, faire une copie de ton quad tree par exemple, pour pouvoir d'un coté le modifier et de l'autre lire la version
- sur le premier core, tu lances le rendu de ce quad tree en envoyant les commandes
- sur les 3 autres cores, tu commences la prochaine frame
cela implique de separer la logique du jeu de la logique du rendu; par exemple, tu vas devoir stocker la position et l'animation actuelle du personnage de maniere a pouvoir la lire avec le rendu mais a modifier pour la frame suivante.
Si jamais ton coeur adoré a fini le rendu, et bien tu peux lui dire d'aider a effectuer des taches pour le compte des autres cores (les "voler"
pour leur rendre service, et des qu'ils ont fini hop tu te lances sur le rendu de la frame qui vient de se finir.
Si les autres cores vont trop vite pour le rendu, cela signifie que ton rendu va "lagger", dans ce cas tu risques d'accumuler des frames de retard. Pour cela, bien evidemment, tu ne stockes pas une liste des frames a rendre, tu n'en stocke qu'une, et si le premier thread a du retard il va sauter directement a la frame la plus recente.
Enfin, pour que tout ce beau monde fonctionne, tu as besoin d'un scheduler, qui va diviser les taches a effectuer et qui va egalement les ordonnancer sur plusieurs cores.
mettons que tu divises ton IA sur 4 cores, et que tu aies 40 personnages; la logique veut que chaque core recoive 10 personnages. mais que se passe t'il si ts 10 premieres IA qui vont sur le coeur 1 jouent aux echecs, pendant que les 30 autres jouent a la bataille et ne monopolisent pas beaucoup de neurones ? ben le core 1 va ramer a mort sur ces 10 et les autres cores vont se tourner les pouces. dans ce cas, le plus simple est en fait de diviser les taches en k*n ou n est le nombre de cores et k un nombre de taches par core, que j'ai mis arbitrairement a 16 ou 32 et qui donnent de bons resultats.
Dans ce cas, si le core 1 rame sur une tache, les cores 2 3 et 4 peuvent:
- diviser une de ses taches dans sa queue et lui en voler la moitié
- lui voler une tache complete
et aider a la progression du core 1. Si tu n'as qu'une tache sur le core 1 et qu'il est deja dessus, tu ne peux pas l'aider.
Enfin, comme je me sens utile et de tres bonne humeu, je vous recommande la bibliotheque intel "thread building blocks" et la doc qui va avec.
J'ai commencé un moteur de jeu dont l'ambition est que la boucle principale envoie une tache dans la liste, cette tache a sa completion declenchera d'autres taches, etc etc, et que l'integralité du jeu soit donc des taches.
J'ai donc pour cela commencé a faire une petite lib ressemblant a intel TBB, et je suis en train de travailler sur les taches pour pouvoir les enchainer et ainsi faire l'integralité d'un update de frame sur les taches, utilsiant au maximum les CPU
j'ai aussi lancé mon langage de script qui permettra (un jour) d'effectuer les calculs en parallele, decorrelles de la logique. Car comme montré plus haut, le principal probleme du multithread est que les gens pensent a un fil continu et ne savent pas comment paralleliser. par exemple, lorsqu'on shoote avec une arme a feu, on a :
- le son
- le systeme de particule (effet graphique)
- la balle et le calcul de ce qu'elle touche
mais dans du code en C++ on se voit mal effectuer ces trois choses en parallele car on ne peut pas lancer un thread expres pour faire le bruit d'une balle, et un autre pour faire l'effet graphique. Si ces choses arrivent sur un evenement, c'est tres dur de paralleliser cela.
Donc mon plan est de creer un langage qui permet de dire "effectue ces 3 choses la", va creer 3 taches et va les mettre dans le scheduler. Tout cela sans que le programmeur aient a tripatouiller
WARNING: l'enorme probleme est que si tout est multithread, alors chaque unité peut mourir pendant qu'un autre core lui demande combien elle a de PV, ou autres problemes de synchro. il est important de proteger correctement ces variables.
une idée pour cela est dans le moteur de valve je crois, qui consiste a avoir plein de copie d'objets et ce qu'isl appellent un "pipeline" qui permet de reconstruire un objet a partir des modifications appirtées par chaque thread.
le multithread restecependant quelque chose de tres dur a maitriser et donne d'innombrables bugs tres difficiles a reproduire, etant donné que le scheduler a la main sur tout et qu'on a peu de controle sur lui.
0 |
0 |