UTILISATION DE LA SCANLINE POUR OPTIMISER LA LECTURE ET L'ÉCRITURE DES FONCTIONS

Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 - 28 oct. 2011 à 16:08
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 - 7 nov. 2011 à 11:55
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/53709-utilisation-de-la-scanline-pour-optimiser-la-lecture-et-l-ecriture-des-fonctions-get-set-pixels

cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
7 nov. 2011 à 11:55
Re-Bonjour,

A Caribensila : Il y a quand-même un truc qui me chagrine : Je n'arrive pas à comprendre pourquoi le code de RectangleFilling3b(color : TColor) n'est pas plus rapide que ton code de Pattern qui est nettement plus compliqué vu qu'il travaille avec une texture de taille différente de celle de la cible !!!???.

Je pensais améliorer en virant l'appel aux Logs Népériens et à Power en les remplaçant par du plus simple comme ci-dessous mais on n'y gagne rien de notable.

procedure tFastBitmap2.RectangleFilling3b(color : TColor);
var Col : TRGBTriple; ScanYX : pRGBTriple; x,y,ncop,nlc,i,j : integer;
sl,size : DWord; adSrc : pointer;
begin with Col do begin
rgbtBlue := GetBValue(color);
rgbtGreen := GetGValue(color);
rgbtRed := GetRValue(color);
end;
// Dernière Ligne :
ScanYX :=pRGBTriple(Scan0+(H-1)*MLS);
for x:=0 to pred(W) do begin
ScanYX^ := Col;
Inc(ScanYX);
end;
// Re-copies des dernières lignes par doublement du nombre de lignes
// Calcul du nombre ncop de re-copies possibles par doublement
ncop:=0; j:=H shr 1;
while j>0 do begin
inc(ncop); j:=j shr 1;
end;
sl :=abs(MLS); // size d'une ligne
adSrc:=Bmp.Scanline[H-1]; // adresse de la source
y:=H-2; // indice de l'adresse de destination
nlc:=1; // nlc = nombre de lignes à re-copier
for i:=1 to ncop do begin
size:=nlc*sl; // taille du block à re-copier
CopyMemory(Bmp.ScanLine[y],adSrc,size);
dec(y,nlc);
nlc:=nlc shl 1; // doublement du nombre de lignes à re-copier
end;
if y<0 then EXIT;
// Re-copie pour les lignes manquantes du haut
size:=(y+1)*sl;
CopyMemory(Bmp.ScanLine[y],adSrc,size);
//100 fois RectangleFilling3b sur Bmp de 750x602, mis : 734 ms
//100 fois RectangleFilling3b sur Bmp de 750x602, mis : 797 ms
//100 fois RectangleFilling3b sur Bmp de 750x602, mis : 766 ms
// N'oublie pas que les pointeurs augmentent certes de gauche à droite sur chaque ligne,
// mais que les pointeurs de chaque début de ligne, eux, augmentent de bas en haut.
end;

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
7 nov. 2011 à 11:20
Bonjour,

Comparaison de perfs entre l'algo Pattern et la version Pettern2 suivante :

procedure tFastBitmap2.Pattern2(const Patt, Display: TBitmap);
begin with Display.canvas do begin
brush.BitMap:=Patt;
FillRect(clipRect);
end;
end;

Résultats :
- 100 fois Pattern avec Texture de 50x50 sur Bmp de 750x602, mis : 735 ms
- 100 fois Pattern2 avec Texture de 50x50 sur Bmp de 750x602, mis : 641 ms
Comme quoi, les gars et les filles qui ont conçu puis optimisé Canvas.FillRect() ont bien "bétonné" leur code ... avec un atout supplémentaire : Canvas.FillRect(Rect) permet de ne remplir qu'une partie du bitMap-cible alors que Pattern remplit toute la surface de la cible.

Conclusion : On aura au moins essayé.

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
6 nov. 2011 à 17:26
Re,

Finalement la RectangleFilling3b marche en effectuant les re-copies du bas vers le haut, comme suit :

procedure tFastBitmap2.RectangleFilling3b(color : TColor);
var Col : TRGBTriple; ScanYX : pRGBTriple; x,y,ncop,nlc,i : integer;
sl,size : DWord; adSrc : pointer;
begin with Col do begin
rgbtBlue := GetBValue(color);
rgbtGreen := GetGValue(color);
rgbtRed := GetRValue(color);
end;
// Dernière Ligne :
ScanYX :=pRGBTriple(Scan0+(H-1)*MLS);
for x:=0 to pred(W) do begin
ScanYX^ := Col;
Inc(ScanYX);
end;
// Re-copies des dernières lignes par doublement du nombre de lignes
ncop:=trunc(Ln(H)/Ln(2)); // nombre de re-copies possibles par doublement
sl :=abs(MLS); // size d'une ligne
adSrc:=Bmp.Scanline[H-1];
y:=H-2; // indice de l'adresse de destination
for i:=1 to ncop do begin
if i=1 then nlc:=1 else nlc:=nlc*2; // nombre de lignes à re-copier
size:=nlc*sl;
CopyMemory(Bmp.ScanLine[y],adSrc,size);
y:=y-nlc;
end;
if y<0 then EXIT;
// Re-copie pour les lignes manquantes du haut
size:=(y+1)*sl;
CopyMemory(Bmp.ScanLine[y],adSrc,size);
end;

Résultat : 100 fois RectangleFilling3b sur Bmp de 750x602, mis : 734 ms
alors qu'avec Canvas.FillRect sur Bmp de 750x602 cela avait mis : 656 ms
donc à moins de trouver un truc à améliorer dans la RectangleFilling3b on peut la laisser tomber et utiliser tout bonnement Canvas.FillRect().

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
6 nov. 2011 à 16:52
Re-bonjour,

Ok, merci pou tFastBitmap2.RectangleFilling3b() et pour FillMemory(p,W*H*SizeOf(TRGBTriple),Gris);

Je verrai ça demain matin, car comme je suis scotché à ma bécane depuis ce mat, je vais maintenant rattraper mon repas de midi.

A+.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 nov. 2011 à 16:43
Et pour :

