audio: SSE2 float-to-int converters should clamp input.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 15 May 2018 02:29:35 -0400
changeset 119912a487acdb306
parent 11990 ce0099c8d037
child 11992 08c415f14810
audio: SSE2 float-to-int converters should clamp input.

The scalar versions already do this.
src/audio/SDL_audiotypecvt.c
     1.1 --- a/src/audio/SDL_audiotypecvt.c	Tue May 15 01:40:05 2018 -0400
     1.2 +++ b/src/audio/SDL_audiotypecvt.c	Tue May 15 02:29:35 2018 -0400
     1.3 @@ -560,7 +560,14 @@
     1.4  
     1.5      /* Get dst aligned to 16 bytes */
     1.6      for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
     1.7 -        *dst = (Sint8) (*src * 127.0f);
     1.8 +        const float sample = *src;
     1.9 +        if (sample >= 1.0f) {
    1.10 +            *dst = 127;
    1.11 +        } else if (sample <= -1.0f) {
    1.12 +            *dst = -128;
    1.13 +        } else {
    1.14 +            *dst = (Sint8)(sample * 127.0f);
    1.15 +        }
    1.16      }
    1.17  
    1.18      SDL_assert(!i || ((((size_t) dst) & 15) == 0));
    1.19 @@ -568,13 +575,15 @@
    1.20      /* Make sure src is aligned too. */
    1.21      if ((((size_t) src) & 15) == 0) {
    1.22          /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
    1.23 +        const __m128 one = _mm_set1_ps(1.0f);
    1.24 +        const __m128 negone = _mm_set1_ps(-1.0f);
    1.25          const __m128 mulby127 = _mm_set1_ps(127.0f);
    1.26          __m128i *mmdst = (__m128i *) dst;
    1.27          while (i >= 16) {   /* 16 * float32 */
    1.28 -            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src), mulby127));  /* load 4 floats, convert to sint32 */
    1.29 -            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby127));  /* load 4 floats, convert to sint32 */
    1.30 -            const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+8), mulby127));  /* load 4 floats, convert to sint32 */
    1.31 -            const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+12), mulby127));  /* load 4 floats, convert to sint32 */
    1.32 +            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.33 +            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.34 +            const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+8)), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.35 +            const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+12)), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.36              _mm_store_si128(mmdst, _mm_packs_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4)));  /* pack down, store out. */
    1.37              i -= 16; src += 16; mmdst++;
    1.38          }
    1.39 @@ -583,7 +592,14 @@
    1.40  
    1.41      /* Finish off any leftovers with scalar operations. */
    1.42      while (i) {
    1.43 -        *dst = (Sint8) (*src * 127.0f);
    1.44 +        const float sample = *src;
    1.45 +        if (sample >= 1.0f) {
    1.46 +            *dst = 127;
    1.47 +        } else if (sample <= -1.0f) {
    1.48 +            *dst = -128;
    1.49 +        } else {
    1.50 +            *dst = (Sint8)(sample * 127.0f);
    1.51 +        }
    1.52          i--; src++; dst++;
    1.53      }
    1.54  
    1.55 @@ -604,7 +620,14 @@
    1.56  
    1.57      /* Get dst aligned to 16 bytes */
    1.58      for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
    1.59 -        *dst = (Uint8) ((*src + 1.0f) * 127.0f);
    1.60 +        const float sample = *src;
    1.61 +        if (sample >= 1.0f) {
    1.62 +            *dst = 255;
    1.63 +        } else if (sample <= -1.0f) {
    1.64 +            *dst = 0;
    1.65 +        } else {
    1.66 +            *dst = (Uint8)((sample + 1.0f) * 127.0f);
    1.67 +        }
    1.68      }
    1.69  
    1.70      SDL_assert(!i || ((((size_t) dst) & 15) == 0));
    1.71 @@ -612,14 +635,15 @@
    1.72      /* Make sure src is aligned too. */
    1.73      if ((((size_t) src) & 15) == 0) {
    1.74          /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
    1.75 -        const __m128 add1 = _mm_set1_ps(1.0f);
    1.76 +        const __m128 one = _mm_set1_ps(1.0f);
    1.77 +        const __m128 negone = _mm_set1_ps(-1.0f);
    1.78          const __m128 mulby127 = _mm_set1_ps(127.0f);
    1.79          __m128i *mmdst = (__m128i *) dst;
    1.80          while (i >= 16) {   /* 16 * float32 */
    1.81 -            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src), add1), mulby127));  /* load 4 floats, convert to sint32 */
    1.82 -            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+4), add1), mulby127));  /* load 4 floats, convert to sint32 */
    1.83 -            const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+8), add1), mulby127));  /* load 4 floats, convert to sint32 */
    1.84 -            const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+12), add1), mulby127));  /* load 4 floats, convert to sint32 */
    1.85 +            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.86 +            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.87 +            const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+8)), one), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.88 +            const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+12)), one), one), mulby127));  /* load 4 floats, clamp, convert to sint32 */
    1.89              _mm_store_si128(mmdst, _mm_packus_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4)));  /* pack down, store out. */
    1.90              i -= 16; src += 16; mmdst++;
    1.91          }
    1.92 @@ -628,7 +652,14 @@
    1.93  
    1.94      /* Finish off any leftovers with scalar operations. */
    1.95      while (i) {
    1.96 -        *dst = (Uint8) ((*src + 1.0f) * 127.0f);
    1.97 +        const float sample = *src;
    1.98 +        if (sample >= 1.0f) {
    1.99 +            *dst = 255;
   1.100 +        } else if (sample <= -1.0f) {
   1.101 +            *dst = 0;
   1.102 +        } else {
   1.103 +            *dst = (Uint8)((sample + 1.0f) * 127.0f);
   1.104 +        }
   1.105          i--; src++; dst++;
   1.106      }
   1.107  
   1.108 @@ -649,7 +680,14 @@
   1.109  
   1.110      /* Get dst aligned to 16 bytes */
   1.111      for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
   1.112 -        *dst = (Sint16) (*src * 32767.0f);
   1.113 +        const float sample = *src;
   1.114 +        if (sample >= 1.0f) {
   1.115 +            *dst = 32767;
   1.116 +        } else if (sample <= -1.0f) {
   1.117 +            *dst = -32768;
   1.118 +        } else {
   1.119 +            *dst = (Sint16)(sample * 32767.0f);
   1.120 +        }
   1.121      }
   1.122  
   1.123      SDL_assert(!i || ((((size_t) dst) & 15) == 0));
   1.124 @@ -657,11 +695,13 @@
   1.125      /* Make sure src is aligned too. */
   1.126      if ((((size_t) src) & 15) == 0) {
   1.127          /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
   1.128 +        const __m128 one = _mm_set1_ps(1.0f);
   1.129 +        const __m128 negone = _mm_set1_ps(-1.0f);
   1.130          const __m128 mulby32767 = _mm_set1_ps(32767.0f);
   1.131          __m128i *mmdst = (__m128i *) dst;
   1.132          while (i >= 8) {   /* 8 * float32 */
   1.133 -            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src), mulby32767));  /* load 4 floats, convert to sint32 */
   1.134 -            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby32767));  /* load 4 floats, convert to sint32 */
   1.135 +            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby32767));  /* load 4 floats, clamp, convert to sint32 */
   1.136 +            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby32767));  /* load 4 floats, clamp, convert to sint32 */
   1.137              _mm_store_si128(mmdst, _mm_packs_epi32(ints1, ints2));  /* pack to sint16, store out. */
   1.138              i -= 8; src += 8; mmdst++;
   1.139          }
   1.140 @@ -670,7 +710,14 @@
   1.141  
   1.142      /* Finish off any leftovers with scalar operations. */
   1.143      while (i) {
   1.144 -        *dst = (Sint16) (*src * 32767.0f);
   1.145 +        const float sample = *src;
   1.146 +        if (sample >= 1.0f) {
   1.147 +            *dst = 32767;
   1.148 +        } else if (sample <= -1.0f) {
   1.149 +            *dst = -32768;
   1.150 +        } else {
   1.151 +            *dst = (Sint16)(sample * 32767.0f);
   1.152 +        }
   1.153          i--; src++; dst++;
   1.154      }
   1.155  
   1.156 @@ -691,7 +738,14 @@
   1.157  
   1.158      /* Get dst aligned to 16 bytes */
   1.159      for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
   1.160 -        *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
   1.161 +        const float sample = *src;
   1.162 +        if (sample >= 1.0f) {
   1.163 +            *dst = 65535;
   1.164 +        } else if (sample <= -1.0f) {
   1.165 +            *dst = 0;
   1.166 +        } else {
   1.167 +            *dst = (Uint16)((sample + 1.0f) * 32767.0f);
   1.168 +        }
   1.169      }
   1.170  
   1.171      SDL_assert(!i || ((((size_t) dst) & 15) == 0));
   1.172 @@ -708,10 +762,12 @@
   1.173             though it looks like dark magic. */
   1.174          const __m128 mulby32767 = _mm_set1_ps(32767.0f);
   1.175          const __m128i topbit = _mm_set1_epi16(-32768);
   1.176 +        const __m128 one = _mm_set1_ps(1.0f);
   1.177 +        const __m128 negone = _mm_set1_ps(-1.0f);
   1.178          __m128i *mmdst = (__m128i *) dst;
   1.179          while (i >= 8) {   /* 8 * float32 */
   1.180 -            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src), mulby32767));  /* load 4 floats, convert to sint32 */
   1.181 -            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby32767));  /* load 4 floats, convert to sint32 */
   1.182 +            const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby32767));  /* load 4 floats, clamp, convert to sint32 */
   1.183 +            const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby32767));  /* load 4 floats, clamp, convert to sint32 */
   1.184              _mm_store_si128(mmdst, _mm_xor_si128(_mm_packs_epi32(ints1, ints2), topbit));  /* pack to sint16, xor top bit, store out. */
   1.185              i -= 8; src += 8; mmdst++;
   1.186          }
   1.187 @@ -720,7 +776,14 @@
   1.188  
   1.189      /* Finish off any leftovers with scalar operations. */
   1.190      while (i) {
   1.191 -        *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
   1.192 +        const float sample = *src;
   1.193 +        if (sample >= 1.0f) {
   1.194 +            *dst = 65535;
   1.195 +        } else if (sample <= -1.0f) {
   1.196 +            *dst = 0;
   1.197 +        } else {
   1.198 +            *dst = (Uint16)((sample + 1.0f) * 32767.0f);
   1.199 +        }
   1.200          i--; src++; dst++;
   1.201      }
   1.202  
   1.203 @@ -741,7 +804,14 @@
   1.204  
   1.205      /* Get dst aligned to 16 bytes */
   1.206      for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
   1.207 -        *dst = ((Sint32)(*src * 8388607.0f)) << 8;
   1.208 +        const float sample = *src;
   1.209 +        if (sample >= 1.0f) {
   1.210 +            *dst = 2147483647;
   1.211 +        } else if (sample <= -1.0f) {
   1.212 +            *dst = -2147483648;
   1.213 +        } else {
   1.214 +            *dst = ((Sint32)(sample * 8388607.0f)) << 8;
   1.215 +        }
   1.216      }
   1.217  
   1.218      SDL_assert(!i || ((((size_t) dst) & 15) == 0));
   1.219 @@ -749,10 +819,12 @@
   1.220  
   1.221      {
   1.222          /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
   1.223 +        const __m128 one = _mm_set1_ps(1.0f);
   1.224 +        const __m128 negone = _mm_set1_ps(-1.0f);
   1.225          const __m128 mulby8388607 = _mm_set1_ps(8388607.0f);
   1.226          __m128i *mmdst = (__m128i *) dst;
   1.227          while (i >= 4) {   /* 4 * float32 */
   1.228 -            _mm_store_si128(mmdst, _mm_slli_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src), mulby8388607)), 8));
   1.229 +            _mm_store_si128(mmdst, _mm_slli_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby8388607)), 8));  /* load 4 floats, clamp, convert to sint32 */
   1.230              i -= 4; src += 4; mmdst++;
   1.231          }
   1.232          dst = (Sint32 *) mmdst;
   1.233 @@ -760,7 +832,14 @@
   1.234  
   1.235      /* Finish off any leftovers with scalar operations. */
   1.236      while (i) {
   1.237 -        *dst = ((Sint32)(*src * 8388607.0f)) << 8;
   1.238 +        const float sample = *src;
   1.239 +        if (sample >= 1.0f) {
   1.240 +            *dst = 2147483647;
   1.241 +        } else if (sample <= -1.0f) {
   1.242 +            *dst = -2147483648;
   1.243 +        } else {
   1.244 +            *dst = ((Sint32)(sample * 8388607.0f)) << 8;
   1.245 +        }
   1.246          i--; src++; dst++;
   1.247      }
   1.248