Il était une fois, quand> était plus rapide que <… Attendez, quoi?

280

Je lis un super tutoriel OpenGL . C'est vraiment génial, croyez-moi. Le sujet sur lequel je suis actuellement est le Z-buffer. En plus d'expliquer de quoi 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 (qui est supérieure et qui ne l'est pas) peut également être personnalisé. 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, alors les valeurs de l'espace fenêtre seront inversées, en termes de ce qui constitue le plus proche ou le plus éloigné du spectateur.

Plus tôt, il a été dit que la valeur Z de l'espace fenêtre de 0 est la plus proche et 1 la plus éloignée. Cependant, si nos valeurs Z d'espace 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. Pourtant, si nous inversons la direction du test de profondeur (GL_LESS à GL_GREATER, etc.), nous obtenons exactement le même résultat. Ce n'est donc qu'une convention. En effet, retourner le signe de Z et le test de profondeur était autrefois une optimisation des performances vitale pour de nombreux jeux.

Si je comprends bien, en termes de performances, retourner le signe de Z et le test de profondeur n'est rien d'autre que changer une <comparaison en >comparaison. Donc, si je comprends bien , et l'auteur ne mentais pas ou de faire les choses, puis changer <à l' >habitude d'être une optimisation vitale pour de nombreux jeux.

L'auteur invente-t-il des choses, est-ce que je comprends mal quelque chose, ou est-ce effectivement le cas qui <était autrefois plus lent ( vitalement , comme le dit l'auteur) que >?

Merci d'avoir clarifié cette question assez curieuse!

Avertissement: je suis pleinement conscient que la complexité de l'algorithme est la principale source d'optimisations. De plus, je soupçonne que de nos jours, cela ne ferait vraiment aucune différence et je ne demande rien pour optimiser quoi que ce soit. Je suis juste extrêmement, douloureusement, peut-être d'une curiosité prohibitive.

