libavcodec/ppc/pixblockdsp.c
f46bb608
 /*
  * Copyright (c) 2002 Brian Foley
  * Copyright (c) 2002 Dieter Shirley
  * Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
  *
2d5e9451
  * This file is part of FFmpeg.
f46bb608
  *
2d5e9451
  * FFmpeg is free software; you can redistribute it and/or
f46bb608
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
2d5e9451
  * FFmpeg is distributed in the hope that it will be useful,
f46bb608
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
2d5e9451
  * License along with FFmpeg; if not, write to the Free Software
f46bb608
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include "config.h"
 
 #include "libavutil/attributes.h"
 #include "libavutil/cpu.h"
 #include "libavutil/ppc/cpu.h"
 #include "libavutil/ppc/util_altivec.h"
ea7ee4b4
 
f46bb608
 #include "libavcodec/avcodec.h"
 #include "libavcodec/pixblockdsp.h"
 
 #if HAVE_ALTIVEC
 
31dea051
 #if HAVE_VSX
 static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
e07fa300
                                ptrdiff_t stride)
31dea051
 {
     int i;
     vector unsigned char perm =
         (vector unsigned char) {0x00,0x10, 0x01,0x11,0x02,0x12,0x03,0x13,\
             0x04,0x14,0x05,0x15,0x06,0x16,0x07,0x17};
     const vector unsigned char zero =
         (const vector unsigned char) vec_splat_u8(0);
 
     for (i = 0; i < 8; i++) {
         /* Read potentially unaligned pixels.
          * We're reading 16 pixels, and actually only want 8,
          * but we simply ignore the extras. */
         vector unsigned char bytes = vec_vsx_ld(0, pixels);
 
         // Convert the bytes into shorts.
         //vector signed short shorts = (vector signed short) vec_perm(zero, bytes, perm);
         vector signed short shorts = (vector signed short) vec_perm(bytes, zero, perm);
 
         // Save the data to the block, we assume the block is 16-byte aligned.
         vec_vsx_st(shorts, i * 16, (vector signed short *) block);
 
e07fa300
         pixels += stride;
31dea051
     }
 }
 #else
f46bb608
 static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
de452e50
                                ptrdiff_t stride)
f46bb608
 {
     int i;
7014b659
     const vec_u8 zero = (const vec_u8)vec_splat_u8(0);
f46bb608
 
     for (i = 0; i < 8; i++) {
3932ccc4
         vec_u8 perm = vec_lvsl(0, pixels);
f46bb608
         /* Read potentially unaligned pixels.
          * We're reading 16 pixels, and actually only want 8,
          * but we simply ignore the extras. */
7014b659
         vec_u8 pixl = vec_ld(0, pixels);
         vec_u8 pixr = vec_ld(7, pixels);
         vec_u8 bytes = vec_perm(pixl, pixr, perm);
f46bb608
 
         // Convert the bytes into shorts.
7014b659
         vec_s16 shorts = (vec_s16)vec_mergeh(zero, bytes);
f46bb608
 
         // Save the data to the block, we assume the block is 16-byte aligned.
7014b659
         vec_st(shorts, i * 16, (vec_s16 *)block);
f46bb608
 
de452e50
         pixels += stride;
f46bb608
     }
 }
 
31dea051
 #endif /* HAVE_VSX */
 
 #if HAVE_VSX
 static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
e07fa300
                                 const uint8_t *s2, ptrdiff_t stride)
31dea051
 {
   int i;
   const vector unsigned char zero =
     (const vector unsigned char) vec_splat_u8(0);
   vector signed short shorts1, shorts2;
 
   for (i = 0; i < 4; i++) {
     /* Read potentially unaligned pixels.
      * We're reading 16 pixels, and actually only want 8,
      * but we simply ignore the extras. */
     vector unsigned char bytes = vec_vsx_ld(0,  s1);
 
     // Convert the bytes into shorts.
     shorts1 = (vector signed short) vec_mergeh(bytes, zero);
 
     // Do the same for the second block of pixels.
     bytes =vec_vsx_ld(0,  s2);
 
     // Convert the bytes into shorts.
     shorts2 = (vector signed short) vec_mergeh(bytes, zero);
 
     // Do the subtraction.
     shorts1 = vec_sub(shorts1, shorts2);
 
     // Save the data to the block, we assume the block is 16-byte aligned.
     vec_vsx_st(shorts1, 0, (vector signed short *) block);
 
     s1    += stride;
     s2    += stride;
     block += 8;
 
     /* The code below is a copy of the code above...
      * This is a manual unroll. */
 
     /* Read potentially unaligned pixels.
      * We're reading 16 pixels, and actually only want 8,
      * but we simply ignore the extras. */
     bytes = vec_vsx_ld(0,  s1);
 
     // Convert the bytes into shorts.
     shorts1 = (vector signed short) vec_mergeh(bytes, zero);
 
     // Do the same for the second block of pixels.
     bytes = vec_vsx_ld(0,  s2);
 
     // Convert the bytes into shorts.
     shorts2 = (vector signed short) vec_mergeh(bytes, zero);
 
     // Do the subtraction.
     shorts1 = vec_sub(shorts1, shorts2);
 
     // Save the data to the block, we assume the block is 16-byte aligned.
     vec_vsx_st(shorts1, 0, (vector signed short *) block);
 
     s1    += stride;
     s2    += stride;
     block += 8;
   }
 }
 #else
