[ASTUCE] HAAA LES COULEURS, INTEGER, BYTE ... EVITEZ LES SHR SHL ET AUTRES FONCT

hurrycane Messages postés 117 Date d'inscription samedi 4 janvier 2003 Statut Membre Dernière intervention 19 juin 2009 - 27 mai 2006 à 13:59
 Utilisateur anonyme - 3 juin 2006 à 13:04
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/37786-astuce-haaa-les-couleurs-integer-byte-evitez-les-shr-shl-et-autres-fonctions-delphi-va-se-charger-de-tout

Utilisateur anonyme
3 juin 2006 à 13:04
Merci beaucoup pour ces précisions,
je vais donc pouvoir tester l'assembleur intégré sans craintes.

Les interruptions .. ça me rappel des vieux codes sous TP6
et je me rappel aussi d'une panique quand elles n'étaient plus accèssibles...

Il ne me reste plus qu'a trouver une doc et en avant la découverte ;-)

Merci pour le lien MMX(très instructif)
@+
Cirec
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
2 juin 2006 à 02:00
non en fait, on ne peu pas faire de mauvais accés au registre ... c'est trés securisé justement ... au pire, et vive delphi pour cela, on obtient une erreur de compilation voir d'execution dans le pire des cas et la vive windows, il est trés rare de destabilisé le systeme en totalitée a cause d'une erreur.

la seule cause des blue screen sont des erreurs materiel et de pilote. pour un programme il n'y a generalement pas de blue screen.
les violation d'adresses se resume par un arret du processus ... la dessus windows assure plutot bien.

il est egalement impossible de detruire le CPU avec une mauvaise manipulation de code ... c'est impossible ou alors il faudrait vraiment faire exprés comme par exemple en coupant le ventillateur du CPU ... mais la encore, la carte mere est censée protéger le CPU et le CPU se protege egalement tout seul des surchauffes dangereuse (derniere generation).

l'assembleur n'est pas trés compliqué en sois ... bien que difficile a assimiler.
et tout programme ecrit en C ou Pascal est obligatoirement transformer en code assembleur a la compilation. (assembleur x86 pour les PC windows)

comme tu le vois dans mon exemple (pas parfait) il n'est pas difficile d'ecrire quelque ligne d'assembleur :

var R,G,B : byte;
Col : integer;
begin
// une couleur delphi (BBGGRR) ici un bleu metalique assé beau.
Col := $009C7454;

asm
push EAX; // sauvegarde du registre EAX
mov EAX, Col; // place Col dans le registre EAX
mov R,AL; // place la valeur du registre AL dans R
mov G,AH; // place la valeur du registre AH dans G
shr EAX, $0F; // decale EAX de 16 bits vers la droite
mov B,AL; // place la valeur du registre AL dans B
// mov A,AH; // on pourrait recuperer l'alpha ici.
pop EAX; // restaure le registre EAX
end;

// on affiche
caption := format('%.2x %.2x %.2x',[R,G,B]);
end;

l'assembleur integré a Delphi est tout simplement de l'assembleur ... du bon ... du vrai ... meme si ce n'est pas a un niveau d'utilisation comme dans MASM par exemple ...
et il n'est pas pratique de developper tout en assembleur...

quand on ecrit une delcaration ASM en delphi c'est surtout pour generer un code assembleur directement pour ne pas laisser le choix au compilo de delphi ...
c'est pour cela que dans la plupart des cas, les routines assembleurs ne sont pas utile car le compilateur delphi fait des merveilles de ce coté la.

pour notre exemple, l'utilisation de l'assembleur est totalement inutile.

mais il le serat si par exemple nous avions voulus créer un algorythme de traitement d'image pour de la video en utilisant les accelerations tel que MMX ou SSE...
la pour acceder a ces registres speciaux nous avons obligatoirement besoin de l'assembleur car il n'existe pas de fonctions speciales pour ces accelerations.

http://esibert.developpez.com/delphi/mmx/

ou l'on vois deux exemple d'utilisation de MMX pour les additions et les multiplications.

sinon l'assembleur ne rime plus vraiment a rien sous windows NT ...
a cause de la HAL qui empeche toute commutation directe avec les interruptions ...

exemple si on essaye de faire du ModeX (int 13h) ou si on essaye de cacher le curseur de texte dans la console ...

cache le curseur (erreur) :
asm
xor ax,ax
mov ah,01h
mov cx,2020h
int 10h
end;

version du dos installé (erreur) :
asm
MOV AH,30H
INT 21H
end;

et enfin, tentative d'initialisation du ModeX (erreur) :
Asm
Mov Ax,$13
Int $10
end;


tout cela passerais trés bien sur un DOS 6 ou DOS 7 (win 95 / 98) mais pas sous NT > 4.0

l'assembleur pour l'affichage ou la manipulation de peripherique etait trés bien a l'epoque...
mais avec OpenGL, DirectX, OpenAL et Cie ... il n'est plus que d'une utilitée toute relative.

