Forum Programmation.c++ intel intrinsics

Posté par  . Licence CC By‑SA.
Étiquettes :
3
22
nov.
2014

Bonjour,

Je manipule des vecteurs 16 bits avec les intrinsics SSE et GCC, tout fonctionne bien.
Il y a cependant une manipulation que je n'arrive pas à concrétiser : ces vecteurs 16 bits sont destinés à être affichés à l'écran en tant qu'image. Il me faut donc les convertir en vecteurs 8 bits après désaturation (je désature bien mais mon type de sortie __m128i contient toujours des integers 16 bits).

Quelqu'un connaîtrait-il la bonne méthode, tout en restant dans les registres SSE ? (pour l'instant, je fais une conversion avec une boucle accélérée openmp).

Merci

Bon, il semble que sse3 me permet

__m128i _mm_shuffle_epi8 ( __m128i a, __m128i b)

me reste plus qu'à trouver le bon masque ou la macro qui va bien.

  • # Une union ?

    Posté par  . Évalué à 2.

    typedef union
    {
    __m128i trucmuche;
    std::array<unsigned char, sizeof(__m128i) / sizeof(unsigned char)> chose
    };
    • [^] # Re: Une union ?

      Posté par  . Évalué à 1. Dernière modification le 22 novembre 2014 à 19:41.

      Ca n'est pas tout à fait mon cas :

      je me retrouve avec 2 registres __m128i contenant

      __m128i{0x00, A, 0x00, B, 0x00, C .....}

      et

      __m128i{0x00, I, 0x00, J, 0x00, K .....}

      qui doivent devenir

      __m128i{A, B, C, ..... I, J, K,...}

      mais merci pour l'idée

  • # une solution

    Posté par  . Évalué à 2. Dernière modification le 22 novembre 2014 à 20:09.

    Bien, je pense pouvoir faire affaire avec :

    // macro pompée sur projet Simd (http://sourceforge.net/projects/simd/)
    #define SIMD_CHAR_AS_LONGLONG(a) (((long long)a) & 0xFF)
    #define SIMD_LL_SETR_EPI8(a, b, c, d, e, f, g, h) \
        SIMD_CHAR_AS_LONGLONG(a) | (SIMD_CHAR_AS_LONGLONG(b) << 8) | \
        (SIMD_CHAR_AS_LONGLONG(c) << 16) | (SIMD_CHAR_AS_LONGLONG(d) << 24) | \
        (SIMD_CHAR_AS_LONGLONG(e) << 32) | (SIMD_CHAR_AS_LONGLONG(f) << 40) | \
        (SIMD_CHAR_AS_LONGLONG(g) << 48) | (SIMD_CHAR_AS_LONGLONG(h) << 56)
    #define SIMD_MM_SETR_EPI8(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \
        {SIMD_LL_SETR_EPI8(a0, a1, a2, a3, a4, a5, a6, a7), SIMD_LL_SETR_EPI8(a8, a9, aa, ab, ac, ad, ae, af)}
    
    // nos 2 masques
    const __m128i FIRST_PACKET = SIMD_MM_SETR_EPI8(0xF,0xD,0xB,0x9,0x7,0x5,0x3,0x1,-1,-1,-1,-1,-1,-1,-1,-1);
    const __m128i SECOND_PACKET = SIMD_MM_SETR_EPI8(-1,-1,-1,-1,-1,-1,-1,-1,0xF,0xD,0xB,0x9,0x7,0x5,0x3,0x1);
    
    // les registre à entrelacer
    __m128i k1 = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
    __m128i k2 = _mm_set_epi8(16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31);
    
    // distribution des octets
    __m128i res1 = _mm_shuffle_epi8 (k1,  FIRST_PACKET);
    __m128i res2 = _mm_shuffle_epi8 (k2,  SECOND_PACKET);
    
    // le résultat escompté
    __m128i res = res1 + res2;
    
    out: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
    • [^] # Re: une solution

      Posté par  . Évalué à 2.

      et pour les plus assidus l'implémentation

      #define SIMD_CHAR_AS_LONGLONG(a) (((long long)a) & 0xFF)
      #define SIMD_LL_SETR_EPI8(a, b, c, d, e, f, g, h) \
          SIMD_CHAR_AS_LONGLONG(a) | (SIMD_CHAR_AS_LONGLONG(b) << 8) | \
          (SIMD_CHAR_AS_LONGLONG(c) << 16) | (SIMD_CHAR_AS_LONGLONG(d) << 24) | \
          (SIMD_CHAR_AS_LONGLONG(e) << 32) | (SIMD_CHAR_AS_LONGLONG(f) << 40) | \
          (SIMD_CHAR_AS_LONGLONG(g) << 48) | (SIMD_CHAR_AS_LONGLONG(h) << 56)
      #define SIMD_MM_SETR_EPI8(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \
      {SIMD_LL_SETR_EPI8(a0, a1, a2, a3, a4, a5, a6, a7), SIMD_LL_SETR_EPI8(a8, a9, aa, ab, ac, ad, ae, af)}
      
      const __m128i FIRST_MASK = SIMD_MM_SETR_EPI8(0x0,0x2,0x4,0x6,0x8,0xA,0xC,0xE,-1,-1,-1,-1,-1,-1,-1,-1);
      const __m128i SECOND_MASK = SIMD_MM_SETR_EPI8(-1,-1,-1,-1,-1,-1,-1,-1,0x0,0x2,0x4,0x6,0x8,0xA,0xC,0xE);
      
      struct U122U8
      {
      
          void operator()(const unsigned char* src, unsigned char* dst, int pixelsCount) const
          {
      
              const quint16 *pIn = reinterpret_cast<const quint16 *>(src);
      #pragma omp parallel for schedule(static)
              for (int i=0; i< pixelsCount; i+=16) {
                  // charge 8 pixels allignés
                  // désature en shiftant à droite
                  // réarrange les octets
                  const __m128i first = _mm_shuffle_epi8 (
                              _mm_srli_epi16(
                                  _mm_load_si128((const __m128i *)(pIn + i)), 4),
                              FIRST_MASK);
      
                  // même chose pour les 8 octets suivants
                  const __m128i second = _mm_shuffle_epi8 (
                              _mm_srli_epi16(
                                  _mm_load_si128((const __m128i *)(pIn + i + 8)), 4),
                              SECOND_MASK);
      
                  // bitwise OR
                  _mm_storeu_si128((__m128i *)(dst + i), _mm_or_si128(first, second));
              }
          }
      };
    • [^] # Re: une solution

      Posté par  . Évalué à 2.

      Qu'est-ce que c'est moche par rapport aux intrinsics Altivec. À chaque fois que je lis du code SSE, je regrette la desparition des PPC…

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.