36 votes

Quand les VBO sont-elles plus rapides que les "simples" primitives OpenGL (glBegin()) ?

Après avoir entendu parler pendant de nombreuses années des Vertex Buffer Objects (VBO), j'ai finalement décidé de les expérimenter (mon travail n'est normalement pas critique en termes de performances, évidemment...).

Je vais décrire mon expérience ci-dessous, mais pour faire court, je constate que les performances sont indiscernables entre le mode direct "simple" (glBegin()/glEnd()), les modes de rendu vertex array (côté CPU) et VBO (côté GPU). J'essaie de comprendre pourquoi et dans quelles conditions je peux m'attendre à voir les VBO surpasser de manière significative leurs ancêtres primitifs (jeu de mots).

Détails de l'expérience

Pour l'expérience, j'ai généré un nuage gaussien 3D (statique) d'un grand nombre de points. Chaque point est associé à des informations de vertex et de couleur. Puis j'ai fait tourner la caméra autour du nuage dans des images successives dans une sorte de comportement "orbital". Encore une fois, les points sont statiques, seul l'oeil bouge (via gluLookAt()). Les données sont générées une fois avant tout rendu et stockées dans deux tableaux pour être utilisées dans la boucle de rendu.

Pour le rendu direct, l'ensemble des données est rendu dans un seul bloc glBegin()/glEnd() avec une boucle contenant un seul appel à glColor3fv() et glVertex3fv().

Pour le rendu des tableaux de sommets et des VBO, l'ensemble des données est rendu avec un seul appel glDrawArrays().

Ensuite, je l'exécute simplement pendant une minute environ dans une boucle serrée et je mesure le nombre moyen d'images par seconde avec le chronomètre haute performance.

Résultats des performances ###

Comme mentionné ci-dessus, les performances étaient indiscernables sur mon ordinateur de bureau (XP x64, 8 Go de RAM, 512 Mo de Quadro 1700) et sur mon ordinateur portable (XP32, 4 Go de RAM, 256 Mo de Quadro NVS 110). Il a cependant évolué comme prévu avec le nombre de points. Évidemment, j'ai également désactivé vsync.

Résultats spécifiques de l'ordinateur portable (rendu avec GL_POINTS) :

glBegin()/glEnd() :

  • 1K pts --> 603 FPS
  • 10K pts --> 401 FPS
  • 100K pts --> 97 FPS
  • 1M pts --> 14 FPS

Vertex Arrays (côté CPU) :

  • 1K pts --> 603 FPS
  • 10K pts --> 402 FPS
  • 100K pts --> 97 FPS
  • 1M pts --> 14 FPS

Vertex Buffer Objects (côté GPU) :

  • 1K pts --> 604 FPS
  • 10K pts --> 399 FPS
  • 100K pts --> 95 FPS
  • 1M pts --> 14 FPS

J'ai rendu les mêmes données avec GL_TRIANGLE_STRIP et j'ai obtenu des résultats similaires (bien que plus lents comme prévu en raison de la rastérisation supplémentaire). Je peux aussi poster ces chiffres si quelqu'un les veut. .

Question(s)

  • Qu'est-ce qui se passe ?
  • Que dois-je faire pour réaliser le gain de performance promis par les VBO ?
  • Qu'est-ce que je rate ?

27voto

starmole Points 611

L'optimisation du rendu 3D comporte de nombreux facteurs. Il y a généralement 4 goulots d'étranglement :

  • CPU (création de sommets, appels APU, tout le reste)
  • Bus (transfert CPU<->GPU)
  • Vertex (vertex shader sur l'exécution du pipeline de fonctions fixes)
  • Pixel (remplissage, exécution du fragment shader et rops)

Votre test donne des résultats faussés parce que vous avez beaucoup de CPU (et de bus) tout en maximisant le débit des vertex ou des pixels. Les VBOs sont utilisés pour réduire le CPU (moins d'appels api, transferts DMA parallèles au CPU). Comme vous n'êtes pas lié au CPU, ils ne vous apportent aucun gain. C'est la base de l'optimisation. Dans un jeu par exemple, le CPU devient précieux car il est nécessaire pour d'autres choses comme l'IA et la physique, et pas seulement pour émettre des tonnes d'appels api. Il est facile de voir que l'écriture de données de vertex (3 flottants par exemple) directement dans un pointeur mémoire est beaucoup plus rapide que l'appel d'une fonction qui écrit 3 flottants en mémoire - au moins, vous économisez les cycles pour l'appel.

10voto

Slava V Points 2259

Il y a peut-être quelques trucs qui manquent :

  1. C'est une supposition hasardeuse, mais votre de l'ordinateur portable Il se peut que la carte n'effectue pas du tout ce type d'opération (c'est-à-dire qu'elle l'émule).

  2. Est-ce que vous copiez les données dans la mémoire du GPU (via glBufferData ( GL_ARRAY_BUFFER avec soit GL_STATIC_DRAW o GL_DYNAMIC_DRAW param) ou utilisez-vous un pointeur vers le tableau principal (non GPU) en mémoire ? (cela nécessite de le copier à chaque image et les performances sont donc lentes).

  3. Est-ce que vous passez indices comme un autre tampon envoyé par glBufferData y GL_ELEMENT_ARRAY_BUFFER params ?

Si ces trois choses sont faites, le gain de performance est important. Pour Python (v/pyOpenGl), il est environ 1000 fois plus rapide sur des tableaux de plus de quelques 100 éléments, C++ jusqu'à 5 fois plus rapide, mais sur des tableaux de 50k-10m sommets.

Voici les résultats de mes tests pour c++ (Core2Duo/8600GTS) :

 pts   vbo glb/e  ratio
 100  3900  3900   1.00
  1k  3800  3200   1.18
 10k  3600  2700   1.33
100k  1500   400   3.75
  1m   213    49   4.34
 10m    24     5   4.80

Ainsi, même avec 10m de sommets, le framerate était normal, alors qu'avec glB/e, il était lent.

4voto

Andreas Points 1036

En passant :
Le "mode direct" (glBegin/glEnd) n'est pas supporté dans :

  • OpenGLES.
  • OpenGL 3.x.

Donc, si vous envisagez un jour de porter votre application sur une plate-forme mobile (par exemple, l'iPhone), ne vous y habituez même pas.

J'enseigne OpenGL à l'université et la diapositive expliquant glBegin/glEnd est entourée d'un gros cadre rouge avec un en-tête en gras "NE PAS UTILISER". rouge autour d'elle avec un en-tête en gras "DO NOT USE".

L'utilisation de tableaux de sommets ne représente que deux lignes de plus et vous économisez des cycles dès le départ.

2voto

Will Mc Points 187

En lisant le Livre Rouge, je me souviens d'un passage qui disait que les VBO sont peut-être plus rapides. en fonction du matériel . Certains matériels les optimisent, d'autres non. Il est possible que votre matériel ne le fasse pas.

1voto

Bahbar Points 12482

14Mpoints/s, ce n'est pas beaucoup. C'est suspect. Pouvons-nous voir le code complet faisant le dessin, ainsi que l'initialisation ? (comparez ces 14M/s aux 240M/s ( !) qu'obtient Slava Vishnyakov). C'est encore plus suspect qu'il tombe à 640K/s pour 1K dessins (comparé à ses 3.8M/s, qui semblent plafonnés par les ~3800 SwapBuffers, de toute façon).

Je parierais que le test ne mesure pas ce que vous pensez qu'il mesure.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X