et qui de nos jours fait encore des programmes console ? (cas rare).

bien sur, l'assembleur serat trés utile pour de l'encodage/decodage, compression ect...
la oui ... notre vieil ami nous serat encore utile.

et il est bien plus rapide d'ecrire :

color := R + (G shl 8) + (B shl 16);

que de refaire la meme en Assembleur :

push EAX;
push EBX;
mov EAX,R;
mov EBX,G;
shl EBX,$08;
add EAX,EBX; // ou or EAX,EBX;
mov EBX,B;
shl EBX,$0f;
add EAX,EBX; // ou or EAX,EBX;
mov Col,EAX;
pop EAX;
pop EBX;

sans parler des erreurs que l'on pourrait rencontrer avec les tailles d'operandes ... bref peu pratique dans des cas pareils et c'est bien pour cela qu'on a inventer des langages de haut niveau tel C,C++ et Pascal.

mais on peu toujours s'amuser a l'utiliser de cette façon pour ce faire la mains.
Utilisateur anonyme
31 mai 2006 à 12:55
Merci pour toutes ces précisions, n'ayant aucune connaissance dans les registres et en assembleur il m'était difficile de comprendre comment "Delphi" s'y prend pour trouver les informations.

Mais grâce à toi je me coucherai moins bête ce soir ;-)

Et qui sait peut être qu'un jour je me mettrais à l'assembleur (ça fait longtemps que ça me tente mais ça parait barbare)
mais ce qui me retient par dessus tout c'est la peur, en effet, je ne connais pas grand chose pour ne pas dire rien, je ne sais pas à quel point l'accès au registre est sécurisé où non.

Un accès maladroit au registre peut il avoir de fâcheuses conséquences ?

Et l'assembleur intégré de Delphi suffit il pour débuter ?

Bravo et merci 10/10

@+
Cirec
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
30 mai 2006 à 22:43
en fait aussi, pour bien comprendre l'empilage des registres d'un CPU, il faut voir cela avec une chronologie historique des CPU.

au depart les CPU etait en 8bit ... donc on avait que des registre 8Bit, impossible donc de travailler avec des valeurs 16 ou 32 bits, une valeur 16 bit occuperait donc 2 registre et une 32bits 4 registre ... ce qui ne permettais donc pas une grande souplesse et performance.
AL BL CL et DL
(L = Low)

les CPU sont ensuite passé au 16bits ... cela augmentas alors le nombre de registres :
registres 16 bits, registre 8bits
AX, AH AL
BX, BH BL
CX, CH CL
DX, DH DL
(H High et L Low)

ensuite sont arrivé les CPU 32bits :
regsitres 32bits, 16bits et 8bits
EAX, AX, AH AL
EBX, BX, BH BL
ECX, CX, CH CL
EDX, DX, DH DL
(E = Etendu)

et maintenant avec les CPU 64bits on imagine bien ce que cela donne :
les registre 64bits sont notés avec la lettre R.
RAX, EAX, AX, AH AL
RBX, EBX, BX, BH BL
RCX, ECX, CX, CH CL
RDX, EDX, DX, DH DL

sur les CPU 32 bit les valeurs 64Bit utilise plusieurs registre 32bits (2)...
on pourrait egalement emuler des valeurs 128bits sur les quatres registre A,B,C et D mais est-ce vraiment utile d'avoir des chiffres au dela du milliard de milliard ? (pour nous amateurs que nous sommes)

il existe bien sur d'autre registre plus specialisé ... pour les valeurs flottante, chaine de caractere, ect... ect... puis les autres registre MMX, SSE, SSE2, 3DNow ect...

mais il est inutile dans notre cas d'avoir recours a ces registres.
le but ici etait d'expliquer simplement l'empilation des registres du CPU ... ou du moins la hierarchie.
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
30 mai 2006 à 22:18
merci pour la correction, en effet, il y a des cas ou en presence de couleur Integer dont l'ordre des octets et RRGGBB (image Bitmap pf24bit) il faut inverser la structure des enregistrement.
on aurat non plus R,G,B mais B,G,R ... d'ou mon erreur grossiere d'avoir inverser toutes les structure.

donc si on travail avec des couleurs Delphi les structures seront R,G,B : byte
et si on travail avec des images bitmap les structures seronts B,G,R : byte

je sais c'est un peu bizare ... mais c'est comme ça...


en fait Delphi ne sais pas comment convertir une couleur en byte et inversement... pour lui il ne s'agit que de mettre chaque octet d'un entier 32 bit dans 3 ou 4 octet correspondant a des valeurs Byte.
pour ce n'est qu'un simple Transtypage ... et pour le CPU c'est une simple lecture de registre.
par exemple il placeras l'entier 32 bit dans une registre 32 bit (EAX par exemple) et il lirat alors les registres 8 bit d'EAX pour connaitre la valeur de chaque octet (AH et AL)

voici comment on peut voir cela en assembleur :

registre EAX :

[EAX--------] 32 bit
[-----|AX---] 16 bit
[-----|AH|AL] 8 bit