Armen Tsirunyan
la source
6
Le lien vers ce didacticiel semble être (récemment) mort. :(
TZHX
@TZHX: Puisque la réponse acceptée est écrite par l'auteur du tutoriel, nous espérons la retrouver. Voir mon dernier commentaire à sa réponse :)
Armen Tsirunyan
3
Le tutoriel OpenGL référencé est disponible ici .
Fons
(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 performances est le résultat de ce qui se produit à la suite de l'opération de comparaison. C'est une route longue et sinueuse à prendre pour expliquer tous les effets secondaires, mais voici quelques conseils. Les jeux utilisés pour remplir le tampon de profondeur pour éviter un traitement plus coûteux des fragments pour les fragments qui ont échoué au test de profondeur. Quake avait l'habitude de diviser la plage de profondeur en deux moitiés pour éviter de vider le tampon de trame car le jeu remplissait toujours chaque pixel à l'écran, etc.
t0rakka
2
@Fons ressemble à nouveau au lien mort :(
nalzok

Réponses:

350

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

Je n'ai pas bien expliqué cela, car ce n'était pas important. Je pensais juste que c'était un petit truc 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 du matériel graphique, pas de votre CPU. Non operator<.

Ce à quoi je faisais référence était une ancienne optimisation spécifique où une trame que vous utiliseriez GL_LESSavec une plage de [0, 0,5]. L'image suivante, vous effectuez le rendu avec GL_GREATERune plage de [1.0, 0.5]. Vous faites des va-et-vient, "renversant littéralement le signe de Z et le test de profondeur" à chaque image.

Cela perd un peu de précision en profondeur, mais vous n'avez pas eu à effacer le tampon de profondeur, ce qui était une fois une opération plutôt lente. Étant donné que le nettoyage en profondeur n'est pas seulement gratuit de nos jours, mais en fait plus rapide que cette technique, les gens ne le font plus.

Nicol Bolas
la source
1
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. Par conséquent, il suffit d'effacer pour définir les états de tuile sur effacer (ce qui est rapide), changer le signe de comparaison de profondeur, cependant, signifie que la totalité du tampon HiZ doit être vidée car elle ne stocke qu'une valeur min ou max selon le signe de comparaison.
Jasper Bekkers
3
@NicolBolas: Commentaire de PerTZHX, le lien vers votre tutoriel dans ma question est mort. Pourriez-vous s'il vous plaît nous faire savoir où les didacticiels doivent être déplacés et éventuellement modifier la question, s'il vous plaît?
Armen Tsirunyan
2
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 endroit plus accessible. Peut-être GitHub ou quelque chose. web.archive.org/web/20150215073105/http://arcsynthesis.org/…
ApoorvaJ
3

La réponse est presque certainement que pour n'importe quelle incarnation de puce + pilote utilisée, la hiérarchie Z 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 - la mise en mémoire tampon Z est effectuée dans du matériel à fonction fixe et est canalisée - il n'y a aucune spéculation et donc aucune prédiction de branche.

Crowley9
la source
0

Une telle optimisation nuira aux performances de nombreuses solutions graphiques intégrées car elle rendra la résolution du tampon d'images moins efficace. L'effacement d'un tampon est un signal clair pour le pilote qu'il n'a pas besoin de stocker et de restaurer le tampon lors du binning.

Peu d'informations de base: un rasterizer de tuilage / binning traite l'écran en nombre de très petites tuiles qui tiennent dans la mémoire sur puce. Cela réduit les écritures et les lectures dans la mémoire externe, ce qui réduit le trafic sur le bus mémoire. Lorsqu'une trame est terminée (le swap est appelé ou les FIFO sont vidés car ils sont pleins, les liaisons de framebuffer changent, etc.) le framebuffer doit être résolu; cela signifie que chaque bac est traité à son tour.

Le pilote doit supposer que le contenu précédent doit être conservé. La conservation signifie que le bac doit être écrit dans la mémoire externe et restauré ultérieurement à partir de la mémoire externe lorsque le bac est à nouveau traité. L'opération claire indique au conducteur que le contenu du bac est bien défini: la couleur claire. C'est une situation qui est banale à optimiser. Il existe également des extensions pour "supprimer" le contenu du tampon.

t0rakka
la source
-8

Cela concerne les bits de drapeau dans un assemblage hautement réglé.

x86 a les instructions jl et jg, mais la plupart des processeurs RISC n'ont que jl et jz (pas de jg).

Joshua
la source
2
Si telle 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? À ma connaissance, ce n'est certainement plus le cas aujourd'hui. Étiez-vous censé écrire des forboucles avec une branche inconditionnelle en arrière et une branche conditionnelle, rarement prise en avant pour quitter la boucle alors? Cela semble gênant.
Pascal Cuoq
54
-1: Cette question n'a rien à voir avec les CPU . GL_LESS et GL_GREATER sont des opérations de comparaison de profondeur, qui s'exécutent sur des GPU.
Nicol Bolas
8
C'est drôle le nombre de répétitions que vous pouvez obtenir pour une réponse correcte au titre mais qui n'a pas grand-chose à voir avec la question réelle.
Joshua
7
+1 Non, cette réponse est correcte pour au moins une partie de la question. La question est: "L'auteur invente-t-il des choses, est-ce que je comprends mal quelque chose, ou est-ce effectivement le cas qu'une fois <était plus lent (vitalement, comme le dit l'auteur) que>?". Trois options sont proposées. Cette réponse répond sur la possibilité de l'option 3. Nulle part dans l'article la technologie du CPU / GPU n'est donnée, ni qu'il doit s'agir d'un GPU (premiers jeux 3D où sur CPU). Ok ... Je ne pense pas qu'il y ait eu beaucoup de jeux 3D sur RISC :-)
xanatos
3
(et la balise GPU a été ajoutée à 20:34. La première révision n'avait que la balise CPU. Cette réponse a été écrite à 18:44)
xanatos