FillMemory(p,W*H*SizeOf(TRGBTriple),Gris);

W*H*SizeOf(TRGBTriple) n'est pas toujours correct ! Il n'est en fait correct que pour des Bitmaps de largeur multiple de 4, à cause de l'alignement en mémoire...

Il faudrait faire :

FillMemory(p,H*BytePerLine,Gris);

OK ? :)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 nov. 2011 à 16:33
Re,

Pour tFastBitmap2.RectangleFilling3b(color : TColor), il y a une erreur à cette ligne :

y := nlc; // indice de l'adresse de destination

Ce n'est pas la bonne ligne.
N'oublie pas que les pointeurs augmentent certes de gauche à droite sur chaque ligne, mais que les pointeurs de chaque début de ligne, eux, augmentent de bas en haut.
Donc, au deuxième tour de boucle, il faut que y=3 et non pas y=2.

Il n'est pas évident de se faire une représentation mentale du bufffer de mémoire. Surtout en pf24bit avec les décalages de fin de ligne.
Perso, je travaille souvent avec un petit croquis représentant le buffer en mémoire d'un Bitmap de 3x4 pixels... Ca aide ! ;)
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
6 nov. 2011 à 16:05
Re-bonjour,

1) remplissage monochrome avec l'algo Pattern en lui passant un Pattern 1x1 pixel :
L'algo fonctionne, résultat : 100 fois Pattern avec Texture de 1x1 sur Bmp de
750x602, mis : 672 ms

2) Remplissage avec une nuance de gris avec FillMemory() en 1 seule passe :

procedure tFastBitmap2.RectangleFillingGris(Gris : byte);
var p : pointer;
begin p:=Bmp.scanline[H-1];
FillMemory(p,W*H*SizeOf(TRGBTriple),Gris);
end;

Résultat : 100 fois RectangleFillingGris sur Bmp de 750x602, mis : 422 ms
C'est effectivement plus rapide, mais c'est gris.

Pour passer en couleur monochrome j'aimerais bien arriver à faire fonctionner tFastBitmap2.RectangleFilling3b(color : TColor) de mon message du 06/11/2011 12:26:02 car je pense qu'on devrait obtenir une vitesse, bien que moins rapide qu'avec FillMemory, un peu meilleure qu'avec Pattern sans avoir à se farcir des Pattern de 1x1 pixel.

A+.

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
6 nov. 2011 à 15:02
Bonjour,

Merci Caribensila. Il y avait un oubli dans le code de Pattern dans les lignes du style :
DispScan0 := Integer( Display.Picture.Bitmap.Scanline[0] ); //Picture : non déclaré a dit le compilo
mais en remplaçant par DispScan0 := Integer( Display.Scanline[0] );
ça a de suite marché et la vitesse est bonne :

100 fois Pattern avec Texture de 50x50 sur Bmp de 750x602, mis : 735 ms

Mais aurais tu une idée pour faire marcher ma procedure tFastBitmap2.RectangleFilling3b(color : TColor) de mon message précédent ??? car là je galère, je suppose que j'y utilise mal CopyMemory ???.

A+.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 nov. 2011 à 14:17
J'ai remis la main sur mon algo de remplissage avec texture (il était dans une application de création de tissu écossais... lol )!
Je vous le donne tout brut :

Procedure Pattern(const Pattern, Display: TBitmap);
var Line : Integer;
DispScan0 : Integer;
DispScanL : Integer;
PattScanL : Integer;
PattBperL : Integer;
DispBperL : Integer;
BytperPix : Integer;
Remainded : Integer;
CopyCount : Integer;
begin
{INITIALISATION}
DispScan0 := Integer( Display.Picture.Bitmap.Scanline[0] );
DispScanL := DispScan0;
PattScanL := Integer( Pattern.Picture.Bitmap.Scanline[0] );
DispBperL := DispScan0-Integer( Display.Picture.Bitmap.Scanline[1] );
if Pattern.Height=1 then PattBperL := 4
else PattBperL := PattScanL-Integer( Pattern.Picture.Bitmap.Scanline[1] );
BytperPix := 3;
if Pattern.PixelFormat=pf32bit then BytperPix:= 4;
Remainded := Display.Width*BytperPix;
CopyCount := Pattern.Width*BytperPix;
{ON REPRODUIT LES LIGNES DE LA TEXTURE HORIZONTALEMENT SUR LE BITMAP DE DESTINATION}
if Display.Width>Pattern.Width then begin //Si le Bitmap de destination est plus large que la texture.
for Line := 1 to Pattern.Height do begin
if Line>Display.Height then Break; //On stoppe si Display est rempli.
CopyMemory( Pointer(DispScanL), Pointer(PattScanL), CopyCount );
Dec( Remainded, CopyCount );
while CopyCount<=Remainded do begin
CopyMemory( Pointer(DispScanL+CopyCount), Pointer(DispScanL), CopyCount );
Dec( Remainded, CopyCount );
Inc( CopyCount, CopyCount );
end;
CopyMemory( Pointer(DispScanL+CopyCount), Pointer(DispScanL), Remainded); //Ajustement des derniers pixels.
Dec( PattScanL, PattBperL );
Dec( DispScanL, DispBperL );
Remainded := Display.Width*BytperPix;
CopyCount := Pattern.Width*BytperPix;
end; end
else begin //Si la texture est plus large que le Bitmap de destination.
for Line := 1 to Pattern.Height do begin
if Line>Display.Height then Break; //On stoppe si Display est rempli.
CopyMemory( Pointer(DispScanL), Pointer(PattScanL), DispBperL );
Inc( PattScanL, PattBperL );
Inc( DispScanL, DispBperL );
end;
end;
{ON REPRODUIT LA TEXTURE HORIZONTALE, VERTICALEMENT SUR LE BITMAP DE DESTINATION}
Remainded := (Display.Height-Pattern.Height)*DispBperL; //On met les compteurs à zéro.
CopyCount := (Pattern.Height)*DispBperL; // On met les compteurs à zéro.
Dec(DispScanL, CopyCount-DispBperL);
while CopyCount<=Remainded do begin
CopyMemory( Pointer(DispScanL), Pointer(Integer(DispScan0)-CopyCount+DispBperL), CopyCount );
Dec( Remainded,CopyCount );
Inc( CopyCount,CopyCount );
Dec( DispScanL,CopyCount );
end;
CopyMemory( Pointer(DispScan0-DispBperL*(Display.Height-1)),Pointer(DispScan0-Remainded+DispBperL),Remainded ); //Ajustement des derniers pixels.
end;
------------------------------------------------------------------

