Besoin d'aide pour optimisation en MMX

fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004 - 25 mars 2004 à 21:00
cs_dadou16 Messages postés 1 Date d'inscription lundi 26 avril 2004 Statut Membre Dernière intervention 19 mai 2004 - 19 mai 2004 à 17:44
Bonjour,

je développe un logiciel de backup de DVD appelé FairUse (http://fairuse.free.fr) en licence GPL. Je dispose de 2 algos pour le redimensionnement : un redimensionnement bilinéaire en MMX et un bicubique écrit en VC++, et donc très lent.

Je l'ai réécrit en ASM simple, mais ca n'apporte pas grand chose au niveau vitesse. J'aimerais le réécrire en MMX, mais le pb c'est qu'il y a une multiplication entre un int et un char. Du coup je ne sais pas comment faire puisque cette opération n'est pas possible en MMX ?

Merci,

fu

P.S. : si quelqu'un a envie de participer au projet et réécrivant/optimisant cette routine, ca m'intéresse bcp :)

12 réponses

Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 21:57
Ca a l'air intéressant, je vais jeter un coup d'oeil
0
fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 22:06
Les sources sont dispo sur le site. Voici les fonctions à optimiser (avec en commentaire la version assembleur). Ces fonctions sont dans Resize.cpp.

void __fastcall ResizePlane::_ResizeX(const unsigned char *src, unsigned char *dst)
{
const unsigned char *pptr;
int *filter, total;
unsigned loop0, loop1, length;
for(loop0 0, filter _filterX; loop0 != _dstDim.x; loop0++) {
pptr = src + *filter++;
length = *filter++;for(loop1 0, total 1 << 15; loop1 != length; loop1++) {
total += *pptr++ * *filter++;
}
*dst++ = _clip1[total >> 16];
}
//unsigned width;
//
//width = _dstDim.x;
//filter = _filterX;
//__asm
//{
// mov esi, dword ptr [width]
// mov edx, dword ptr [dst]
// mov ebx, dword ptr [filter]
//jloop0:
// mov eax, dword ptr [src]
// add eax, dword ptr [ebx]
// mov edi, dword ptr [ebx+4]
// add ebx, 8
// push edx
// mov edx, 8000h
//jloop1:
// movzx ecx, byte ptr [eax]
// imul ecx, dword ptr [ebx]
// add edx, ecx
// inc eax
// add ebx, 4
// dec edi
// jnz jloop1
//
// sar edx,10h
// mov ecx, dword ptr [this]
// mov eax, dword ptr [ecx+38h]
// mov cl,byte ptr [eax+edx]
// pop edx
// mov byte ptr [edx],cl
// inc edx
//
// dec esi
// jnz jloop0
//}
}

void __fastcall ResizePlane::_ResizeY(const unsigned char *src, unsigned srcStep, unsigned char *dst, unsigned dstStep)
{
const unsigned char *ptr;
int *filter, total;
unsigned loop0, loop1, length;
for(loop0 0, filter _filterY; loop0 != _dstDim.y; loop0++, dst += dstStep) {
ptr = src + *filter++ * srcStep;
length = *filter++;for(loop1 0, total 1 << 15; loop1 != length; loop1++, ptr += srcStep) {
total += *ptr * *filter++;
}
*dst = _clip1[total >> 16];
}
//unsigned height;
//
//height = _dstDim.y;
//filter = _filterY;
//__asm
//{
// mov esi, dword ptr [height]
// mov edx, dword ptr [dst]
// mov ebx, dword ptr [filter]
//jloop0:
// mov eax, dword ptr [src]
// mov ecx, dword ptr [ebx]
// imul ecx, srcStep
// add eax, ecx
// mov edi, dword ptr [ebx+4]
// add ebx, 8
// push edx
// mov edx, 8000h
//jloop1:
// movzx ecx, byte ptr [eax]
// imul ecx, dword ptr [ebx]
// add edx, ecx
// add eax, srcStep
// add ebx, 4
// dec edi
// jnz jloop1
//
// sar edx,10h
// mov ecx, dword ptr [this]
// mov eax, dword ptr [ecx+38h]
// mov cl,byte ptr [eax+edx]
// pop edx
// mov byte ptr [edx],cl
// add edx, dstStep
//
// dec esi
// jnz jloop0
//}
}
0
Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 22:10
J'ai pas dû télécharger les bonnes sources, parce que ya pas ça dans le resize.cpp que j'ai
0
fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 22:35
Oui, je sais, car je l'ai rajouté après. C'est pour ca que je t'ai redonné le code des deux fonctions ici. :)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 22:36
ok pardon, sinon tu pourrais expliquer vite fait comment marchent ces fonctions ? merci
0
fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004
26 mars 2004 à 22:58
La fonction _Filter génère un filtre de redimensionnement pour le redimensionnement horizontal, et un filtre pour le redimensionnement vertical. Ca donne deux tableaux stockés dans _ResizeX et _ResizeY. Le redimensionnement horizontal et le vertical sont faits séparément, en deux temps dans ResizePlane::Resize(), c'est la partie "original FU resizer".
Ensuite, pour chaque axe on parcourt le filtre correspondant et on calcule la valeur de chaque point. Ca c'est ce que font les fonctions que j'ai posté ci-dessus.

