EXEMPLE D'UTILISATION DE SETDIBITSTODEVICE

vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 - 19 mai 2006 à 00:35
gabuzomeuh Messages postés 53 Date d'inscription jeudi 31 juillet 2003 Statut Membre Dernière intervention 28 mars 2007 - 12 août 2007 à 19:14
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/37657-exemple-d-utilisation-de-setdibitstodevice

gabuzomeuh Messages postés 53 Date d'inscription jeudi 31 juillet 2003 Statut Membre Dernière intervention 28 mars 2007
12 août 2007 à 19:14
Bonjour,

Moi je comprends pas pourquoi define BYTEWIDTH = 4*((3*TABWIDTH+3)/4) c'est a dire (TABWIDTH*3)+3.

Pourquoi + 3 ?

Qqn peut m'expliquer ?

Merci
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
22 mai 2006 à 22:48
La dernière deja?!? C'est pas grave. C'est déja bien gentil de ta part de me consacrer ce temps. Merci bien. Bon allez. C'est la dernière mise à jour après moi aussi je passe à autre chose. Voila j'ai corriger la fonction myZeroMemory. C'est maintenant celle de BruNews. Plus grosse mais plus rapide.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 mai 2006 à 21:03
Allez une dernière:

myZeroMemory() boucle autant de tours que d'octets, pas terrible, il faut dérouler afin de faire le moins de sauts de code possible, c'est le plus pénalisant pour les perfs.

Exemple avec 8 octets (2 DWORDs) par tour:
__declspec(naked) void __fastcall bnZeroMemory(void *destination, UINT size)
{ // ECX destination, EDX size
__asm {
test edx, edx
mov eax, edx
je short zeroEXIT
and eax, 7
sub edx, eax
jz short finHUIT
parHUIT:
mov dword ptr[ecx], 0
mov dword ptr[ecx+4], 0
add ecx, 8
sub edx, 8
jnz short parHUIT
finHUIT:
test eax, eax
je short zeroEXIT
parUN:
mov byte ptr[ecx], 0
inc ecx
dec eax
jnz short parUN
zeroEXIT:
ret 0
}
}
MickCo Messages postés 16 Date d'inscription mercredi 10 novembre 2004 Statut Membre Dernière intervention 13 août 2007
22 mai 2006 à 16:21
Merci à toi BruNews.
Désolé SAKingdom, je me suis égaré quand j'ai vu qu'on parlait d'optimisation.
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
22 mai 2006 à 15:06
Bon j'ai apporté les optimisations que BruNews ma suggéré. J'ai aussi remplacé ma fonction mymemset par myZeroMemory. Elle est en assembler. Ensuite, pour MickCo:

lpBits[tmp]=bluelevel;
lpBits[tmp+1]=greenlevel;
lpBits[tmp+2]=redlevel;
tmp += 3;

Le but de cette source est en partie d'expliquer comme le calcule des positions dans le buffer s'effectue. Si je fais tmp += 3, sa reviend à expliquer une méthode pour dessiner des rectangles. Hors avec ce que j'explique et avec un peut d'imagination, on peut tout faire avec ça même du 3D.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 mai 2006 à 13:15
shift ne sera pas parallélisable avec ADD sur le même registre, que soit avant ou après.
Si on fait le tout en 1 'lea' alors no probleme.

Regarde "Agner Fog" (google), MASM32 inclut un fichier sur les optimisations.
Manuels Intel: http://brunews.free.fr/brunews/download/Intel.rar
Michael Abrash explique aussi tout cela dans ses bouquins.
MickCo Messages postés 16 Date d'inscription mercredi 10 novembre 2004 Statut Membre Dernière intervention 13 août 2007
22 mai 2006 à 12:21
C'est un vieux réflexe. Je ne peux pas m'empecher d'optimiser le code moi-même.
S'il est vrai que les optimisations de compilations sont efficaces, on ne sait pas trop ce que fait réellement chaque compilateur. De plus, pour mon boulot, j'utilise les mêmes algos sur plusieurs plateformes differentes et donc plusieurs compilateurs differents (et plus ou moins evolués selon la plateforme). Donc, à la base, mieux vaut que j'optimise au max mon code sans trop savoir ce qu'a dans le ventre chaque compilateur.