Je ne me souviens plus si j'avais épuisé les optimisations possibles (et de mon niveau)... Mais peut-être qu'avec l'ASM ?..

Pour un remplissage monochrome, je pense que l'algo fait le job en lui passant un Pattern 1x1 pixel, mais je n'ai pas testé.
Mais si on se contente d'un remplissage gris (entre tout blanc et tout noir inclus), le plus rapide serait peut-être d'utiliser FillMemory() en 1 seule passe.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
6 nov. 2011 à 12:26
Bonjour,

1) A Caribensila : J'ai testé ta modification de RectangleFilling3 comme suit :

procedure tFastBitmap2.RectangleFilling3a(color : TColor);
var Col : TRGBTriple; ScanYX : pRGBTriple; x,y : integer;
begin with Col do begin
rgbtBlue := GetBValue(color);
rgbtGreen := GetGValue(color);
rgbtRed := GetRValue(color);
end;
// 1ière Ligne :
ScanYX :=pRGBTriple(Scan0);
for x:=0 to pred(W) do begin
Inc(ScanYX);
ScanYX^ := Col
end;
// Lignes suivantes par re-copie de la 1ière
for y:=1 to pred(H) do CopyMemory(Bmp.ScanLine[y],Bmp.ScanLine[0],abs(MLS));
end;

Résultat : on gagne effectivement quelques cycles en descendant de 657 ms à 641 ms avec 100 fois RectangleFilling avec ScanYX : pRGBTriple et CopyMemory sur Bmp de 750x602.

J'ai aussi essayé de voir ce que l'on gagnerait en CopyMemoriant par doublement du nombre de lignes à chaque re-copie comme suit :

procedure tFastBitmap2.RectangleFilling3b(color : TColor);
var Col : TRGBTriple; ScanYX : pRGBTriple; x,y,ncop,nlc,i : integer;
sbl,size : DWord; adSrc : pointer;
begin with Col do begin
rgbtBlue := GetBValue(color);
rgbtGreen := GetGValue(color);
rgbtRed := GetRValue(color);
end;
// 1ière Ligne :
ScanYX :=pRGBTriple(Scan0);
for x:=0 to pred(W) do begin
Inc(ScanYX);
ScanYX^ := Col
end;
// Re-copies des 1ières lignes par doublement du nombre de lignes
ncop:=trunc(Ln(H)/Ln(2)); // nombre de re-copies possibles par doublement
sbl :=abs(MLS); // size d'une ligne
adSrc:=Bmp.Scanline[0];
for i:=1 to ncop do begin
nlc :=trunc(Power(2,i-1)); // nombre de lignes à re-copier
size:=nlc*sbl;
y:=nlc; // indice de l'adresse de destination
ShowMessage('nlc : '+intToStr(nlc)+' size : '+intToStr(size)+' y : '+intToStr(y));
CopyMemory(Bmp.ScanLine[y],adSrc,size);
end;
end;

... mais manque de chance le showMessage m'apprend que cela re-copie uniquement la 1ière ligne puis, au deuxième tour de boucle, provoque une EAV lors de la re-copie des 2 premières lignes. Et cela fait un bon moment que je galère pour trouver la cause de cette violation d'accès.!!!???

2) A Denis007 : passer le compilateur en mode optimisé : merci pour l'info, avec delphi-5 c'est dans Projet/Options/Compilateur : l'option était cochée d'origine.

J'ai comparé tes trois dernières versions ASM de GetPixel et c'est la première la plus rapide, c.à.d celle-ci :

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor; {Fonctionne}
var Scan : integer; {$IFOPT O-} pRGB3 : pRGBTriple; {$ENDIF}
begin Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov eax,Scan; //Obtenir l'adresse
mov ebx,[eax]; //Lire le mot dans EBX
mov eax,ebx; //Déplacer ce mot dans EAX
mov ecx,ebx; //Déplacer ce mot dans ECX
shr eax,$10; //tourner de 16 bits
and eax,$ff;
and ebx,$ff00
or ebx,eax;
shl ecx,$10;
and ecx,$ff0000;
or ebx,ecx;
end; {asm}
{$ELSE}
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
{$ENDIF}
end;

Résultats comparatifs pour 100 fois GetPixels sur Bmp de 750x602
- version 1, mis : 1515 ms soit 1,26 fois plus rapide que version 3
- version 2, mis : 1859 ms
- version 3, mis : 1906 ms

A+.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
5 nov. 2011 à 22:38
Il est très difficile d'optimiser un code pour faire mieux que le compilateur surtout en utilisant les macros de chez Microsoft-Borland.
Néanmoins merci pour les test de pseudo3, je suis arrivé au même résultat.