En regardant les sources de AviSynth je me suis rendu compte qu'il fonctionne sur le même principe, et j'ai trouvé la routine ci-dessous qui à mon avis ressemble fortement à ce qu'il faut pour FU. Mais... dans le calcul du filtre fait dans _Filter() il y a un coefficient de 65536, tandis que dans AviSynth le coefficient est de 16384 (donc 2 bits de moins) et dans le code MMX on retrouve une ligne qui je pense "compense" ca en revenant sur 16 bits, mais pour l'instant je n'arrive pas à reproduire ce comportement en C++ (ca me fausse les couleurs).

pslld mm3, 2 ; Shift up from 14 bits fraction to 16 bit fraction

Pour revenir à FU, il est intéressant de noter que bien que filter soit déclaré en int *filter, en réalité les valeurs ne dépassent jamais le coefficient 65536 (ou 16384 pour AviSynth).

Extrait de AviSynth :

for (int y=0; y<vi.height; ++y)
{
int* cur_luma = pattern_luma+2;
int* cur_chroma = pattern_chroma+2;
int x = vi.width / 2;

__asm {
mov edi, this
mov ecx, [edi].original_width
mov edx, [edi].tempY
mov ebx, [edi].tempUV
mov esi, srcp
mov eax, -1
// deinterleave current line
align 16
deintloop:
inc eax
movd mm1, [esi] ;mm1 = 0000VYUY
movq mm2, mm1
punpcklbw mm2, mm0 ;mm2 = 0V0Y0U0Y
pand mm1, mm7 ;mm1 = 00000Y0Y
movd [edx+eax*4], mm1
psrld mm2, 16 ;mm2 = 000V000U
add esi, 4
movq [ebx+eax*8], mm2
sub ecx, 2
jnz deintloop
// use this as source from now on
mov eax, cur_luma
mov ebx, cur_chroma
mov edx, dstp
align 16
xloopYUV:
mov esi, [eax] ;esi=&tempY[ofs0]
movq mm1, mm0
mov edi, [eax+4] ;edi=&tempY[ofs1]
movq mm3, mm0
mov ecx, fir_filter_size_luma
add eax, 8 ;cur_luma++
align 16
aloopY:
// Identifiers:
// Ya, Yb: Y values in srcp[ofs0]
// Ym, Yn: Y values in srcp[ofs1]
movd mm2, [esi] ;mm2 = 0| 0|Yb|Ya
add esi, 4
punpckldq mm2, [edi] ;mm2 = Yn|Ym|Yb|Ya
;[eax] = COn|COm|COb|COa
add edi, 4
pmaddwd mm2, [eax] ;mm2 = Y1|Y0 (DWORDs)
add eax, 8 ;cur_luma++
dec ecx
paddd mm1, mm2 ;accumulate
jnz aloopY

mov esi, [ebx] ;esi=&tempUV[ofs]
add ebx, 8 ;cur_chroma++
mov ecx, fir_filter_size_chroma
align 16
aloopUV:
movq mm2, [esi] ;mm2 = 0|V|0|U
;[ebx] = 0|COv|0|COu
add esi, 8
pmaddwd mm2, [ebx] ;mm2 = V|U (DWORDs)
add ebx, 8 ;cur_chroma++
dec ecx
paddd mm3, mm2 ;accumulate
jnz aloopUV

movq mm4, mm3 ; clip chroma at 0
psrad mm3, 31
pandn mm3, mm4

paddd mm1, mm6 ;Y1|Y1|Y0|Y0 (round)
paddd mm3, mm6 ; V| V| U| U (round)
pslld mm3, 2 ; Shift up from 14 bits fraction to 16 bit fraction

pand mm3, mm5 ;mm3 = v| 0|u| 0

psrld mm1, 14 ;mm1 = 0|y1|0|y0
por mm3, mm1
packuswb mm3, mm3 ;mm3 = ...|v|y1|u|y0
movd [edx], mm3
add edx, 4
dec x
jnz xloopYUV
}
srcp += src_pitch;
dstp += dst_pitch;
}
0
Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
27 mars 2004 à 11:54
Ca serait possible de faire de filter un unsigned short* plutot qu'un int* ? Ca ferait gagner une conversion de type, et si ça ne dépasse jamais 65535 ça devrait pas poser de problèmes
0
fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004
27 mars 2004 à 12:01
J'ai trouvé comment faire pour utiliser le coefficient 16384 :)

Je ne comprends pas pourquoi faire cette conversion ? De toute façon ca doit finir dans des registres MMX sous forme de WORD, non ?
0
Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
27 mars 2004 à 12:04
Ben tres exactement, donc autant que ça soit des word des le début, ça fait gagner quelques pack-ing
0
Chrishka Messages postés 21 Date d'inscription dimanche 17 août 2003 Statut Membre Dernière intervention 27 mars 2004
27 mars 2004 à 12:37
sinon ça fait quoi _clip1[total >> 16] ?
0
fairuse Messages postés 6 Date d'inscription jeudi 25 mars 2004 Statut Membre Dernière intervention 27 mars 2004
27 mars 2004 à 12:38
J'ai pas tout pigé mais je te fais confiance. ;)
La modif est faite. On traite donc maintenant des short* avec un coefficient de 16384.
0
cs_dadou16 Messages postés 1 Date d'inscription lundi 26 avril 2004 Statut Membre Dernière intervention 19 mai 2004
19 mai 2004 à 17:44
j'effectue un PFE sur le traitement d'image et j'ai besoin de quelque petit programme comme FFT ,filtrage,binarisation, seuillage..en assembleur et surtout en utilisant MMX alos au secours...
0
Rejoignez-nous