require("../global.php"); entete(); ?>
En tant que codeur, il nous arrive par moment des aventures insolites, des tuiles inattendues ou plus rarement des miracles inespérés, qui échappent quotidiennement au quidam ordinaire. Il était temps de consigner ces faits héroïques.
Du fait, cette page aurait pu porter comme titre "Le coin des codeurs", mais je préfère "JMP_$", qui est d'une part plus original et d'autre part mon instruction préférée.
Au menu cette fois-ci : Comment avoir deux pages linéaires en mode 13h, un exemple d'IRQ verticale qui fonctionne, un petit truc à savoir à propos du codage des modes d'adressage, une pénalité facile à éviter pour 486, un éclaircissement au niveau des algorithmes de texture 3d, une petite gruge rigolote pour casser l'écran en plusieurs fenêtres, et pour finir un petit détour par le monde des virus.
Bon zapping...
 
Je me permets de te rappeler, très cher, qu'un caractère, pour le CRTC, c'est un bloc de 4 points situés aux mêmes adresses sur chacun des quatre plans de bits. T'as pas lu le titre de l'article, il est question de codeurs, alors rentre vite à la maison car ta maman t'appelle, expédiais-je posément, tandis que j'envoyais ma santiag en direction du postérieur de l'intéressé, avec comme mission de lui laisser une marque tellement incrustée dans sa chair qu'elle se transmettra sur plusieurs générations, ce qui clût la conversation (Note aux CORs : hé, les mecs, je suis vraiment désolé pour le "clût", n'allez pas croire que je le fasse exprès mais d'après mon dictionnaire la forme passée de l'indicatif du verbe "clore" n'est pas usitée, j'ai donc dû inventer cette orthographe. Nécessité fait loi)
De retour chez moi, cette question continua de me trotter dans la tête. En partie parce qu'elle continuait de me trotter dans la tête, et en partie parce que je ne pouvais m'empêcher de faire le rapprochement avec le mode odd/even où il est effectivement possible de fixer la valeur du bit 0 de l'adresse d'un accès. Il s'agit du bit 5 du Misc à l'adresse 3c2 en écriture et 3cc en lecture. Je consultais alors ma documentation secrète à propos de ce bit et ce que je vis me laissa perplexe comme un intégriste devant un manuel de cuisine : il y avait un second bit à coté de celui qui m'attirait, un second bit négligemment marqué "indéfini - ne pas tenir compte".
Mon oeil ! Il se pourrait bien que ce bit, associé avec l'autre, me permette de fixer la valeur des deux bits effacés en mode chain4 !
J'essayais aussitôt.
Juste après quoi mon cri de victoire retentit dans le quartier ("GAAAAA!!"). Il se passait bien quelque chose ! Mes accès en écriture n'aboutissaient plus au même endroit !
Pour voir où ils aboutissaient, je modifiais les bits 14 et 15 du compteur d'adresse du CRTC dans la ferveur et dans le registre C, et là, avec une joie que je ne cherchais plus à dissimuler, je vis apparaître les points précédemment pockés !
Malheureusement, il me fallut aussi renoncer au bit indéfini qui n'avait apparemment réellement aucune influence, et je compris qu'il faudrait me contenter de deux pages et non pas quatre.
Résumé de la situation :
Pour écrire dans la seconde page, mettre le bit 5 du Misc (3c2) à un. Pour écrire dans la première page, le remettre à zéro.
Pour afficher la seconde page, mettre le bit 15 du registre C du CRTC (3d5) à un. Le remettre à zéro pour afficher la première page.
J'en conçu aussitôt quatre petites routines :
AffPage1: mov dx,3d4h mov ax,0ch out dx,ax retn AffPage2: mov dx,3d4h mov ax,800ch out dx,ax retn SetPage1: mov dx,3c2h mov al,63h out dx,al retn SetPage2: mov dx,3c2h mov al,43h out dx,al retn
Fermement décidé à faire breveter cette trouvaille pour revendre par la suite les droits d'utilisation à une grosse firme, et devenir par la même billgathesement riche, je pris tout de même la précaution de vérifier mon programme de test sur d'autres machines.
A la fac tout d'abord. Ca ne marcha pas.
Puis chez un pote. Puis chez un deuxième. Puis un troisième. Ca ne marcha nulle part.
Puis sur tout le board !
Ah, ça fonctionna chez un autre user ! Enfin.
Quelle carte est-ce que j'utilise moi ? Une Trident. Argh.
Aaaaaaaaaaaaargh !!!!
Ca ne marche exclusivement que sur les Tridents. Je suis vert. Essayons d'oublier. Pas facile.
D'accord, mais une fois que vous aurez méprisement arraché le jumper fautif, vous ne serez peut-être pas beaucoup plus avancé, car la procédure à suivre pour diriger l'interruption n'est pas très facile à trouver, les diverses documentations restant pour le moins floues sur le sujet.
Pour vous éviter quelques heures de recherches, voici la marche à suivre :
/* Mettre le bit 4 du registre 11h du CRTC à 1. /* Laisser le bit 5 à zéro (dans la bible il est écrit qu'il faut que ce bit soit sur 1 pour déclencher l'IRQ, mais c'est le contraire en fait)
/* Puis naturellement autoriser les IRQ 2 et 9 qui peuvent être masquées dans les deux 8259
Et voilà. Jusqu'ici ca va. Le problème c'est pour signaler à la VGA que l'interruption est terminée et qu'elle peut en renvoyer une autre quand elle veut. Pour cela il faut :
/* Lire l'ISR0 (port 3c2 en lecture) /* Remettre le bit 4 à 0 dans le registre 11h du CRTC /* Aussitôt le remettre à 1
/* Bien sur ensuite il faut signaler l'EOI aux deux 8259
Voilà, maintenant à vous les joies des IRQ verticales !
Vous lancez votre débugger, armé jusqu'aux dents d'un flegme plein d'appréhension (ce qui, que les choses soient bien claires, ne signifie pas grand chose).
Et là, lorsque vous vous retrouvez face à votre code, les bras et/ou la mâchoire vous en tombent : Vos jolis MOV [EDX*2],al ont étés remplacés par de peu élégants MOV [EDX*2+00000000h],al qui prennent 4 octets de plus que prévus, un cycle de préchargement supplémentaire, qui font déborder votre inner loop du cache, bref, en un mot : célakatass ! "Mais pourquoiiii !?" hurlez-vous.
C'est la vie. Il n'existe pas de forme de codage qui permette de coder un index seul sans déplacement. Et lorsque vous appliquez un facteur à une base, ce n'est plus une base mais un index.
Pour corriger ce petit problème, deux solutions : utiliser une base nulle, genre MOV [EDX*2+EBX],al, ce qui est plus court et revient au même si EBX est nul, ou bien si le facteur est deux, faire plutôt MOV [EDX+EDX],al.
Dans le même genre, sachez également qu'il est impossible d'utiliser EBP comme base sans avoir en plus un déplacement d'au moins 8 bits, ce qui rajoute un octet a l'instruction.
Inutile de me répéter "Intel Suxx", il n'y avait aucune autre manière de faire, et si vous arrivez à faire mieux avec 3 octets d'OpCode pour coder toutes les instructions avec tous les modes d'adressage possibles, et bien, heu... vous n'y arriverez pas.
Or ce principe de pipe line n'est possible que si les instructions exécutées en premier n'ont pas d'influence sur le décodage des instructions suivantes. Si c'est la cas, le 486 stoppe le décodage de l'instruction suivante jusqu'à ce que l'instruction en cours d'exécution soit achevée, ce qui coûte un cycle.
Notez au passage que les 386 ne disposent pas de cette capacité à déterminer si une instruction aura des répercutions sur la suivante, ce qui fait que le processeur stoppe toujours le décodage d'une instruction pendant une exécution. C'est ce "semi-pipeline" qui fait que les instructions du 386 nécessitent généralement un cycle de plus que sur 486.
Bref, vous pouvez vous demander : "mais quelles instructions influent sur le décodage des suivantes ?" C'est très simple : les références mémoires ne peuvent pas être décodées à l'avance si l'on ne connaît pas la valeur des registres utilisés comme base ou index dans l'opérande.
Résultat des courses, si vous faîtes :
MOV BX,15 ADD AX,[BX]
Le 486 stoppera le décodage de l'ADD tant que le MOV ne sera pas exécuté, et vous perdrez un cycle.
Il convient donc d'éviter une telle situation en entrelaçant les instructions (pas pour tout le programme, pensez-y juste dans les boucles les plus internes).
Il est donc fréquent de lire dans des news-groups orientés "coderz" quantités d'âneries qui font peter une durite aux codeurs graphistes sérieux qui tentent de faire comprendre à ces milliers de "coderz" qu'un Phong n'est pas un Gouraud et qu'un Gouraud n'est pas un Deep-shading. C'est pour préserver les dernières durites de ces codeurs regardant du patrimoine (dont je ne fais pas partie) que je vais énoncer ici (en priant pour ne pas faire d'erreur) les deux principes sus-nommés de Gouraud et de Phong.
Les deux méthodes ont pour but de lisser des surfaces polygonales 3d. Elles ne permettent pas de lisser les contours des objets qui paraîtront donc toujours taillées à la hache ou au démanteleur fibro-plasmique amorti, selon vos moyens.
Pour chaque point de l'objet, on connaît un vecteur normal. Je sais, il n'est pas très intelligent de parler de vecteur normal pour un point, mais vous voyez de quoi je parle : je parle d'un vecteur normal à la surface qui passerait par ce point si cette surface était continue d'une face à l'autre. Pour avoir ce vecteur, vous pouvez le rentrer manuellement dans vos données ou bien le calculer avec la moyenne des normales des faces environnantes ou bien avec un vecteurs qui va du centre de l'objet vers le point si votre objet est un patatoïde.
Bref, on dispose aussi du vecteur lumineux qui pointe de la source de lumière vers l'objet (vecteur qui n'est constant pour l'objet que dans l'hypothèse ou la source de lumière est à l'infini).
Le but du lissage est de donner à chaque point affiché une intensité proportionnelle au cosinus de l'angle entre le vecteur lumineux et le vecteur normal _EN_CE_POINT_.
Le problème, c'est qu'on ne connaît pas le vecteur normal en chaque point. Tout le principe de Phong réside dans le calcul d'une approximation raisonnable de ce vecteur à partir d'un nombre fini de vecteurs normaux, à chaque sommet d'un polygone. Gouraud lui se simplifie le travail en cherchant à "approximer" directement l'intensité finale.
Citons avant de commencer l'approximation la plus simple, celle qui consiste à reprendre le vecteur normal à la face pour tous les points de la face. Si l'on considère de plus que le vecteur lumineux est fixe sur la face (c'est à dire que la source de lumière est très éloignée), intensité pour toute la face est constante. Mais on ne lisse rien du tout.
Pour lisser, M. Gouraud à proposé (Quand ca ? beuuuuh... il y a quelques années quand même, hein...) d'interpoler linéairement intensité sur toute la surface du polygone. Si le polygone est un triangle, l'opération est très facile. Sinon, il faut veiller à ce que la face soit effectivement interpolable linéairement entre ces vecteurs aux sommets, mais bon bref, vivent les triangles.
Pour du Gouraud, on calcule donc intensité des points où l'on connaît la normale (produit scalaire) et on interpole ensuite cette intensité le long des côtés du polygone puis entre deux côtés pour remplir le polygone. On s'en tire donc avec une addition par point, avec un petit code gen du genre
i = 0 REPT MAX MOV [DI+i],AH ADD AX,BX i = i+1 ENDM
On peut même faire mieux, mais là n'est pas le sujet.
Notez au passage, parce que ce n'est pas évident pour tout le monde (ca ne l'a pas été pour moi en tout cas), que l'incrément de couleur d'un point à un autre est constant sur tout le polygone.
L'intérêt du Gouraud est que la transition d'une face à l'autre se fait sans à-coup intensité (normal : deux polygones contigus partagerons les mêmes normales sur le côté commun). L'inconvénient c'est que les faces apparaissent toujours plates.
Pour remédier à ce problème, M. Phong proposa quelques temps après une amélioration à la méthode de Gouraud, qui consiste à interpoler les vecteurs normaux plutôt que intensité, et à RENORMER LES VECTEURS. Il est en effet nécessaire de garder la norme du vecteur normal constante si l'on veut donner l'impression de faire tourner ce vecteur, et donc au final d'avoir l'impression que la face plane est courbe.
Il est donc nécessaire de se faire un produit vectoriel entre le vecteur normal de chaque point et un vecteur lumineux qui pourra être lui aussi recalculé pour chaque point (si votre source de lumière n'est pas à l'infini).
Notez que si vous êtes prêt à calculer votre produit scalaire en coordonnées sphériques, c'est un jeu d'enfant d'interpoler le vecteur en coordonnées angulaires car alors il n'est plus nécessaire de "renormer".
L'intérêt du phong est que le rendu est exact. La lumière forme un halo sur une face qui ne parait plus plate.
Il existe bien sur des méthodes d'approximation qui permettent d'obtenir un effet similaire de "halo" sans le calcul point par point du produit scalaire entre deux vecteurs interpolés et renormés, mais aucune de ces méthodes, à ma connaissance, ne correspondent à un cas particulier de la méthode de Phong, il n'est donc effectivement pas convenable d'appeler ça du Phong.
D'autant que certaines de ces méthodes n'ont rien à envier question ingéniosité à celles exposés ci-dessus (qui ont quand même ce petit côté bête et méchant, il faut bien le dire).
But this story shall also be told...
Ce que l'on ne sait pas généralement, c'est que ce compteur peut fonctionner plusieurs fois par image, ce qui permet de répéter plusieurs fois la même portion de VRAM à l'écran.
A quoi ca sert de répéter plusieurs fois la même chose ? Oh, pas à grand chose, mais c'est toujours utile par exemple pour des zooms hards à la "Good Bad & Ugly".
Voici une petite arnaque à tomber par terre tellement qu'elle est bonne, tirée du virus V6000, dont le but est de garder le virus en mémoire ... lorsque l'utilisateur reboote à partir d'une disquette saine !
Si si, c'est possible, voici comment le virus s'y prend : Il écrit dans la CMOS qu'il n'y a pas de lecteur de disquettes (il faut recalculer le check sum pour que la gruge passe inaperçue, bien sur), et lorsque le micro reboote, le BIOS va inconditionnellement charger le secteur boot du disque dur (ce qui se fait en un rien de temps et ne laisse pas l'utilisateur se rendre compte de ce qui se passe), et dans ce secteur de boot le virus s'installe en mémoire, remodifie la CMOS pour réintégrer le lecteur de disquettes,puis simule un boot avec le BIOS. Au passage, il peut même, pour plus de sécurité, infecter la disquette (de toute façon, le virus est stealth).
Et hop, le tour est joué, l'utilisateur croit s'être débarrassé du virus alors qu'en fait pas du tout.
" Un PC multimédia permet de travailler de façon interactive, de l'image fixe ou animée, du son et du texte. Il possède un lecteur CD ROM double ou quadruple vitesse, une carte son, des enceintes et une carte graphique suffisante pour une bonne qualité d'image". Qu'on se le dise.
Voila qui, on l'espère, incitera nos lecteurs a délaisser quelques temps la section 'lingerie' de ce catalogue.
D'autant qu'on trouve aussi (page 1159) un indispensable glossaire que vous transporterez toujours avec vous lors des coding parties. Par exemple, vous serez peut être ravis d'apprendre qu'"Un 486DX convient parfaitement pour travailler sur tableur" (mais si vous voulez en plus jouer à PacMan, attendez le P6), que la RAM est cette chose qui "permet d'utiliser plusieurs logiciels en même temps", et autres merveilleusetées.
Bon, allez, assez plaisanté, on a tous du code qui nous attend.
A la prochaine.
PiedDePage(); ?>