donc pour recuperer Col, R, G, B et A on ferat :

mov EAX, Col (on place Col=clBlue dans EAX sens des octets A,B,G,R)
mov R, AL (on place la valeur de AL dans R)
mov G, AH (on place la valeur de AH dans G)
shr EAX,16 (on decale EAX de 16 bits vers la droite)
mov B, AL (on place la valeur de AH dans B)
mov A, AH (on place la valeur de AH dans A)

equivalant delphi :

R := byte(Col);
G := byte(Col shr 8);
B := byte(Col shr 16);
A := byte(Col shr 24);

pour une couleur dont le sens des octets serat R,G,B,A (bitmap 32bit ou 24 bit)
mov EAX, Col
mov A, AL
mov B, AH
shr EAX,16
mov G, AL
mov R, AH

equivalant delphi :

A := byte(Col);
B := byte(Col shr 8);
G := byte(Col shr 16);
R := byte(Col shr 24);

et voilou ... voila comment delphi et le CPU execute le transtypage 32bit ver 4*8bit

dans l'exemple avec DWORD ver 2*WORD (32bit ver 2*16bit) on ferat plutot cela :

mov EAX, DWORDVALUE
mov Word1, AX
shr EAX,16
mov Word2, AX

equivalant delphi :

Word2 := word(DWORDVALUE);
Word1 := word(DWORDVALUE shr 16);

cela nous donne egalement d'autre possibilitée en melangeant valeur 16bit et 8bit :
Int 32bit vers W 16bits + B1 et B2 8bits

mov EAX, Int
mov B2, AL
mov B1, AH
shr EAX,16
mov W, AX

equivalant delphi :

B2 := byte(Int);
B1 := byte(Int shr 8);
W := word(Int shr 16);


on remarque donc que Absolute et les enregistrement "magique" nous permettent de se passer de ce genre de ligne de code.
Utilisateur anonyme
30 mai 2006 à 01:02
Toujours aussi bon notre F0xi,

mais j'ai quand même un petit truc qui me chiffonne:

1°) pour utiliser les déclarations suivantes avec une form :
type
TRGBRec = record
B,G,R : Byte;
end;
TARGBRec = record
A,B,G,R : byte;
end;

var
Color : integer; { ou TColor }
RGB : TRGBRec ABSOLUTE Color;
ARGB : TARGBRec ABSOLUTE Color;

Il faut transformer Color en Colors (par exemple) sinon ça ne fonctionnera pas, parce que Color entre en conflit avec la propriété Color de la form :

var
Colors : integer; { ou TColor }
clRGB : TRGBRec ABSOLUTE Colors;
ARGB : TARGBRec ABSOLUTE Colors;


Et tant qu'on y est évitez d'utiliser des noms de variables qui correspondent à des nom de procédure où fonction (Ex : RGB)


2°) Encore et toujours le même problème :
tu définis :
TRGBRec = record
B,G,R : Byte;

Mais ceci donne un résultat erroné !!!!

pour le tester :

procedure TForm1.Button1Click(Sender: TObject);
begin
Colors := clBlue;
With clRGB do
Label1.Caption := Format('Couleur : %s --- R : %d, G : %d, B : %d',[ColorToString(Colors), R, G, B ]);
end;

Donne Red := 255; Green := 0; Blue := 0; (clRed = Incorrect)

Alors que :
TRGBRec = record
R,G,B : Byte;

Donne Red := 0; Green := 0; Blue := 255; (clBlue = Correct)

Sinon cette petite astuce est très très utile et très simple en plus, comme le dit Hurrycane : Il fallait y penser

Ce qui me surprend c'est comment Delphi sait qu'il faut convertir un TColor en RGB et inversement où en toutes autres valeurs (selon les déclarations de Types)????

@+
Cirec
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
27 mai 2006 à 17:54
ahh j'ai hate de voir cela.

en fait il faut bien comprendre que ABSOLUTE est une sorte de pointeur mais ... sans pointeur.
c'est une directive qui permet réellement de partager l'adresse memoire d'une variable avec d'autre variable.

par exemple on pourrait egalement ecrire :

type
TIntCutByte = record
B4,B3,B2,B1 : byte;
end;
TIntCutWord = record
W2,W1 : byte;
end;
var
I : integer;
B : TIntCutByte ABSOLUTE I;
W : TIntCutWord ABSOLUTE I;

on pourrait egalement l'ecrire de cette façon :

TCardCut = record
case cardinal of
0 : (C : cardinal);
1 : (B4,B3,B2,B1 : byte);
2 : (W2,W1 : word);
end;
hurrycane Messages postés 117 Date d'inscription samedi 4 janvier 2003 Statut Membre Dernière intervention 19 juin 2009 1
27 mai 2006 à 13:59
fallait y penser foxi
fallait y penser !!! bravo
jai une petite idée pour lappliquer a autre chose
lorsque ce sera pret je te ferai la surprise ! 10/10
Rejoignez-nous