f46bb608
 static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
de452e50
                                 const uint8_t *s2, ptrdiff_t stride)
f46bb608
 {
     int i;
3932ccc4
     vec_u8 perm;
7014b659
     const vec_u8 zero = (const vec_u8)vec_splat_u8(0);
     vec_s16 shorts1, shorts2;
f46bb608
 
     for (i = 0; i < 4; i++) {
         /* Read potentially unaligned pixels.
          * We're reading 16 pixels, and actually only want 8,
          * but we simply ignore the extras. */
3932ccc4
         perm = vec_lvsl(0, s1);
7014b659
         vec_u8 pixl  = vec_ld(0,  s1);
         vec_u8 pixr  = vec_ld(15, s1);
3932ccc4
         vec_u8 bytes = vec_perm(pixl, pixr, perm);
f46bb608
 
         // Convert the bytes into shorts.
7014b659
         shorts1 = (vec_s16)vec_mergeh(zero, bytes);
f46bb608
 
         // Do the same for the second block of pixels.
3932ccc4
         perm = vec_lvsl(0, s2);
f46bb608
         pixl  = vec_ld(0,  s2);
         pixr  = vec_ld(15, s2);
3932ccc4
         bytes = vec_perm(pixl, pixr, perm);
f46bb608
 
         // Convert the bytes into shorts.
7014b659
         shorts2 = (vec_s16)vec_mergeh(zero, bytes);
f46bb608
 
         // Do the subtraction.
         shorts1 = vec_sub(shorts1, shorts2);
 
         // Save the data to the block, we assume the block is 16-byte aligned.
7014b659
         vec_st(shorts1, 0, (vec_s16 *)block);
f46bb608
 
         s1    += stride;
         s2    += stride;
         block += 8;
 
         /* The code below is a copy of the code above...
          * This is a manual unroll. */
 
         /* Read potentially unaligned pixels.
          * We're reading 16 pixels, and actually only want 8,
          * but we simply ignore the extras. */
3932ccc4
         perm = vec_lvsl(0, s1);
f46bb608
         pixl  = vec_ld(0,  s1);
         pixr  = vec_ld(15, s1);
3932ccc4
         bytes = vec_perm(pixl, pixr, perm);
f46bb608
 
         // Convert the bytes into shorts.
7014b659
         shorts1 = (vec_s16)vec_mergeh(zero, bytes);
f46bb608
 
         // Do the same for the second block of pixels.
3932ccc4
         perm = vec_lvsl(0, s2);
f46bb608
         pixl  = vec_ld(0,  s2);
         pixr  = vec_ld(15, s2);
3932ccc4
         bytes = vec_perm(pixl, pixr, perm);
f46bb608
 
         // Convert the bytes into shorts.
7014b659
         shorts2 = (vec_s16)vec_mergeh(zero, bytes);
f46bb608
 
         // Do the subtraction.
         shorts1 = vec_sub(shorts1, shorts2);
 
         // Save the data to the block, we assume the block is 16-byte aligned.
7014b659
         vec_st(shorts1, 0, (vec_s16 *)block);
f46bb608
 
         s1    += stride;
         s2    += stride;
         block += 8;
     }
 }
 
31dea051
 #endif /* HAVE_VSX */
 
f46bb608
 #endif /* HAVE_ALTIVEC */
 
d0bf20a4
 #if HAVE_VSX
 static void get_pixels_vsx(int16_t *restrict block, const uint8_t *pixels,
de452e50
                            ptrdiff_t stride)
d0bf20a4
 {
     int i;
     for (i = 0; i < 8; i++) {
         vec_s16 shorts = vsx_ld_u8_s16(0, pixels);
 
         vec_vsx_st(shorts, i * 16, block);
 
de452e50
         pixels += stride;
d0bf20a4
     }
 }
 
 static void diff_pixels_vsx(int16_t *restrict block, const uint8_t *s1,
de452e50
                             const uint8_t *s2, ptrdiff_t stride)
d0bf20a4
 {
     int i;
     vec_s16 shorts1, shorts2;
     for (i = 0; i < 8; i++) {
         shorts1 = vsx_ld_u8_s16(0, s1);
         shorts2 = vsx_ld_u8_s16(0, s2);
 
         shorts1 = vec_sub(shorts1, shorts2);
 
         vec_vsx_st(shorts1, 0, block);
 
         s1    += stride;
         s2    += stride;
         block += 8;
     }
 }
 #endif /* HAVE_VSX */
 
f46bb608
 av_cold void ff_pixblockdsp_init_ppc(PixblockDSPContext *c,
                                      AVCodecContext *avctx,
                                      unsigned high_bit_depth)
 {
 #if HAVE_ALTIVEC
     if (!PPC_ALTIVEC(av_get_cpu_flags()))
         return;
 
     c->diff_pixels = diff_pixels_altivec;
 
     if (!high_bit_depth) {
         c->get_pixels = get_pixels_altivec;
     }
 #endif /* HAVE_ALTIVEC */
d0bf20a4
 
 #if HAVE_VSX
     if (!PPC_VSX(av_get_cpu_flags()))
         return;
 
     c->diff_pixels = diff_pixels_vsx;
 
     if (!high_bit_depth)
         c->get_pixels = get_pixels_vsx;
 #endif /* HAVE_VSX */
f46bb608
 }