J'apprenais OpenGL récemment. Dans les jeux, nous devons mettre à jour la position des objets de jeu fréquemment, et ils entreront et sortiront de l'écran en permanence. Cela signifie donc que dans le rendu, nous devons également mettre à jour le tampon de sommet assez souvent.
Dans le contexte d'OpenGL, une façon intuitive est d'utiliser glBufferSubData pour mettre à jour ceux qui ont changé.
Mais j'ai également lu en ligne une astuce appelée Orphaning qui crée une nouvelle mémoire tampon et y télécharge toutes les données des sommets.
En raison également du coût de l'état et du coût de téléchargement, plusieurs glBufferSubData peuvent également coûter plus cher.
Voici ma question,
- Quelle méthode est la meilleure?
- Les stands sont-ils vraiment importants dans ce cas?
- Les changements d'état et le coût de téléchargement sont-ils vraiment importants dans ce cas?
Merci!
opengl
rendering
optimization
vbo
YiFeng
la source
la source
Réponses:
C'est une question complexe avec beaucoup de petits détails qui comptent vraiment, les performances varient en fonction de la plate-forme et de l'application. Vous devez donc définir les goulots d'étranglement possibles avant d'investir dans des optimisations.
Cela dit, tout d'abord, je suppose que vous devez réduire autant que possible les téléchargements et les mises à jour, par exemple utiliser l'instanciation.
Deuxièmement, notez que les GPU ne peuvent pas transférer les tampons et effectuer le rendu en même temps, donc toutes les commandes OpenGL dans la file d'attente de commandes sont traitées séquentiellement par le périphérique. Il existe différentes manières de copier des données et / ou de les rendre disponibles pour être utilisées par le GPU.
Il existe différentes façons de diffuser des données sur le GPU
1-
glBufferData
ouglBufferSubData
méthodeUtiliser
glBufferData
ouglBufferSubData
est comme memcpy. vous passez un pointeur et une opération DMA peut être effectuée, je l'ai dit parce que la mémoire peut être épinglée dans la mémoire du processeur et utilisée directement par le GPU sans qu'un transfert de mémoire vers le GPU ne se produise, en fonction de l'indicateur d'utilisation (GL_STREAM). À votre avis, vous devriez essayer ceci au début, car il est plus simple à mettre en œuvre.2- obtenir un pointeur sur la mémoire interne en utilisant
glMapBuffer
Si ce qui précède n'est pas assez bon, vous pouvez utiliser
glMapBuffer
un pointeur vers la mémoire interne et vous pouvez utiliser ce pointeur pour remplir directement le tampon, c'est bien avec les opérations de lecture et d'écriture de fichier, car vous pouvez directement mapper les données du fichier dans la mémoire du GPU plutôt que de copier d'abord dans un tampon temporaire. Si vous ne voulez pas mapper tout le tampon, vous pouvez utiliserglMapBufferRange
ce qui peut être utilisé pour mapper une partie du tampon.Une astuce consiste à créer un grand tampon, à utiliser la première moitié pour le rendu et la seconde moitié pour la mise à jour.
3- Orphelin tampon
En ce qui concerne l'orphelin du tampon, cela peut être fait en utilisant glBufferData avec null et les mêmes paramètres qu'il avait. Le pilote retournera le bloc de mémoire une fois qu'il n'est pas utilisé. Et sera utilisé par le prochain appel glBufferData (aucune nouvelle mémoire ne sera allouée).
Toutes les méthodes mentionnées provoquent beaucoup de synchronisation coûteuse, encore une fois, les GPU ne peuvent pas transférer les tampons et effectuer le rendu en même temps.
4-
Unsynchronized Buffers
La méthode la plus rapide (et la plus difficile à obtenir) consiste à utiliser des tampons sans synchronisation
GL_MAP_UNSYNCHRONIZED_BIT
avecglMapBufferRange
lesquels vous pouvez utiliser un indicateur , le problème est qu'aucune synchronisation n'est effectuée, nous pouvons donc télécharger des données vers un tampon utilisé et donc tout bousiller. Vous pouvez utiliser plusieurs tampons avec un bit non synchronisé pour rendre les choses un peu plus faciles.la source
Je le fais d'une autre manière. Peut-être que quelque chose ne va pas là-bas. Des choses dangereuses cachées.
(J'utilise C # + OpenTK.GameWindow)
Pour l'instanciation de l'objet, j'utilise un objet tampon de tableau séparé pour l'ensemble des matrices de modèle pour chaque instance. Dans le sommet partagé:
Dans mes matrices de code C # sont stockées dans un tableau flottant
float[] mat4_array
Ensuite, je lie le tableau à l'objet tampon de tableau:
À chaque image, les matrices du modèle sont mises à jour. Pour mettre à jour,
mat4_array
j'appelle simplement:et rendre la scène. en utilisant
GL.DrawElementsInstanced
.Il n'y a pas d'appels OpenGL supplémentaires et cela fonctionne parfaitement.
la source