Ce qui me conforme un peut mais voici d'autre implémentation que j'ai écrit la nuit dernière : il faut pour cela passer le compilateur en mode optimisé (avec delphi-7) dans Project/Option/Compilateur.

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor; {Fonctionne}
var Scan : integer; {$IFOPT O-} pRGB3 : pRGBTriple; {$ENDIF}
begin Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov eax,Scan; //Obtenir l'adresse
mov ebx,[eax]; //Lire le mot dans EBX
mov eax,ebx; //Déplacer ce mot dans EAX
mov ecx,ebx; //Déplacer ce mot dans ECX
shr eax,$10; //tourner de 16 bits
and eax,$ff;
and ebx,$ff00
or ebx,eax;
shl ecx,$10;
and ecx,$ff0000;
or ebx,ecx;
end; {asm}
{$ELSE}
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
{$ENDIF}
end;

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor; {Fonctionne}
var Scan : integer; {$IFOPT O-} pRGB3 : pRGBTriple; {$ENDIF}
begin Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov eax,Scan; //Obtenir l'adresse
mov bx,[eax]; //Lire le mot dans EBX
mov cl,[eax+2];
mov al,bl;
shl eax,$10;
and ebx,$0000ff00;
add ebx,eax;
add ebx,ecx;
end; {asm}
{$ELSE}
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
{$ENDIF}
end;

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor; {Fonctionne}
var Scan : integer; {$IFOPT O-} pRGB3 : pRGBTriple; {$ENDIF}
begin Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov eax,Scan;
mov cl,[eax];
mov dl,[eax+$01];
mov al,[eax+$02];
and eax,$000000ff;
and edx,$000000ff;
shl edx,$08;
or eax,edx;
xor edx,edx;
mov dl,cl;
shl edx,$10;
or eax,edx;
mov ebx,eax;
end; {asm}
{$ELSE}
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
{$ENDIF}
end;

A Bientôt. et trout ceci pour intervertir le rouge et le vert.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
5 nov. 2011 à 16:41
@pseudo3
Un tuto d'initiation de 15 pages, c'est tout juste ce que je cherchais car je pars de zéro.
C'est très gentil de m'avoir dégoter ce lien.
Pour l'unit Delphi (NewGint) en ASM, cela m'intéresse aussi beaucoup car je m'étais jadis frotté à la bistromatique, mais sans ASM. Je ne serais donc pas complètement en Terra incognita sur le fond.
Merci beaucoup.

Pour la procedure tFastBitmap2.RectangleFilling3(), quelques idées :
Je tenterais de passer la variable ScanYX en pRGBTriple plutôt qu'en Integer, et de l'incrémenter de cette façon :
Inc(ScanYX); au lieu de: ScanYX:=Scan0 + X*BPP;
Et, au lieu de
var R,G,B : byte;
j'essaierais
var Col : TRGBTriple;
begin
with Col do begin
rgbtBlue := GetBValue(color);
rgbtGreen := GetGValue(color);
rgbtRed := GetRValue(color);
end;
Ce qui permettrait, dans la boucle, de faire :
ScanYX^ := Col
Je n'ai rien testé, mais ça permettrait peut-être de gagner quelques cycles...

Encore merci et pardon à Denis de squatter son topic. J'espère pouvoir bientôt apprécier à sa juste valeur son dernier code en assembleur. ;)
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
5 nov. 2011 à 15:12
Re-bonjour,

Vérification faite, tu peux trouver le tuto sur l'ASM de mon collègue (son pseudo est KR85 sur ce site) ici : http://www.phidels.com/php/index.php3?page=../commun/voirexemples.inc.php3&ChoixMenu=tutorial&PHPSESSID=2750503af1813848c6ad87f319323fa8

C'est un tuto d'initiation de 15 pages.

Sur le même site tu peux aussi télécharger du même auteur une unit Delphi (NewGint) en ASM qui permet de faire des calculs avec des nombres entiers stockés dans des string's donc des nombres énormes. Pour ma part je m'en suis servi pour des calculs nécessitant un nombre élevé de décimales via une unité de transformation des nombres entiers en nombres réels (un réel n'est autre qu'un entier fois 10PuissancePlusOuMoins_N ce qui revient à gérer la position de la virgule dans un nombre entier.

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
5 nov. 2011 à 14:45
Bonjour Caribensila,

Tu dis "Tout ça donne un joli petit algo bouclé, amusant à coder, et très efficace."
... je n'en doute pas, par contre pour l'instant je me contente des perfs de Brush.BitMap.

Entre-temps j'ai comparé les perfs entre les deux solutions de remplissage monochorme suivantes :

procedure tFastBitmap2.RectangleFilling2(color : TColor);
begin with Bmp.canvas do begin
brush.color:=color;
FillRect(clipRect);
end;
end;

procedure tFastBitmap2.RectangleFilling3(color : TColor);
var y,x, ScanYX : integer; R,G,B : byte;
begin R:=GetRValue(color);
G:=GetGValue(color);
B:=GetBValue(color);
// 1ière Ligne :
for x:=0 to pred(W) do begin
ScanYX:=Scan0 + X*BPP;
with pRGBTriple(ScanYX)^ do begin
rgbtRed :=R;
rgbtGreen:=G;
rgbtBlue :=B;
end;
end;
for y:=1 to pred(H) do CopyMemory(Bmp.ScanLine[y],Bmp.ScanLine[0],abs(MLS));
end;

Les vitesses sont à 5 ms près identiques.
Par flemme, dans RectangleFilling3, je me suis contenté de reproduire la première ligne, ligne par ligne, et non suivant une progression par doublement.

Assembleur. Tu dis "Mais, adepte de l'optimisation, je serais intéressé par un bon tuto sur ce sujet".

Je me souviens qu'un collègue en avait placé un sur le site de Phidels.
Je vais vérifier s'il s'y trouve encore.

A+.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
5 nov. 2011 à 14:16
Bonjour pseudo3,
« Par contre dans le cas d'une texture nuancée on risque de ne reproduire que sa première première ligne sur le BitMap, à moins de compliquer un peu le code. »

Effectivement, ça complique un peu. Cependant le principe reste le même et je crois me souvenir que c'est avec une texture qu'on réalise la meilleure amélioration des performances, même vs Windows.APIs.

Imaginons une texture 3x3 pixels :

Horizontalement:
On "CopyMemory" les 3 premiers pixels à la suite.
Puis les 6 premiers à la suite, puis les 12, etc...
Idem pour la 2ème et 3ème ligne.

Verticalement:
On "CopyMemory" les 3 premières lignes à la suite, puis les 6, puis les 12... premières lignes, etc...

Tout ça donne un joli petit algo bouclé, amusant à coder, et très efficace. :)

Malheureusement, je n'ai pas encore de compétence en assembleur. Mais, adepte de l'optimisation, je serais intéressé par un bon tuto sur ce sujet. Avis! ;)
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
5 nov. 2011 à 13:07
Re-bonjour,

Je viens de faire des tests comparatifs entre l'ancienne version de FastBitmap2 et la nouvelle qui utilise l'ASM.

Résultats :

1) Pour 100 fois GetPixels sur Bmp de 750x602
- ancienne version, mis : 1797 ms.
- version ASM, mis : 1547 ms
- d'où un gain de speed de 16%.

2) Pour 100 fois SetPixels sur Bmp de 750x602,
- ancienne version, mis : 1843 ms
- version ASM, mis : 1546 ms
- d'où un gain de speed de 19%.

3) RectangleFilling : Vraiment dommage que dans le nouveau code cette routine ne bénéficie pas de l'ASM car, en l'état actuel, pour en bénéficier, cela oblige à faire appel à SetPixel(x,y,color) dans des boucles imbriquées ce qui va secouer la pile avec les paramètres x,y et color donc avec un ralentissement.

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
5 nov. 2011 à 12:03
Bonjour Caribensila,

Tu dis "Pour remplir un bitmap avec une couleur donnée ou une texture, j'avais trouvé un algo plus rapide que les méthodes classiques, mais je n'arrive plus à mettre la main dessus dans mon dorbel ... avec CopyMemory..."
... Ok merci le principe semble intéressant pour un remplissage avec une couleur.
... Par contre dans le cas d'une texture nuancée on risque de ne reproduire que sa première première ligne sur le BitMap, à moins de compliquer un peu le code.

A+.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
5 nov. 2011 à 11:50
Bonjour 007,

En réponse à "Je serais curieux de savoir ce que donne ton test comparatif des unité u_fast_bitamp et u_fast_bitamp2 si tu retire ces tests" j'ai donc fait ce test mais cela n'a rien changé : les 100 fois For_a_rectangle_filling sur Bmp de 750x602, oscillent entre les 2400 ms et les 2500 ms.

