IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Permutation d'octets (24 bits big endian => little endian)


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut Permutation d'octets (24 bits big endian => little endian)
    Bonjour tout le monde.

    Tout d'abord, je tiens à préciser que je suis débutant en assembleur.

    Pour la petite histoire, j'ai une application écrite en C++ qui récupère un flux d'image provenant d'une caméra dans un filtre DirectShow qui est ensuite transformé pour être enregistré dans un fichier au format AVI.
    Cette caméra me délivre les images en RGB8, ce qui signifie que chaque pixel de l'image est codé sur 24 bits : 8bits rouge - 8bits vert - 8bits bleu. Le problème est que la caméra me fournit les octets en utilisant le format big endian et que Windows part du principe que c'est du little endian... Il se trouve que je n'ai trouvé aucun moyen de signaler à DirectShow que les données arrivent sous forme de BGR8 au lieu de RGB8 (inversion des octets rouge <=> bleu, ce qui équivaut à du BGR au lieu de RGB...).
    Il me faut donc permuter le premier octet du pixel avec le dernier.

    Donc je me suis dit que ce genre de permutation devrait être beaucoup plus performante si on la faisait en assembleur qu'en C++...
    En l'occurence, c'est du MASM, mais étant donné que je n'utilise que des fonctions très basiques, j'imagine que ça n'a pas beaucoup d'importance.


    On en arrive à ma question (ouf... ) : j'ai réussi à faire ma permutation mais je n'ai pas compris certaines choses.

    Voilà mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    BYTE* p = (BYTE*)pFrame->pBuffer;
    unsigned long nbPixels = M_nWidth * m_nHeight;
    __asm
    {
        MOV ecx, nbPixels
        loop1:
            MOV edx, p
            MOV al, [edx]
            MOV ah, [edx + 2]
            MOV [edx], ah
            MOV [edx + 2], al
            ADD p, 3
            DEC ecx
            JNZ loop1
    }
    Pourquoi je peux pas récupérer la valeur de p dans al en faisant MOV al, [p] ?

    Combien de cycle sont nécessaire pour effectuer un tour de la boucle ? (j'hésite entre 3 et 4, mais j'avoue que cette partie la de l'assembleur reste assez obscure pour moi...)

    Comment améliorer ce petit bout de code ?


    Merci d'avance !

  2. #2
    Membre chevronné
    Avatar de Forthman
    Homme Profil pro
    conception mécanique
    Inscrit en
    Janvier 2005
    Messages
    702
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : conception mécanique
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2005
    Messages : 702
    Points : 1 905
    Points
    1 905
    Par défaut
    Bonjour,

    Pour "mov al,[p]" avec un compilateur "normal" ça fonctionne (peut être avec mov al, byte ptr [p] )

    Mais quelque part ce n'est pas plus mal car comme ça tu évites de placer "[p]" partout dans ta boucle

    si j'étais toi, je placerai justement ce mov edx,p en dehors de la boucle et j'incrémenterais edx à la place
    enfin, à tester mais pas sûr que ça fasse quelque-chose : inverser deux lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MOV ah, [edx + 2]
    MOV [edx], ah
    MOV [edx + 2], al
    pour avoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MOV ah, [edx + 2]
    MOV [edx + 2], al
    MOV [edx], ah
    car le pipeline n'aime (n'aimait) pas devoir gérer deux instructions successives utilisant le même registre en écriture
    (ici ah )

    enfin, si tu as un nombre de pixels constant, tu peux dérouler un peu ta boucle.

    mais bon, ça ne va pas multiplier la vitesse par deux

  3. #3
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut
    Merci Forthman pour la réponse.


    Citation Envoyé par Forthman Voir le message
    Pour "mov al,[p]" avec un compilateur "normal" ça fonctionne (peut être avec mov al, byte ptr [p] )
    Quand j'avais essayé (effectivement mov al, byte ptr [p]), ça ne marchait pas... al contenait la valeur de l'adresse vers laquelle pointe p.


    Citation Envoyé par Forthman Voir le message
    Mais quelque part ce n'est pas plus mal car comme ça tu évites de placer "[p]" partout dans ta boucle
    Pourquoi c'est mieux d'eviter d'avoir [p] partout ? (J'avais prévenu, je suis débutant ! )


    Citation Envoyé par Forthman Voir le message
    si j'étais toi, je placerai justement ce mov edx,p en dehors de la boucle et j'incrémenterais edx à la place
    Ah oui, effectivement !
    Merci.


    Citation Envoyé par Forthman Voir le message
    enfin, à tester mais pas sûr que ça fasse quelque-chose : inverser deux lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MOV ah, [edx + 2]
    MOV [edx], ah
    MOV [edx + 2], al
    pour avoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MOV ah, [edx + 2]
    MOV [edx + 2], al
    MOV [edx], ah
    car le pipeline n'aime (n'aimait) pas devoir gérer deux instructions successives utilisant le même registre en écriture
    (ici ah )
    Je ne savais pas.
    Merci encore.


    Citation Envoyé par Forthman Voir le message
    enfin, si tu as un nombre de pixels constant, tu peux dérouler un peu ta boucle.

    mais bon, ça ne va pas multiplier la vitesse par deux
    Là, j'ai pas compris.
    Qu'est-ce que tu veux dire par "dérouler un peu ta boucle" ?

  4. #4
    Membre chevronné
    Avatar de Forthman
    Homme Profil pro
    conception mécanique
    Inscrit en
    Janvier 2005
    Messages
    702
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : conception mécanique
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2005
    Messages : 702
    Points : 1 905
    Points
    1 905
    Par défaut
    Avec un exemple ça sera plus clair :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    MOV ecx, nbPixels
    mov edx,p
    SHR ecx,1
        loop1:
            MOV al, [edx]
            MOV ah, [edx + 2]
            MOV [edx + 2], al
            MOV [edx], ah
     
            MOV al, [edx + 3]
            MOV ah, [edx + 5]
            MOV [edx + 5], al
            MOV [edx + 3], ah
     
            ADD edx, 6
            DEC ecx
            JNZ loop1
    donc si tu as un nombre pair de points, ça fonctionne en déroulant un peu la boucle
    du coup, tu divises le nombre de ADD edx,3 par deux, ainsi que le nombre de JNZ

  5. #5
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut
    Ok, je comprends maintenant.
    Mais non, ça va pas être possible, ça.
    La taille de l'image est définie auparavant par l'utilisateur (selon les capacités de la caméra), donc elle varie.
    Et puis, ce serait plutôt de l'ordre de 640*480, voire beaucoup plus...

    En tout cas, merci beaucoup pour ton aide.

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Hello à tous les deux,

    Je n'ai fait que survoler ce fil, mais je signale aussi l'existence de l'instruction BSWAP sur x86, qui permet de renverser l'endianness d'un registre 32 bits. Je ne sais pas ce que cela vaut au niveau du pipeline et ça a « l'inconvénient » de travailler sur quatre octet et non trois.

  7. #7
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut
    Salut Obsidian,

    oui, j'avais penser a BSWAP mais comme tu l'a dit toi-même, avec 24 bits, ça ne marche pas. Il faudrait que je "jongle" qvec les octets.
    Ou alors il faut me montrer comment on fait.

    Et puis j'imagine que, au final, la traduction en assembleur sera ressemblante à ce qu'on a donné ici.
    A moins qu'il y ai encore beaucoup d'optimisations possible.

    En tout cas, merci.

  8. #8
    Membre éclairé

    Homme Profil pro
    Rédacteur technique (retraité)
    Inscrit en
    Octobre 2009
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 81
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Rédacteur technique (retraité)

    Informations forums :
    Inscription : Octobre 2009
    Messages : 168
    Points : 807
    Points
    807
    Par défaut
    Bonjour, quelques suggestions:

    Citation Envoyé par Aniki
    oui, j'avais penser a BSWAP mais comme tu l'a dit toi-même, avec 24 bits, ça ne marche pas. Il faudrait que je "jongle" avec les octets.
    Un BSWAP 24 bits (permute seulement les 3 octets faibles et laisse le quatrième en place):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            ROL eax, 8
            BSWAP eax
    Optimisation: au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            MOV al, [edx]
            MOV ah, [edx + 2]
            MOV [edx + 2], al
            MOV [edx], ah
    on peut écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            MOV al, [edx]
            XCHG al, [edx+2]
            MOV [edx], al
    on gagne 1 accès mémoire et on utilise un seul registre.

    Citation Envoyé par Aniki
    Ok, je comprends maintenant.
    Mais non, ça va pas être possible, ça.
    La taille de l'image est définie auparavant par l'utilisateur (selon les capacités de la caméra), donc elle varie.
    Et puis, ce serait plutôt de l'ordre de 640*480, voire beaucoup plus...
    Si le gain de performance le justifie, pourquoi ne pas agrandir le buffer d'un pixel de remplissage à la fin pour rendre pair le compte de pixels. Quitte à supprimer ensuite ce pixel supplémentaire.

    Autre piste: à l'initialisation du buffer, remapper chaque pixel sur un DWORD 32 bits. Le buffer serait 33% plus grand mais on pourrait bénéficier du fait que tous les accès pixel correspondraient à une adresse "alignée" et le BSWAP 24 bits suggéré plus haut serait directement utilisable.

    De plus cette dernière piste ouvrirait des possibilités du coté des instructions MMX, SSE et/ou SSE2.

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Citation Envoyé par DomDA91 Voir le message
    Un BSWAP 24 bits (permute seulement les 3 octets faibles et laisse le quatrième en place):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            ROL eax, 8
            BSWAP eax
    C'est envisageable mais il faut tenir compte du coût de huit rotations qui n'est pas forcément négligeable (selon les implémentations), même par rapport à un accès bus s'il reste en cache, et surtout du fait qu'il faut aller ré-écrire ces données en mémoire pour les mettre à jour. Bon, cela dit, étant donné le nombre d'instructions données dans la solution initiale, je pense qu'on y gagne quand même largement.

    Autre piste: à l'initialisation du buffer, remapper chaque pixel sur un DWORD 32 bits. Le buffer serait 33% plus grand mais on pourrait bénéficier du fait que tous les accès pixel correspondraient à une adresse "alignée" et le BSWAP 24 bits suggéré plus haut serait directement utilisable.
    C'est à cela que je pensais également, mais ça peut être très coûteux aussi, en fonction de la source du flux vidéo. Par exemple, ça ne permet pas de mapper facilement un fichier en mémoire et ré-agencer les données en entier serait aussi cher que faire les traitement à la volée.

Discussions similaires

  1. Réponses: 3
    Dernier message: 25/11/2014, 18h57
  2. Conversion Big Endian vers Little Endian
    Par tupac25 dans le forum Langage
    Réponses: 2
    Dernier message: 13/04/2010, 16h40
  3. classe d'une table d'octets (8 bits)
    Par AurelieB dans le forum C++
    Réponses: 5
    Dernier message: 29/05/2006, 09h09
  4. Big endian et Little endian?
    Par moon93 dans le forum C
    Réponses: 4
    Dernier message: 07/05/2006, 22h48
  5. [6809] Documentation opcodes ? Big ou little endian ?
    Par krhamidou dans le forum Autres architectures
    Réponses: 2
    Dernier message: 21/01/2006, 16h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo