.the rush//Technique d’optimisation GPU
Un jeu, comme tout programme, traite des données. Ces données passent par un ensemble de modules. Ce cheminement s’appelle un pipeline. Le pipeline dans un jeu est assez long et traverse différentes couches logicielles et hardware. En l’occurrence, des datas sont triées par le CPU puis envoyées vers le driver. Le driver route ces datas vers le GPU. Le GPU prends ces datas plus des datas locales pour faire de l’affichage. Une mauvaise synchro, un traitement trop long et c’est toute l’application qui rame.
Ca, c’est pour l’intro. Aujourd’hui, on va regarder en détail une optimisation qui arrive en bout de pipeline. Les optims CPU et drivers, on verra ca plus tard. Celle-ci est suffisament simple et performante pour qu’on la regarde maintenant.
Sur un GPU, plusieurs choses peuvent ralentir le rendu. Principalement:
- Le fillrate : l’écriture d’un pixel dans le back buffer.
- Le bandwidth: la lecture dans les textures, la géométrie.
- L’éxecution de code Pixel Shader/Vertex Shader/Géométrie shader.
- Le vidage de pipeline suite à un retournement (changement de blending par exemple)
On va s’intérresser au fillrate et à l’éxécution de shaders. On a des problèmes de fillrate quand on écrit trop dans le backbuffer (pour simplifier). Ca arrive quand on a de l’overdraw (rendre par dessus de quelque chose déjà rendu) ou quand on rend dans un backbuffer trop grand (1920×1200 avec une geforce4). Une partie de ce problème est résolu en amont en triant la géométrie a rendre et en dessinand du plus proche au plus loin. Néanmoins, ca suffit pas toujours. Quand on a de la géométrie qui nécessite un blending (particules, rendu multipass, etc). Pour diminuer ce problème, il y a une technique.
L’adaptative backbuffer size (je ne sais pas s’il y a un autre terme). On fait le rendu dans une surface plus petite qu’on étire au moment de l’affichage.
Le principe est tout bête et nous permet d’économiser du Fillrate et aussi du GPU (moins de pixels à calculer).
Comment choisir la taille du rendu?
Déjà il faut se fixer des limites. Je ne descend pas sous les 50% de la surface d’origine. Après c’est a négocier avec les graphistes. Mais pour un jeu de course avec la vitesse et la rémanence ca ne devrait pas se voir. Le calcul se passe ainsi:
- Calcul du temps moyen des N derniers frames.
- Si le temps est > a 16.6ms (60Hz), je multiplie la surface de rendu par 0.95f.
- Si le temps est < 16.6, je multiplie par (1.f/0.95f)
- je clamp entre 0.5f et 1.0f
Si l’application est vraiment dépendante du Fillrate/shader, utiliser un PID Controller pour ne pas avoir d’effet yo-yo.
Ce calcul de facteur dégradant peut aussi être util pour limiter des distances de LOD.
Quid de la qualité?

Dans l’ordre Qualité a 1, 0.75, 0.5 et 0.25. Height constant, je ne modifie que le Width entre 1 et 0.75, La différence visuelle est peu visible sous 0.5, ca devient dégeu.
Quid des performances?
Malheureusement, pour l’instant, je ne peux pas bencher le gain. Je suis encore limité par le CPU et le driver.
Comment on fait ca avec DirectX9 (et openGL)?
En DirectX9, avant le rendu on fait 1 setviewport avec la taille qu’on veut. Lors de la presentation du backbuffer (méthode Present du device DX9), on donne le rectangle source.
Cette technique est utilisée dans WipeoutHD. Ne surtout pas oublier que cette technique est utile *seulement* quand on n’est pas limité par le CPU/Driver/…

1 juillet 2009 à 15:12 Citer
En opengl c’est un poil moins évident vu que le buffer final de l’écran dépend de l’os. Donc il faut un appel à glViewport et ensuite faire un vers texture vers un quad fullscreen en utilisant un lissage pour que ça soit pas trop moche.
Perso j’appellerais ça plutôt du scaling.
1 juillet 2009 à 15:40 Citer
Hmm j’aime pas trop cette technique mais apparemment l’utilisateur ne voit rien, étant trop concentré sur le jeux, donc pourquoi pas! (quelqu’un a déjà vu la différence en jouant à ce jeu?)
Sinon, dans WipeOutHD, le seuil du facteur de résolution était de 0.66 (2/3). (source http://www.gamersglobal.com/news/1336) D’ailleurs, comme eux, tu devrais aussi mettre à l’échelle la hauteur de ton buffer de rendu. tu gagnerais encore plus en vitesse d’affichage et ainsi tu pourrais multiplié par un plus grand facteur (par exemple 0.97). Ca ne va pas être évident à régler.
Est-ce que tu as aussi essayer de réduire la taille de tes buffers utilisés pour le bloom en utilisant le même facteur?
1 juillet 2009 à 17:30 Citer
@SlAyEr
Je n’ai pas encore modifié tout le pipeline (bloom, dof,…).
A priori sur WO HD, il calcule le facteur en amont. Suivant le nombre d’objets à l’écran, le nombres de vaisseaux visible, la quantité de triangles avec du blend, la quantité de particules, nombre de lights dynamiques en deferred, etc, ils calcule le facteur. Facteur soit variable comme moi, soit une de leurs résolutions.
C’est pas une solution miracle. C’est juste une optimisation qui peut-etre utile dans certains cas. Pour l’instant, dans le jeu, ca ne l’est pas (encore). Mais cette expérience m’a tout de même permis de voir la faisabilité et surtout la baisse de qualité quand on passe en 0.75 -> équivalent 1440×1080.
1 juillet 2009 à 18:14 Citer
Les jeux console font ça depuis des temps immémoriaux. Ceci dit dans certains cas, le scaler est inclu au DAC. Aussi ça peut être différent d’un filtre bilinéaire cradoc.
Sur PC il faut rendre dans une texture avant de pouvoir utiliser autre chose qu’un filtre bilineaire. Aussi l’avantage c’est que tu peux utiliser une résolution fixe pour certains éléments (affichage UI notamment) ce qui n’est pas possible si tu attends le Present().
Plein de fun pour toi.
1 juillet 2009 à 19:41 Citer
c’est surement une question de noob mais je pige pas en quoi c’est une optimisation ?
ou c’est parceque ça concerne que les consoles peut être ?
parceque si on parle d’un jeu pc classique on peut définir soi même sa résolution et le réglage par défaut est souvent assez bas. ensuite si je monte la rés je sais que les perfs vont diminuer et je décide du meilleur rapport res/perfs ou je décide par exemple de jouer dans une résolution native de mon moniteur ou une résolution multiple de celui ci par exemple.
Mais si quand je décide de jouer en 1680*1050 et que le jeu est rendu en 1024*768 puis étiré (par quel moyen ? cela coute aussi de s perfs qqpart je suppose ?) je n’obtiendrais pas la qualité graphique voulue, finalement c’est de la “triche” de la part du jeu non ?
questions vraiment posées naivement de ma part et sans malice
1 juillet 2009 à 19:52 Citer
“c’est de la “triche” de la part du jeu non ? ”
Haha. Wipeout HD est vendu comme un jeu en 1080p 60Hz. et c’est le cas. Mais il n’est pas toujours en 1920×1080.
Dans le rendu graphique, tu peux avoir tellement de delta de temps nécessaire entre le calcul de 2images, soit tu laisses le lag, soit tu modifies la résolution temporairement.
Je trouve que garder le 60Hz est plus important.
1 juillet 2009 à 19:57 Citer
@LeGreg
Ca existe encore le DAC quand tu utilises une sortie HDMI?
C’est sur Amiga la 1ere fois que j’ai entendu parlé de ca. Style jeu en 32 couleurs et affichage des scores en 256 et resolution plus fine. 20ans après, c’est toujours la même merde.
1 juillet 2009 à 23:57 Citer
Sur consoles et PC, la conversion analogique est toujours présente. Ceci dit je parle de DAC mais c’est bien entendu la partie logique responsable de lire le frame buffer d’appliquer quelques transformations (overlay, curseur, look up table pour les couleurs, redimensionnement si besoin etc.) et de convertir le tout en signaux électriques. Je n’ai pas d’autre noms pour cette partie désolé.
4 décembre 2009 à 13:51 Citer
C’est une technique intéressante mais ne faut il pas pré-allouer les render targets ? Surtout si on fait du deferred rendering et/ou plusieurs passes de post-filtering, ça fait beaucoup de textures à créer. En même temps, préallouer autant de textures à différente taille ça coute aussi!
4 décembre 2009 à 16:26 Citer
Tu alloues pour la taille la plus grande. Tu modifies les UV (ou l’UV transform) pour prendre seulement la portion qui t’interresse.