Je n'ai plus que de vague souvenir de l'assembleur, mais il me semblais qu'un shift soit fait qu'en 1 seul cycle.
Il est vrai qu'avec la puissance actuelle des PC ainsi que les optimisations des compilateurs pour PC, j'ai délaissé l'assembleur depuis près de 10 ans.

En tout cas ton info est très interressante.
Si tu as des liens parlant des optimisations, je suis prenneur.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 mai 2006 à 11:16
OUPS,
le but ici est d'indiquer au compilo de mettre un 'lea' donc pas de forcer un shift plus couteux en cycles.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 mai 2006 à 11:09
le shift est mis en place de toute div ou mul si puissance de 2 directement par tout compilo moderne, il est clair que si tel n'eut pas été le cas je l'aurais mis.
MickCo Messages postés 16 Date d'inscription mercredi 10 novembre 2004 Statut Membre Dernière intervention 13 août 2007
22 mai 2006 à 11:01
Bonjour à tous,

Sans chercher midi à 14h, ton code peut être facilement optimisé en faisant :
int y 0; int x 0;
int tmp = (TABHEIGHT-1) * bytewidth;
for (y = 0; y < TABHEIGHT; y++)
{
int tmp2 = tmp;
for (x = 0; x < TABWIDTH; x++)
{
//Écriture dans le tableau de couleurs des 3 octects de couleur (BGR)
lpBits[tmp]=bluelevel;
lpBits[tmp+1]=greenlevel;
lpBits[tmp+2]=redlevel;
tmp += 3;
}
tmp = tmp2 - bytewidth;
}

Sur mon micro, ta fonction originale mets à peu près 2ms, avec les changements que je te propose, => env 1,2 ms

au passage pour BruNews, on pourrait en plus faire :
(TABHEIGHT-y-1)*BYTEWIDTH+x+(x<<1) (ah, les vieux souvenir du DOS avec son mode 320x200)
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
21 mai 2006 à 00:54
Ah ok. Merci. Mais pour avoir un programme completement optimiser de cette façon, il faut soi: avoir beaucoup d'expérience ou avoir beacoup de temps devant soi non? Il faut vraiment penser au moindre petit detail. Évidament connaitre l'assembler ça aide beaucoup. Bon je mis remet. Merci encore.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
21 mai 2006 à 00:49
ben non, tu peux lui indiquer la marche à suivre:
tmp = (TABHEIGHT-y-1)*BYTEWIDTH+x+x*2
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
21 mai 2006 à 00:43
Bon alors tu me conseille quoi pour tmp = (TABHEIGHT-y-1)*BYTEWIDTH+3*x? Je le laisse comme ça?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
21 mai 2006 à 00:41
Je déconseille fortement de mettre un mini bout d'asm dans une fonction, ça empêche toute optimisation du compilo. Soit on la fait en entier soit rien.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
21 mai 2006 à 00:35
Ca tombe sous le sens, ceux qui ne connaissent pas l'asm ne comprendront pas, de même que ceux qui ne connaissent pas le C ne comprennent pas la version actuelle
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
21 mai 2006 à 00:27
D'accord je vais essayer de remplacer la commande C par de l'assembler. Mais ça risque pas de rendre le code illisible pour ceux qui ne connaisse pas l'ASM?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
21 mai 2006 à 00:23
mov edx,dword ptr [x]
imul edx,edx,3

C'est de la daube ce imul, au moins 12 cycles, remplacer par:
mov edx, dword ptr[x]
lea edx, [edx+edx*2]
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
20 mai 2006 à 23:48
D'accord je comprend pour les boucles, pour bytewidth mais je comprend pas de quoi tu parle quand tu dit "il faudrait vérifier comment le compilo a généré la multiplication par 3". J'ai été voir dans le listing mais j'ai rien trouvé alors j'ai lancer avec le debuggeur et ça a données ceci pour tmp = (TABHEIGHT-y-1)*BYTEWIDTH+3*x avec comme coordonné x et y 349:

mov eax,15Eh
sub eax,dword ptr [y]
lea ecx,[eax*4-4]
imul ecx,ecx,107h
mov edx,dword ptr [x]
imul edx,edx,3
add ecx,edx
mov dword ptr [tmp],ecx
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
20 mai 2006 à 22:35
for (y = 0; y < TABHEIGHT; y++)
xor ebx, ebx ;;; y = 0
lblFOR:
;;; divers codes
inc ebx
cmp ebx, TABHEIGHT
jb lblFOR

for (y = TABHEIGHT - 1; y >= 0; y--)
mov ebx, TABHEIGHT - 1
lblFOR:
;;; divers codes
dec ebx
jns lblFOR

On voit ici que boucler VERS 0 est toujours meilleur que DEPUIS 0, à transformer tant que faire se peut.

A part cela, il faudrait vérifier comment le compilo a généré la multiplication par 3 dans:
tmp = (TABHEIGHT-y-1)*bytewidth+3*x;
Si tu vois un "mul 3" alors remplacer par un "lea eax, [eax+eax*2]"

bytewidth : ne me semble pas être recalculé donc mettre en constante dans un #define, tu éviteras un accès mémoire dans les boucles pour chaque ligne vue plus haut.
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
20 mai 2006 à 22:01
Ah ouais?? Comment. C'est optimisable en restant dans le C?
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
20 mai 2006 à 21:57
C'est pourtant le code qui est dans le WM_TIMER qui mériterait d'être optimisé
Taron31 Messages postés 199 Date d'inscription vendredi 16 avril 2004 Statut Membre Dernière intervention 28 février 2008
20 mai 2006 à 21:42
Ok
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
20 mai 2006 à 21:28
Non non surtout pas sinon à koi bon poster cette source sur ce site. L'assembler c'est plutot pour les utilitaires et la fonction myWinMain car ça diminurais encore plus la taille du fichier exe.
Taron31 Messages postés 199 Date d'inscription vendredi 16 avril 2004 Statut Membre Dernière intervention 28 février 2008
20 mai 2006 à 21:26
tu penses utiliser de l'asm pour la partie du remplissage de tableau avec les couleurs ?
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
20 mai 2006 à 17:54
Bon j'ai optimiser le code en mode release. Il ne prend plus que 3.5Ko et n'utilise plus le CRT. Pas encore d'assembler. Je préfere éviter pour l'instant.
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
19 mai 2006 à 21:17
Oui c'est vrai c'est beacoup moin lourd que SetPixel.
Merci pour ReleaseDC.
Taron31 Messages postés 199 Date d'inscription vendredi 16 avril 2004 Statut Membre Dernière intervention 28 février 2008
19 mai 2006 à 19:05
C'est sympa comme effet, et ça à l'air beaucoup moins lourd que d'utiliser SetPixel...
Ps: T'oublie un ReleaseDC()

Bon code.
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
19 mai 2006 à 03:14
Ouais mais le but premier de ce code est de montrer comment utiliser le buffer mémoire pour SetDIBitsToDevice, démontrer son fonctionnement. On peut faire plus qu'un simple rectangle avec ça.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
19 mai 2006 à 01:55
Remplir des rectangles, c'est bien ce que tu fais dans ce code, non?
SAKingdom Messages postés 3212 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 16 février 2009 15
19 mai 2006 à 00:37
En effet. FillRect serais plus rapide mais c'est pour dessiner un rectangle je crois non? Avec SetDIBitsToDevice, si on sais bien l'utiliser, on peut dessiner n'importequoi.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
19 mai 2006 à 00:35
delete lpBits; -> delete[] lpBits; (c'est un tableau)

Effectivement c'est beaucoup plus rapide de faire ca que de faire des SetPixel
En général, je n'utilise SetPixel que quand il y a une ou deux pixels à changer.
Dans ton exemple, je pense que FillRect sera encore plus rapide
Rejoignez-nous