283 votes

Il était une fois, quand > était plus rapide que < ... Attends, quoi ?

Je suis en train de lire un tutoriel OpenGL impressionnant . C'est vraiment génial, croyez-moi. Le sujet que j'aborde actuellement est le Z-buffer. En plus d'expliquer ce dont il s'agit, l'auteur mentionne que nous pouvons effectuer des tests de profondeur personnalisés, tels que GL_LESS, GL_ALWAYS, etc. Il explique également que la signification réelle des valeurs de profondeur (ce qui est supérieur et ce qui ne l'est pas) peut également être personnalisée. Je comprends jusqu'à présent. Et puis l'auteur dit quelque chose d'incroyable :

La plage zNear peut être supérieure à la plage zFar ; si c'est le cas, les valeurs de l'espace de la fenêtre sont les suivantes valeurs de l'espace de la fenêtre seront inversées, en termes de ce qui constitue le plus proche ou le plus éloigné de l'observateur.

On a dit plus haut que la valeur Z de 0 dans l'espace fenêtre est la plus proche et la plus proche de la valeur Z dans l'espace fenêtre. 1 est la plus éloignée. Cependant, si les valeurs Z de notre espace de clip étaient annulées, la profondeur de 1 serait la plus proche de la vue et la profondeur de 0 serait la plus éloignée. profondeur de 1 serait la plus proche de la vue et celle de 0 serait la plus éloignée. la plus éloignée. Pourtant, si nous inversons la direction du test de profondeur (GL_LESS vers GL_GREATER, etc.), nous obtenons exactement le même résultat. Il ne s'agit donc que d'une convention. En effet, inverser le signe de Z et le test de profondeur était autrefois une optimisation vitale des performances pour de nombreux jeux.

Si je comprends bien, du point de vue des performances, inverser le signe de Z et le test de profondeur n'est rien d'autre que changer un < par rapport à un > comparaison. Donc, si je comprends bien et que l'auteur ne ment pas ou n'invente pas des choses, alors changer < a > utilisé pour être une optimisation vitale pour de nombreux jeux.

Est-ce que l'auteur invente des choses, est-ce que je comprends mal quelque chose, ou est-ce que c'est vraiment le cas qu'une fois < était plus lent ( vitalement (comme le dit l'auteur) que > ?

Merci de clarifier cette question assez curieuse !

Avertissement : je suis pleinement conscient que la complexité des algorithmes est la source principale des optimisations. De plus, je soupçonne qu'aujourd'hui cela ne ferait aucune différence et je ne demande pas cela pour optimiser quoi que ce soit. Je suis juste extrêmement, douloureusement, peut-être prohibitivement curieux.

6 votes

Le lien vers ce tutoriel semble avoir disparu (récemment) :(

0 votes

@TZHX : Comme la réponse acceptée est rédigée par l'auteur du tutoriel, nous avons l'espoir de la retrouver. Voir mon dernier commentaire à sa réponse :)

0 votes

(a < b) est identique à (b > a), il n'est donc absolument pas nécessaire d'implémenter les deux opérations de comparaison dans le matériel. La différence de performance est le résultat de ce qui se passe à la suite de l'opération de comparaison. La route est longue et sinueuse pour expliquer tous les effets secondaires, mais voici quelques indications. Les jeux avaient l'habitude de remplir le tampon de profondeur pour éviter un traitement plus coûteux des fragments qui échouaient au test de profondeur. Quake avait l'habitude de diviser la plage de profondeur en deux moitiés pour éviter de vider le tampon d'image parce que le jeu remplissait toujours chaque pixel de l'écran, etc.

353voto

Nicol Bolas Points 133791

Si je comprends bien, en termes de performances, inverser le signe de Z et du test de profondeur n'est rien d'autre que de changer une comparaison < en une comparaison >. Donc, si je comprends bien et que l'auteur ne ment pas ou n'invente pas des choses, le changement de < en > était une optimisation vitale pour de nombreux jeux.

Je ne l'ai pas particulièrement bien expliqué, car ce n'était pas important. J'ai juste pensé que c'était un petit détail intéressant à ajouter. Je n'avais pas l'intention de passer en revue l'algorithme spécifiquement.

Cependant, le contexte est essentiel. Je n'ai jamais dit qu'une comparaison < était plus rapide qu'une comparaison >. Rappelez-vous : nous parlons de tests de profondeur de matériel graphique, pas de votre CPU. Pas operator< .

Ce à quoi je faisais référence était une ancienne optimisation spécifique où une trame vous utilisiez GL_LESS avec une plage de [0, 0.5]. L'image suivante, vous effectuez le rendu avec GL_GREATER avec une plage de [1,0, 0,5]. Vous allez et venez, en inversant littéralement le signe de Z et le test de profondeur à chaque image.

On perd ainsi un bit de précision de la profondeur, mais il n'est pas nécessaire de vider le tampon de profondeur, ce qui était autrefois une opération plutôt lente. Comme l'effacement de la profondeur est non seulement gratuit de nos jours mais aussi plus rapide que cette technique, les gens ne le font plus.

1 votes

La raison pour laquelle l'effacement du tampon de profondeur est plus rapide de nos jours a deux raisons, toutes deux basées sur le fait que le GPU utilise un tampon de profondeur hiérarchique. Il suffit donc d'effacer les états des tuiles (ce qui est rapide), mais changer le signe de comparaison de la profondeur signifie que l'ensemble du tampon HiZ doit être vidé car il ne stocke qu'une valeur minimale ou maximale en fonction du signe de comparaison.

3 votes

@NicolBolas : Par le commentaire deTZHX, le lien vers votre tutoriel dans ma question est mort. Pourriez-vous s'il vous plaît nous faire savoir où ont été déplacés les tutoriels et éventuellement éditer la question, s'il vous plaît ?

2 votes

Les tutoriels sont disponibles sur l'archive web. Si @NicolBolas le permet, il serait utile pour la communauté que nous puissions les déplacer vers un emplacement plus accessible. Peut-être GitHub ou autre. web.archive.org/web/20150215073105/http://arcsynthesis.org/

3voto

Crowley9 Points 396

La réponse est presque certainement que, quelle que soit l'incarnation de la puce+pilote utilisée, le Z hiérarchique ne fonctionnait que dans une seule direction - c'était un problème assez courant à l'époque. L'assemblage/branchement de bas niveau n'a rien à voir avec cela - le Z-buffering est fait dans du matériel à fonction fixe, et est pipeliné - il n'y a pas de spéculation et donc pas de prédiction de branchement.

-8voto

Joshua Points 13231

Cela a à voir avec les bits de drapeau dans les assemblages hautement réglés.

Le x86 possède des instructions jl et jg, mais la plupart des processeurs RISC ne possèdent que jl et jz (pas de jg).

0 votes

@Armen : cela dépend de la fréquence d'utilisation de l'appel, n'est-ce pas ?

2 votes

Si c'est la réponse, cela soulève de nouvelles questions. La "branche prise" était-elle plus lente que la "branche ignorée" sur les premiers processeurs RISC ? Ce n'est certainement pas le cas aujourd'hui de manière mesurable, pour autant que je sache. Étiez-vous censé écrire for des boucles avec une branche inconditionnelle vers l'arrière et une branche conditionnelle, rarement utilisée, vers l'avant pour sortir de la boucle ? Ça semble bizarre.

0 votes

Je pensais que sur les architectures modernes, la prédiction des branchements dépendait de la direction du branchement [ainsi, les branchements conditionnels vers l'arrière sont plus rapides s'ils sont pris, vers l'avant sont plus rapides s'ils ne sont pas pris].

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