From f814169da15b8e0e8234bba2f5300338addebab7 Mon Sep 17 00:00:00 2001
From: Rong Yan <rongyan236@gmail.com>
Date: Thu, 16 Oct 2014 01:42:23 +0000
Subject: [PATCH] libswscale/ppc/swscale_altivec.c : fix hScale_altivec_real()
 yuv2planeX_16_altivec() yuv2planeX_8() for POWER LE

---
 libswscale/ppc/swscale_altivec.c | 169 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)

diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c
index 86f40ab..98249cf 100644
--- a/libswscale/ppc/swscale_altivec.c
+++ b/libswscale/ppc/swscale_altivec.c
@@ -33,6 +33,16 @@
 #if HAVE_ALTIVEC
 #define vzero vec_splat_s32(0)
 
+#if !HAVE_BIGENDIAN
+#define yuv2planeX_8(d1, d2, l1, src, x, filter) do {     \
+        vector signed int   i1  = vec_mule(filter, l1);         \
+        vector signed int   i2  = vec_mulo(filter, l1);         \
+        vector signed int   vf1 = vec_mergel(i2, i1);           \
+        vector signed int   vf2 = vec_mergeh(i2, i1);           \
+        d1 = vec_add(d1, vf1);                                  \
+        d2 = vec_add(d2, vf2);                                  \
+    } while (0)
+#else
 #define yuv2planeX_8(d1, d2, l1, src, x, perm, filter) do {     \
         vector signed short l2  = vec_ld(((x) << 1) + 16, src); \
         vector signed short ls  = vec_perm(l1, l2, perm);       \
@@ -44,11 +54,49 @@
         d2 = vec_add(d2, vf2);                                  \
         l1 = l2;                                                \
     } while (0)
+#endif
 
 static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize,
                                   const int16_t **src, uint8_t *dest,
                                   const uint8_t *dither, int offset, int x)
 {
+#if !HAVE_BIGENDIAN
+    register int i, j;
+    DECLARE_ALIGNED(16, int, val)[16];
+    vector signed int vo1, vo2, vo3, vo4;
+    vector unsigned short vs1, vs2;
+    vector unsigned char vf;
+    vector unsigned int altivec_vectorShiftInt19 =
+        vec_add(vec_splat_u32(10), vec_splat_u32(9));
+
+    for (i = 0; i < 16; i++)
+        val[i] = dither[(x + i + offset) & 7] << 12;
+
+    vo1 = vec_ld(0,  val);
+    vo2 = vec_ld(16, val);
+    vo3 = vec_ld(32, val);
+    vo4 = vec_ld(48, val);
+
+    for (j = 0; j < filterSize; j++) {
+        vector signed short l1, l2, vLumFilter = vec_vsx_ld(j << 1, filter);
+        vLumFilter = vec_splat(vLumFilter, 0); // lumFilter[j] is loaded 8 times in vLumFilter
+
+        l1  = vec_vsx_ld(x << 1, src[j]);
+        l2  = vec_vsx_ld(((x) << 1) + 16, src[j]);
+
+        yuv2planeX_8(vo1, vo2, l1, src[j], x, vLumFilter);
+        yuv2planeX_8(vo3, vo4, l2, src[j], x + 8, vLumFilter);
+    }
+
+    vo1 = vec_sra(vo1, altivec_vectorShiftInt19);
+    vo2 = vec_sra(vo2, altivec_vectorShiftInt19);
+    vo3 = vec_sra(vo3, altivec_vectorShiftInt19);
+    vo4 = vec_sra(vo4, altivec_vectorShiftInt19);
+    vs1 = vec_packsu(vo1, vo2);
+    vs2 = vec_packsu(vo3, vo4);
+    vf  = vec_packsu(vs1, vs2);
+    vec_vsx_st(vf, 0, dest);
+#else /* else of #if !HAVE_BIGENDIAN */
     register int i, j;
     DECLARE_ALIGNED(16, int, val)[16];
     vector signed int vo1, vo2, vo3, vo4;
@@ -86,6 +134,7 @@ static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize,
     vs2 = vec_packsu(vo3, vo4);
     vf  = vec_packsu(vs1, vs2);
     vec_st(vf, 0, dest);
+#endif /* end of #if !HAVE_BIGENDIAN */
 }
 
 static inline void yuv2planeX_u(const int16_t *filter, int filterSize,
@@ -122,6 +171,125 @@ static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW,
                                 const uint8_t *src, const int16_t *filter,
                                 const int32_t *filterPos, int filterSize)
 {
+#if !HAVE_BIGENDIAN
+    register int i;
+    DECLARE_ALIGNED(16, int, tempo)[4];
+    if (filterSize % 4) {
+        for (i = 0; i < dstW; i++) {
+            register int j;
+            register int srcPos = filterPos[i];
+            register int val    = 0;
+            for (j = 0; j < filterSize; j++)
+                val += ((int)src[srcPos + j]) * filter[filterSize * i + j];
+            dst[i] = FFMIN(val >> 7, (1 << 15) - 1);
+        }
+    } else
+       switch (filterSize) {
+        case 4:
+            for (i = 0; i < dstW; i++) {
+                register int srcPos = filterPos[i];
+
+                vector unsigned char src_vF = vec_vsx_ld(srcPos, src);
+                vector signed short src_v, filter_v;
+                vector signed int val_vEven, val_s;
+
+                src_v = // vec_unpackh sign-extends...
+                        (vector signed short)(vec_mergeh( src_vF, (vector unsigned char)vzero));
+                // now put our elements in the even slots
+                src_v = vec_mergeh(src_v, (vector signed short)vzero);
+                filter_v = vec_vsx_ld(i << 3, filter);
+                filter_v = vec_mergeh(filter_v, (vector signed short)vzero);
+
+                val_vEven = vec_mule(src_v, filter_v);
+                val_s     = vec_sums(val_vEven, vzero);
+                vec_vsx_st(val_s, 0, tempo);
+                dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
+            }
+        break;
+
+        case 8:
+            for (i = 0; i < dstW; i++) {
+                register int srcPos = filterPos[i];
+
+                vector unsigned char src_vF = vec_vsx_ld(srcPos, src);
+                vector signed short src_v, filter_v;
+                vector signed int val_v, val_s;
+
+                src_v = // vec_unpackh sign-extends...
+                        (vector signed short)(vec_mergeh(src_vF, (vector unsigned char)vzero));
+                filter_v = vec_vsx_ld(i << 4, filter);
+                // the 4 above is 3 (filterSize == 8) + 1 (sizeof(short) == 2)
+
+                val_v = vec_msums(src_v, filter_v, (vector signed int)vzero);
+                val_s = vec_sums(val_v, vzero);
+                vec_vsx_st(val_s, 0, tempo);
+                dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
+            }
+        break;
+
+        case 16:
+            for (i = 0; i < dstW; i++) {
+                register int srcPos = filterPos[i];
+
+                vector unsigned char src_vF = vec_vsx_ld(srcPos, src);
+
+                vector signed short src_vA = // vec_unpackh sign-extends...
+                                             (vector signed short)(vec_mergeh(src_vF, (vector unsigned char)vzero));
+                vector signed short src_vB = // vec_unpackh sign-extends...
+                                             (vector signed short)(vec_mergel(src_vF, (vector unsigned char)vzero));
+
+                vector signed short filter_v0 = vec_vsx_ld(i << 5, filter);
+                vector signed short filter_v1 = vec_vsx_ld((i << 5) + 16, filter);
+                // the 5 above are 4 (filterSize == 16) + 1 (sizeof(short) == 2)
+
+                vector signed int val_acc = vec_msums(src_vA, filter_v0, (vector signed int)vzero);
+                vector signed int val_v   = vec_msums(src_vB, filter_v1, val_acc);
+
+                vector signed int val_s = vec_sums(val_v, vzero);
+
+                vec_vsx_st(val_s, 0, tempo);
+                dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
+            }
+        break;
+
+        default:
+            for (i = 0; i < dstW; i++) {
+                register int j;
+                register int srcPos = filterPos[i];
+
+                vector signed int val_s, val_v = (vector signed int)vzero;
+
+                for (j = 0; j < filterSize - 15; j +=16) {
+                    vector unsigned char src_vF = vec_vsx_ld(srcPos + j, src);
+
+                    vector signed short src_vA = // vec_unpackh sign-extends...
+                                                 (vector signed short)(vec_mergeh(src_vF, (vector unsigned char)vzero));
+                    vector signed short src_vB = // vec_unpackh sign-extends...
+                                                 (vector signed short)(vec_mergel(src_vF, (vector unsigned char)vzero));
+                    vector signed short filter_v0  = vec_vsx_ld((i * 2 * filterSize) + (j * 2), filter);
+                    vector signed short filter_v1  = vec_vsx_ld((i * 2 * filterSize) + (j * 2) + 16, filter);
+
+                    vector signed int val_acc = vec_msums(src_vA, filter_v0, val_v);
+                    val_v = vec_msums(src_vB, filter_v1, val_acc);
+                }
+
+                if (j < filterSize - 7) {
+                    // loading src_v0 is useless, it's already done above
+                     vector unsigned char src_vF = vec_vsx_ld(srcPos + j, src);
+                    vector signed short src_v, filter_v;
+
+                    src_v = // vec_unpackh sign-extends...
+                            (vector signed short)(vec_mergeh(src_vF, (vector unsigned char)vzero));
+                    filter_v = vec_vsx_ld((i * 2 * filterSize) + (j * 2), filter);
+                    val_v = vec_msums(src_v, filter_v, val_v);
+                }
+                val_s = vec_sums(val_v, vzero);
+                vec_vsx_st(val_s, 0, tempo);
+                dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
+          }
+        }
+
+#else /* else of #if !HAVE_BIGENDIAN */
     register int i;
     DECLARE_ALIGNED(16, int, tempo)[4];
 
@@ -284,6 +452,7 @@ static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW,
                 dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
             }
         }
+#endif  /* end of #if !HAVE_BIGENDIAN */
 }
 #endif /* HAVE_ALTIVEC */
 
-- 
1.9.1

