J'ai du mal à distinguer la différence pratique entre appeler glFlush()
et glFinish()
.
La documentation dit cela glFlush()
et glFinish()
poussera toutes les opérations tamponnées vers OpenGL afin que l'on puisse être assuré qu'elles seront toutes exécutées, la différence étant que glFlush()
retourne immédiatement où sous forme de glFinish()
blocs jusqu'à ce que toutes les opérations soient terminées.
Après avoir lu les définitions, j'ai pensé que si je devais utiliser glFlush()
cela, je me heurterais probablement au problème de soumettre plus d'opérations à OpenGL qu'il ne pourrait en exécuter. Donc, juste pour essayer, j'ai troqué mon glFinish()
pour un glFlush()
et voilà, mon programme a fonctionné (pour autant que je sache), exactement la même chose; taux de trame, utilisation des ressources, tout était pareil.
Je me demande donc s'il y a beaucoup de différence entre les deux appels, ou si mon code les fait fonctionner pas différemment. Ou où l'un devrait être utilisé par rapport à l'autre. J'ai également pensé qu'OpenGL aurait un appel comme glIsDone()
pour vérifier si toutes les commandes tamponnées pour un glFlush()
sont complètes ou non (donc on n'envoie pas d'opérations à OpenGL plus rapidement qu'elles ne peuvent être exécutées), mais je n'ai pas pu trouver une telle fonction .
Mon code est la boucle de jeu typique:
while (running) {
process_stuff();
render_stuff();
}
Comme les autres réponses l'ont laissé entendre, il n'y a vraiment pas de bonne réponse selon les spécifications. L'intention générale de
glFlush()
est qu'après l'appel, le CPU hôte n'aura aucun travail lié à OpenGL à faire - les commandes auront été poussées vers le matériel graphique. L'intention générale deglFinish()
est qu'après son retour, il ne reste plus de travail, et les résultats doivent être disponibles également pour toutes les API non OpenGL appropriées (par exemple, les lectures du framebuffer, les captures d'écran, etc.). Que ce soit vraiment ce qui se passe dépend du conducteur. La spécification permet une tonne de latitude quant à ce qui est légal.la source
J'ai toujours été confus au sujet de ces deux commandes aussi, mais cette image m'a tout clarifié: apparemment, certains pilotes GPU n'envoient pas les commandes émises au matériel à moins qu'un certain nombre de commandes n'ait été accumulé. Dans cet exemple, ce nombre est 5 .
L'image montre diverses commandes OpenGL (A, B, C, D, E ...) qui ont été émises. Comme nous pouvons le voir en haut, les commandes ne sont pas encore émises, car la file d'attente n'est pas encore pleine.
Au milieu, nous voyons comment
glFlush()
affecte les commandes en file d'attente. Il indique au pilote d'envoyer toutes les commandes en file d'attente au matériel (même si la file d'attente n'est pas encore pleine). Cela ne bloque pas le thread appelant. Il signale simplement au pilote que nous n'enverrons peut-être pas de commandes supplémentaires. Par conséquent, attendre que la file d'attente se remplisse serait une perte de temps.En bas, nous voyons un exemple utilisant
glFinish()
. Il fait presque la même chose queglFlush()
, sauf qu'il fait attendre le thread appelant jusqu'à ce que toutes les commandes aient été traitées par le matériel.Image tirée du livre "Advanced Graphics Programming Using OpenGL".
la source
glFlush
etglFinish
faire, et je ne peux pas dire ce que dit cette image. Qu'y a-t-il du côté gauche et du côté droit? De plus, cette image a-t-elle été publiée dans le domaine public ou sous une licence qui vous permet de la publier sur Internet?Si vous ne voyez aucune différence de performance, cela signifie que vous faites quelque chose de mal. Comme certains l'ont mentionné, vous n'avez pas besoin d'appeler non plus, mais si vous appelez glFinish, vous perdez automatiquement le parallélisme que le GPU et le CPU peuvent atteindre. Laissez-moi aller plus loin:
En pratique, tout le travail que vous soumettez au pilote est groupé, et envoyé au matériel éventuellement plus tard (par exemple au moment de SwapBuffer).
Donc, si vous appelez glFinish, vous forcez essentiellement le pilote à pousser les commandes vers le GPU (qu'il a groupé jusque-là, et n'a jamais demandé au GPU de travailler), et bloquez le CPU jusqu'à ce que les commandes poussées soient complètement réalisé. Ainsi, pendant tout le temps que le GPU fonctionne, le CPU ne fonctionne pas (du moins sur ce thread). Et tout le temps que le CPU fait son travail (principalement des commandes de traitement par lots), le GPU ne fait rien. Alors oui, glFinish devrait nuire à vos performances. (Ceci est une approximation, car les pilotes peuvent commencer à faire fonctionner le GPU sur certaines commandes si beaucoup d'entre elles étaient déjà groupées. Ce n'est pas typique cependant, car les tampons de commandes ont tendance à être assez grands pour contenir un grand nombre de commandes).
Maintenant, pourquoi appelleriez-vous glFinish alors? Les seules fois où je l'ai utilisé, c'est lorsque j'ai eu des bogues de pilote. En effet, si l'une des commandes que vous envoyez au matériel plante le GPU, alors l'option la plus simple pour identifier la commande coupable est d'appeler glFinish après chaque Draw. De cette façon, vous pouvez préciser ce qui déclenche exactement le crash
En remarque, les API comme Direct3D ne prennent pas du tout en charge un concept Finish.
la source
glFlush remonte vraiment à un modèle client-serveur. Vous envoyez toutes les commandes gl via un tube vers un serveur gl. Ce tuyau pourrait tamponner. Tout comme n'importe quel fichier ou entrée / sortie réseau peut mettre en mémoire tampon. glFlush dit seulement "envoyer le tampon maintenant, même s'il n'est pas encore plein!". Sur un système local, cela n'est presque jamais nécessaire car une API OpenGL locale est peu susceptible de se mettre en mémoire tampon et émet simplement des commandes directement. De plus, toutes les commandes qui provoquent un rendu réel effectueront un vidage implicite.
glFinish, quant à lui, a été conçu pour mesurer les performances. Une sorte de PING vers le serveur GL. Il effectue un aller-retour d'une commande et attend que le serveur réponde "Je suis inactif".
De nos jours, les conducteurs locaux modernes ont des idées assez créatives sur ce que signifie être inactif. Est-ce "tous les pixels sont dessinés" ou "ma file de commandes a de l'espace"? Aussi parce que de nombreux anciens programmes ont saupoudré glFlush et glFinish dans tout leur code sans raison en tant que codage vaudou, de nombreux pilotes modernes les ignorent simplement comme une "optimisation". Je ne peux pas les blâmer pour ça, vraiment.
Donc, en résumé: considérez à la fois glFinish et glFlush comme aucune opération en pratique, sauf si vous codez pour un ancien serveur SGI OpenGL distant.
la source
Jetez un œil ici . En bref, il dit:
Un autre article décrit d'autres différences:
glFlush
glFinish
force OpenGL à exécuter des commandes exceptionnelles, ce qui est une mauvaise idée (par exemple avec VSync)Pour résumer, cela signifie que vous n'avez même pas besoin de ces fonctions lorsque vous utilisez le double tampon, sauf si votre implémentation de swap-buffers ne vide pas automatiquement les commandes.
la source
Il ne semble pas y avoir de moyen d'interroger l'état du tampon. Il y a cette extension Apple qui pourrait servir le même but, mais elle ne semble pas multiplateforme (je ne l'ai pas essayée.) À première vue, il semble avant que
flush
vous n'appuyiez la commande fence; vous pouvez ensuite interroger l'état de cette clôture lorsqu'elle se déplace dans la mémoire tampon.Je me demande si vous pouvez utiliser
flush
avant de mettre en mémoire tampon les commandes, mais avant de commencer à rendre la prochaine image que vous appelezfinish
. Cela vous permettrait de commencer le traitement de l'image suivante au fur et à mesure que le GPU fonctionne, mais si ce n'est pas fait au moment de votre retour, ilfinish
se bloquera pour s'assurer que tout est à l'état neuf.Je n'ai pas essayé cela, mais je le ferai sous peu.Je l'ai essayé sur une ancienne application qui utilise assez même le processeur et le GPU. (Il était utilisé à l'origine
finish
.)Quand je l'ai changé
flush
à la fin etfinish
au début, il n'y avait pas de problèmes immédiats. (Tout avait l'air bien!) La réactivité du programme a augmenté, probablement parce que le CPU n'était pas bloqué en attendant le GPU. Certainement une meilleure méthode.A titre de comparaison, j'ai retiré
finished
du début du cadre, en partantflush
, et il en a été de même.Donc, je dirais utiliser
flush
etfinish
, car lorsque le tampon est vide à l'appel definish
, il n'y a pas de performance. Et je suppose que si le tampon était plein, vous devriez le vouloir definish
toute façon.la source
La question est la suivante: voulez-vous que votre code continue de s'exécuter pendant que les commandes OpenGL sont exécutées, ou uniquement après l'exécution de vos commandes OpenGL.
Cela peut être important dans les cas, comme sur les retards du réseau, pour avoir une sortie de console uniquement après que les images ont été dessinées ou autre.
la source