Par contre je n'ai pas trouvé comment passer mon compilateur en mode optimlisation...(Delphi 5).
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
5 nov. 2011 à 04:37
De la sorte l'appel des fonctions GetRedvalue,GetBluevalue,GetGreenValue ne sont plus nécessaire de même Que la Macro RGB,
Tout ceci était ben trop lent et les temps d'appel des différents call a ces fonctions ne sont plus utile non plus.
J'ai fait ce code optimisé dans le but d'accélérer encore plus l'utilisation des des fonctions Get/Set Pixels.
Elles sont avérer exact et fonctionne d'ors et déjà dans la visualisation d'image miniature d'affichage d'une planche contact.
Ceci afin de fournir une fonctionnalité supplémentaire a www.denisdraw.com.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
5 nov. 2011 à 04:27
J'ai modifier le code de la version fast-bitmap pour cette fois ci utiliser le langage d'assemblage et ceci va encore plus vite (c'db)

Interface

TFastBitmap2 = object
Bmp : Graphics.tBitMap;
W,H,Scan0,MLS,BPP : integer;
procedure Init(iBmp : Graphics.tBitMap);
procedure free;
function GetPixel(X,Y : Integer) : tColor;
procedure SetPixel(x,y :integer; color : TColor);
procedure RectangleFilling(color : TColor);
end;

Implementation

{--------------------------- TFastBitmap2 -------------------------------------}
{Amélioration des fonctions Get/SET BitMap en utilisant le langage d'assemblage}

procedure TFastBitmap2.Init(iBmp : Graphics.tBitMap);
begin
Bmp:=Graphics.tBitMap.create;
Bmp.Assign(iBmp);
if Bmp.PixelFormat<>pf24bit then
Bmp.PixelFormat:=pf24bit;
Scan0:=Integer(BMP.ScanLine[0]);
MLS :=Integer(BMP.ScanLine[1]) - Scan0;
BPP := 3; // pour pf24bit
W:=Bmp.width; H:=Bmp.Height;
end;

procedure TFastBitmap2.free;
begin
Bmp.free;
end;

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor;
var Scan : integer; {$IFOPT O-} pRGB3 : pRGBTriple; {$ENDIF}
begin Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov eax,Scan; //Obtenir l'adresse
mov ebx,[eax]; //Lire le mot dans EBX
mov eax,ebx; //Déplacer ce mot dans EAX
mov ecx,ebx; //Déplacer ce mot dans ECX
shr eax,$10; //tourner de 16 bits
and eax,$ff;
and ebx,$ff00
or ebx,eax;
shl ecx,$10;
and ecx,$ff0000;
or ebx,ecx;
end; {asm}
{$ELSE}
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
{$ENDIF}
end;

procedure tFastBitmap2.SetPixel(x,y :integer; color : TColor);
var Scan : integer;
begin
Scan:=Scan0 + Y*MLS + X*BPP;
{$IFOPT O+}
asm
mov ebx,Scan;
add ebx,2;
mov eax,color;
mov [ebx],al;
dec ebx;
shr eax,$08;
mov [ebx],al;
dec ebx;
shr eax,$08;
mov [ebx],al;
end; {asm}
{$ELSE}
with pRGBTriple(Scan)^ do begin
rgbtRed :=GetRValue(color);
rgbtGreen:=GetGValue(color);
rgbtBlue :=GetBValue(color);
end;
{$ENDIF}
end;

procedure tFastBitmap2.RectangleFilling(color : TColor);
var y,x, ScanY,ScanYX : integer; R,G,B : byte;
begin R:=GetRValue(color);
G:=GetGValue(color);
B:=GetBValue(color);
for y:=0 to pred(H) do begin
ScanY:=Scan0 + Y*MLS;
for x:=0 to pred(W) do begin
ScanYX:=ScanY + X*BPP;
with pRGBTriple(ScanYX)^ do begin
rgbtRed :=R;
rgbtGreen:=G;
rgbtBlue :=B;
end;
end;
end;
end;
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
4 nov. 2011 à 21:18
Bien sur passe ton compilateur en mode optimlisation...
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
4 nov. 2011 à 21:14
Je serais curieux de savoir ce que donne ce test comparatif des unités u_fast_bitamp et u_fast_bitamp2 si tu retire ces tests :

if not ((y>=self.abitmap.height) or (x>=self.abitmap.width) or (y<0) or (x<0)) then

if (y>=self.abitmap.height) or (x>=self.abitmap.width) or (x<0) or (y<0) then
begin
get_pixel:=g_base.rgb_noir;
end

Tout en sachant que les coordonnées sont inscrites dans le rectangle de l'image.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
4 nov. 2011 à 21:11
Je serais curieux de savoir ce que donne to test comparatif des unité u_fast_bitamp et u_fast_bitamp2 si tu retire ces tests :

if not ((y>=self.abitmap.height) or (x>=self.abitmap.width) or (y<0) or (x<0)) then

if (y>=self.abitmap.height) or (x>=self.abitmap.width) or (x<0) or (y<0) then
begin
get_pixel:=g_base.rgb_noir;
end

Tout en sachabnt que les coordonnées sont inscrites dans le rectangle de l'image.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
4 nov. 2011 à 19:45
Pour vous répondre le code de g_base contient des couleur comme celle ci:

RGB_Noir = $000000;
RGB_gris_clair = $c0c0c0;
RGB_Gris = $808080;
RGB_Rouge = $0000ff;

RGB_Vert = $00ff00;
RGB_Vert_foncer = $008000;
RGB_Bleu = $ff0000;
RGB_Jaune = $00FFFF;
RGB_Blanc = $ffffff;

RGB_Bleu_fonce =$800000;
RGB_Magenta =$000080;
RGB_Cyan =$ffff00;
RGB_Jaune_clair =$80FFFF;
RGB_Jaune_tres_clair =$dfffff;
RGB_Jaune_foncer =$2eb6c0;
RGB_Magenta_clair =$000080;
RGB_Magenta_tres_clair =$4040b0;
RGB_Orange =$099cfb;
RGB_Rose =$6075f9;
RGB_Violet =$FF00FF;
RGB_Rose_Chair =$A0A0FF;
RGB_claque =$8009FA;
RGB_Orange_clair =$79e5fe;
RGB_Orange_tres_clair =$dcfaff;
RGB_rose_saumon =$C6CFFC;
RGB_bleu_tres_clair =$FFBBBB;
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
4 nov. 2011 à 17:38
Pour remplir un bitmap avec une couleur donnée ou une texture, j'avais trouvé un algo plus rapide que les méthodes classiques, mais je n'arrive plus à mettre la main dessus dans mon dorbel... :(

Mais le principe de cet algo, basé sur l'Api CopyMemory qui est la plus rapide pour remplir des blocs mémoire, est très simple :
- on remplit la 1ère ligne de façon classique (pixel by pixel).
- on copie cette 1ère ligne dans la 2ème ligne avec CopyMemory().
- on copie les 2 premières lignes dans la 3ème et 4ème de la même façon et en 1 SEULE FOIS avec CopyMemory().
- Puis les 4 premières dans les 4 suivantes, et ainsi de suite...
- Les x dernières lignes, pour finir le remplissage, étant bien sûr remplies avec les x premières lignes du Bitmap.
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
4 nov. 2011 à 14:19
Bonjour,

J'ai fait des tests de vitesse comparatifs avec le code suivant :

Voici l'unité principale :

unit uGenFastBitmap;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, U_fast_bitmap, Buttons, StdCtrls, U_fast_bitmap2;

type
TForm1 = class(TForm)
Image1: TImage;
Panel1: TPanel;
edInfo: TEdit;
bRestaurerImageOriginale: TSpeedButton;
GroupBox1: TGroupBox;
bInitFB1: TSpeedButton;
bGetPixelsFB1: TSpeedButton;
bSetPixelsFB1: TSpeedButton;
bRectFillingFB1: TSpeedButton;
GroupBox2: TGroupBox;
bInitFB2: TSpeedButton;
bGet_PixelsFB2: TSpeedButton;
bSet_PixelsFB2: TSpeedButton;
bRectFillingFB2: TSpeedButton;
procedure bInitFB1Click(Sender: TObject);
procedure bGetPixelsFB1Click(Sender: TObject);
procedure bSetPixelsFB1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure bRectFillingFB1Click(Sender: TObject);
procedure bRestaurerImageOriginaleClick(Sender: TObject);
procedure bInitFB2Click(Sender: TObject);
procedure bGet_PixelsFB2Click(Sender: TObject);
procedure bSet_PixelsFB2Click(Sender: TObject);
procedure bRectFillingFB2Click(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

var FB1 : TFastBitmap;
FB2 : tFastBitmap2;
BmpUnDo : tBitMap;
GTC : DWord;
nbTours : integer;

procedure TForm1.FormCreate(Sender: TObject);
begin BmpUnDo :=tBitMap.Create;
BmpUnDo.Assign(image1.picture.bitMap);
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin BmpUnDo.free; end;

// Avec Fast_Bitmap :

procedure TForm1.bInitFB1Click(Sender: TObject);
begin FB1 := TFastBitmap.Create(Handle);
FB1.Assign(image1.picture.bitMap);
end;

procedure TForm1.bGetPixelsFB1Click(Sender: TObject);
var cl : tColor; i,x,y : integer;
begin //cl:=FB1.get_pixel(10,10);
//showMessage(ColorToString(cl)); //< juste une vérification préalable de bon fonctionnement
edInfo.text:='';
nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do begin
for y:=0 to pred(FB1.Height) do begin
for x:=0 to pred(FB1.Width) do cl:=FB1.get_pixel(x,y);
end;
end;
edInfo.text:=intToStr(nbTours)+' fois Get_Pixels sur Bmp de '+IntToStr(FB1.Width)+'x'+IntToStr(FB1.Height)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
// 100 fois Get_Pixels sur Bmp de 750x602, mis : 1781 ms
end;

procedure TForm1.bSetPixelsFB1Click(Sender: TObject);
var cl : tColor; i,x,y : integer;
begin edInfo.text:='';
nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do begin
for y:=0 to pred(FB1.Height) do begin
for x:=0 to pred(FB1.Width) do FB1.set_pixel(x,y, clAqua);
end;
end;
image1.picture.bitMap:=FB1.abitmap;
image1.repaint;
edInfo.text:=intToStr(nbTours)+' fois Set_Pixels sur Bmp de '+IntToStr(FB1.Width)+'x'+IntToStr(FB1.Height)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
//100 fois Set_Pixels sur Bmp de 750x602, mis : 2187 ms
end;

procedure TForm1.bRectFillingFB1Click(Sender: TObject);
var i : integer;
begin nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do FB1.For_a_rectangle_filling(clYellow);
image1.picture.bitMap:=FB1.abitmap;
image1.repaint;
edInfo.text:=intToStr(nbTours)+' fois For_a_rectangle_filling sur Bmp de '+IntToStr(FB1.Width)+'x'+IntToStr(FB1.Height)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
//100 fois For_a_rectangle_filling sur Bmp de 750x602, mis : 2422 ms
end;

procedure TForm1.bRestaurerImageOriginaleClick(Sender: TObject);
begin image1.picture.bitMap:=BmpUndo;
end;

// Avec Fast_Bitmap2 :

procedure TForm1.bInitFB2Click(Sender: TObject);
begin FB2.Init(image1.picture.bitMap);
end;

procedure TForm1.bGet_PixelsFB2Click(Sender: TObject);
var cl : tColor; i,x,y : integer;
begin {cl:=FB2.GetPixel(10,10);
showMessage(ColorToString(cl)); //< juste une vérification préalable de bon fonctionnement
EXIT;}
edInfo.text:='';
nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do begin
for y:=0 to pred(FB2.H) do begin
for x:=0 to pred(FB2.W) do cl:=FB2.GetPixel(x,y);
end;
end;
edInfo.text:=intToStr(nbTours)+' fois GetPixels sur Bmp de '+IntToStr(FB2.W)+'x'+IntToStr(FB2.H)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
// 100 fois GetPixels sur Bmp de 750x602, mis : 1797 ms (contre 1781 ms)
// soit environ kif-kif
end;

procedure TForm1.bSet_PixelsFB2Click(Sender: TObject);
var cl : tColor; i,x,y : integer;
begin edInfo.text:='';
nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do begin
for y:=0 to pred(FB2.H) do begin
for x:=0 to pred(FB2.W) do FB2.SetPixel(x,y, clAqua);
end;
end;
image1.picture.bitMap:=FB2.Bmp;
image1.repaint;
edInfo.text:=intToStr(nbTours)+' fois SetPixels sur Bmp de '+IntToStr(FB2.W)+'x'+IntToStr(FB2.H)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
//100 fois SetPixels sur Bmp de 750x602, mis : 1843 ms (contre : 2187 ms)
// soit 1,18 fois plus rapide
end;

procedure TForm1.bRectFillingFB2Click(Sender: TObject);
var i : integer;
begin nbTours:=100;
GTC:=GetTickCount;
for i:=1 to nbTours do FB2.RectangleFilling(clYellow);
image1.picture.bitMap:=FB2.Bmp;
image1.repaint;
edInfo.text:=intToStr(nbTours)+' fois RectangleFilling sur Bmp de '+IntToStr(FB2.W)+'x'+IntToStr(FB2.H)+', mis : '+intToStr(GetTickCount-GTC)+' ms';
//100 fois RectangleFilling sur Bmp de 750x602, mis : 688 ms (contre 2422 ms)
// soit 3,5 fois plus rapide
end;

END.

Voici l'unité U_fast_bitmap2 inspirée du code Caribensila :

unit U_Fast_Bitmap2;

interface

uses Windows, Graphics;

type tFastBitmap2 = Object
Bmp : tBitMap;
W,H,Scan0,MLS,BPP : integer;
procedure Init(iBmp : tBitMap);
function GetPixel(X,Y : Integer) : tColor;
procedure SetPixel(x,y :integer; color : TColor);
procedure RectangleFilling(color : TColor);
end;

implementation

procedure tFastBitmap2.Init(iBmp : tBitMap);
begin Bmp:=tBitMap.create;
Bmp.Assign(iBmp);
if Bmp.PixelFormat<>pf24bit then Bmp.PixelFormat:=pf24bit;
Scan0:=Integer(BMP.ScanLine[0]);
MLS :=Integer(BMP.ScanLine[1]) - Scan0;
BPP := 3; // pour pf24bit
W:=Bmp.width; H:=Bmp.Height;
end;

function tFastBitmap2.GetPixel(X,Y : Integer) : tColor;
var Scan : integer; pRGB3 : pRGBTriple;
begin Scan:=Scan0 + Y*MLS + X*BPP;
pRGB3 := pRGBTriple(Scan);
with pRGB3^ do Result:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
end;

procedure tFastBitmap2.SetPixel(x,y :integer; color : TColor);
var Scan : integer;
begin Scan:=Scan0 + Y*MLS + X*BPP;
with pRGBTriple(Scan)^ do begin
rgbtRed :=GetRValue(color);
rgbtGreen:=GetGValue(color);
rgbtBlue :=GetBValue(color);
end;
end;

procedure tFastBitmap2.RectangleFilling(color : TColor);
var y,x, ScanY,ScanYX : integer; R,G,B : byte;
begin R:=GetRValue(color);
G:=GetGValue(color);
B:=GetBValue(color);
for y:=0 to pred(H) do begin
ScanY:=Scan0 + Y*MLS;
for x:=0 to pred(W) do begin
ScanYX:=ScanY + X*BPP;
with pRGBTriple(ScanYX)^ do begin
rgbtRed :=R;
rgbtGreen:=G;
rgbtBlue :=B;
end;
end;
end;
end;

END.

Les résultats de vitesse sont placés en commentaire dans l'unité principale :
Y'a pas photo : les vitesses comparatives s'échelonnent entre le "Kif-kif" et un 3,5 fois plus rapide dans le cas du RectangleFilling basé sur la méthode de Caribensila.

Reste à savoir si on pourrait encore gratter du speed en optimisant un truc dans U_Fast_Bitmap2.

A+.
Debiars Messages postés 285 Date d'inscription lundi 16 juin 2003 Statut Membre Dernière intervention 11 février 2018
4 nov. 2011 à 08:18
mon cher Denis alias Rigolo,
je tiens à te signaler que g_base est utilisé dans la fonction Get_pixel...
Alors...si tu ne veux pas tout nous donner, dis-le...pour qu'on passe à autre chose!
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
3 nov. 2011 à 22:23
Pour ce qui est des unité k_erreur et g_base il suffit de les supprimer g_base n'est pas utilisé et l'appel de la méthode de k_erreur doit être remplacer par votre propre message.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
3 nov. 2011 à 16:53
@Denis007
« La validité d'un pointeur d'adresse est maintenue de sa demande d'allocation à sa libération. »

Oui. Mais je ne te parle pas de l'adresse de l'objet TBitmap mais de l'adresse du buffer de mémore qui contiend le tableau de pixels.
Un objet Tbitmap peut être redimensionné, ou on peut changer son format de pixel par exemple. Autant d'opérations courantes qui changeront l'adresse de son buffer...

D'autre part, je me joins à mes deux camarades pour te demander de nous permettre de tester ton code source; car c'est bien de parler théorie, mais ce n'est pas trop le but recherché quand on poste un source.
Y'en a des qui aiment juger sur pièces... :)
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
3 nov. 2011 à 10:40
Bonjour,

Je suis entièrement d'accord avec Debiars.
On est impatients pour vérifier si ton FastBitMap est réellement plus optimisé que celui du lien du commentaire de Caribensila du 28/10/2011 16:08:00

A+.
Debiars Messages postés 285 Date d'inscription lundi 16 juin 2003 Statut Membre Dernière intervention 11 février 2018
3 nov. 2011 à 08:08
Bonjour 007,

Nous sommes deux maintenant à te réclamer les unités k_erreur et g_base...
Tu pourrais avoir l'amabilité de nous répondre. C'est pas gentil de nous snober comme ça.

A+ si tu le veux bien
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
3 nov. 2011 à 00:47
La validité d'un pointeur d'adresse est maintenue de sa demande d'allocation à sa libération.
C'est pourquoi il est nécessaire de demander son attribution dans la mémoire du gestionnaire de celle-ci.
Mais si une adresse est locale à une méthode alors sa durée de vie et celle de cette méthode.
C'est de l'informatique, en tant que développeur de denis-draw, je te confirme que l'on ne doit pas comparer
les adresses d'une instance à l'autre - mais obtenir des adresses mémoires à la demande de l'applicatif.
C'est pourquoi il est unitile de les comparer comme tu le fait mais plutôt de vérifier que ceci fonctionne dans tous les cas.
Denis
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
2 nov. 2011 à 16:40
@Denis007
« [] ne plus passer les adresses de la Scanline dans la pile comme dans la fonction que tu m'as suggéré et qui demande des opérations d'empilages successifs dans le stack segment et qui ne sont pas des variables de cette fonction mais des constantes »

Le problème est que le tampon mémoire du Bitmap n'est pas garanti comme étant cohérent et qu'il serait dangereux d'ignorer le gestionnaire de mémoire Windows.
J'ai par exemple remarqué que sous Seven les adresses mémoire changeaient beaucoup plus souvent que sous XP. En effet, sous XP, on retrouve même quasi les mêmes adresses entre les différentes instances d'une application. Sous Seven, il semble que le gestionnaire de mémoire soit beaucoup plus versatile.

Mais, en prenant quelques précautions, ça vaut sans doute le coup d'essayer d'encore améliorer les performances comme tu le suggères.
Merci de nous tenir au courant et bonne chance :)
cs_pseudo3 Messages postés 268 Date d'inscription mardi 24 juillet 2007 Statut Membre Dernière intervention 2 février 2021 1
2 nov. 2011 à 15:51
Bonjour,

Inutilisable tant qu'il manque les unités k_erreur et g_base.

A+.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
31 oct. 2011 à 20:38
Effectivement le code à s'inspirer est effectivement et certainement très bon et très rapide néanmoins la fonction GetPixel isolé dans ce code comporte de nombreux paramètres (comme l'adresse de la scanline de départ) et ces paramètres sont échangé dans le module qui les appel, il semble que cela puisse être amélioré dans une classe que j'ai commencer à écrire pour dériver la classe Tbitmap et non plus l'encapsuler, afin de ne plus passer les adresses de la Scanline dans la pile comme dans la fonction que tu m'as suggéré et qui demande des opérations d'empilages successifs dans le stack segment et qui ne sont pas des variables de cette fonction mais des constantes et que l'appel de cette fonction feras des accès à ces constantes qui seront inclus dans cette même classe. D'autre par si ces constantes sont dans cette classe, alors il seras nécessaire de les instancié une première fois pour toutes la durée de la classe voulue et ainsi optimiser et demander une et deux scanline seulement ce qui devrait être encore mieux.db.
cs_Denis007 Messages postés 22 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 7 octobre 2012
31 oct. 2011 à 19:02
Oui bien sur, néanmoins get/setdibit reçoit des packets de bits, une plage de données étendues qui sont transférée par bloc - les fonctions get/set pixels accède à un seul d'entre eux à la fois comme tu as dut le voir. L'accès à la scanline se fait dans un tableau une seule fois pour toute et c'est ce tableau qui est utilisé du lien de la propriété scanline qui est d'ailleurs utilisée autant de fois qu'il y a de ligne verticale et stockée dans un tableau a taille dynamique (le Getmem). L'intérêt est d'utiliser un pointeur sur ce tableau à accès direct plutôt que la propriété Scanline qui est gourmand en ressource quand on l'exécute, essaye de voir le code assembleur en visualisant la cpu sur le code de lecture scanline et tu comprendras. Ainsi l'exécution des fonctions get-setpixel sont très rapides.
Debiars Messages postés 285 Date d'inscription lundi 16 juin 2003 Statut Membre Dernière intervention 11 février 2018
30 oct. 2011 à 15:48
Bonjour Denis,

Y manquerait pas les unités k_erreur et g_base à ton post, des fois ???