(root)/
libpng-1.6.40/
powerpc/
filter_vsx_intrinsics.c
       1  /* filter_vsx_intrinsics.c - PowerPC optimised filter functions
       2   *
       3   * Copyright (c) 2018 Cosmin Truta
       4   * Copyright (c) 2017 Glenn Randers-Pehrson
       5   * Written by Vadim Barkov, 2017.
       6   *
       7   * This code is released under the libpng license.
       8   * For conditions of distribution and use, see the disclaimer
       9   * and license in png.h
      10   */
      11  
      12  #include <stdio.h>
      13  #include <stdint.h>
      14  #include "../pngpriv.h"
      15  
      16  #ifdef PNG_READ_SUPPORTED
      17  
      18  /* This code requires -maltivec and -mvsx on the command line: */
      19  #if PNG_POWERPC_VSX_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */
      20  
      21  #include <altivec.h>
      22  
      23  #if PNG_POWERPC_VSX_OPT > 0
      24  
      25  #ifndef __VSX__
      26  #  error "This code requires VSX support (POWER7 and later). Please provide -mvsx compiler flag."
      27  #endif
      28  
      29  #define vec_ld_unaligned(vec,data) vec = vec_vsx_ld(0,data)
      30  #define vec_st_unaligned(vec,data) vec_vsx_st(vec,0,data)
      31  
      32  
      33  /* Functions in this file look at most 3 pixels (a,b,c) to predict the 4th (d).
      34   * They're positioned like this:
      35   *    prev:  c b
      36   *    row:   a d
      37   * The Sub filter predicts d=a, Avg d=(a+b)/2, and Paeth predicts d to be
      38   * whichever of a, b, or c is closest to p=a+b-c.
      39   * ( this is taken from ../intel/filter_sse2_intrinsics.c )
      40   */
      41  
      42  #define vsx_declare_common_vars(row_info,row,prev_row,offset) \
      43     png_byte i;\
      44     png_bytep rp = row + offset;\
      45     png_const_bytep pp = prev_row;\
      46     size_t unaligned_top = 16 - (((size_t)rp % 16));\
      47     size_t istop;\
      48     if(unaligned_top == 16)\
      49        unaligned_top = 0;\
      50     istop = row_info->rowbytes;\
      51     if((unaligned_top < istop))\
      52        istop -= unaligned_top;\
      53     else{\
      54        unaligned_top = istop;\
      55        istop = 0;\
      56     }
      57  
      58  void png_read_filter_row_up_vsx(png_row_infop row_info, png_bytep row,
      59                                  png_const_bytep prev_row)
      60  {
      61     vector unsigned char rp_vec;
      62     vector unsigned char pp_vec;
      63     vsx_declare_common_vars(row_info,row,prev_row,0)
      64  
      65     /* Altivec operations require 16-byte aligned data
      66      * but input can be unaligned. So we calculate
      67      * unaligned part as usual.
      68      */
      69     for (i = 0; i < unaligned_top; i++)
      70     {
      71        *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
      72        rp++;
      73     }
      74  
      75     /* Using SIMD while we can */
      76     while( istop >= 16 )
      77     {
      78        rp_vec = vec_ld(0,rp);
      79        vec_ld_unaligned(pp_vec,pp);
      80  
      81        rp_vec = vec_add(rp_vec,pp_vec);
      82  
      83        vec_st(rp_vec,0,rp);
      84  
      85        pp += 16;
      86        rp += 16;
      87        istop -= 16;
      88     }
      89  
      90     if(istop > 0)
      91     {
      92        /* If byte count of row is not divisible by 16
      93         * we will process remaining part as usual
      94         */
      95        for (i = 0; i < istop; i++)
      96        {
      97           *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
      98           rp++;
      99        }
     100  }
     101  
     102  }
     103  
     104  static const vector unsigned char VSX_LEFTSHIFTED1_4 = {16,16,16,16, 0, 1, 2, 3,16,16,16,16,16,16,16,16};
     105  static const vector unsigned char VSX_LEFTSHIFTED2_4 = {16,16,16,16,16,16,16,16, 4, 5, 6, 7,16,16,16,16};
     106  static const vector unsigned char VSX_LEFTSHIFTED3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 8, 9,10,11};
     107  
     108  static const vector unsigned char VSX_LEFTSHIFTED1_3 = {16,16,16, 0, 1, 2,16,16,16,16,16,16,16,16,16,16};
     109  static const vector unsigned char VSX_LEFTSHIFTED2_3 = {16,16,16,16,16,16, 3, 4, 5,16,16,16,16,16,16,16};
     110  static const vector unsigned char VSX_LEFTSHIFTED3_3 = {16,16,16,16,16,16,16,16,16, 6, 7, 8,16,16,16,16};
     111  static const vector unsigned char VSX_LEFTSHIFTED4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 9,10,11,16};
     112  
     113  static const vector unsigned char VSX_NOT_SHIFTED1_4 = {16,16,16,16, 4, 5, 6, 7,16,16,16,16,16,16,16,16};
     114  static const vector unsigned char VSX_NOT_SHIFTED2_4 = {16,16,16,16,16,16,16,16, 8, 9,10,11,16,16,16,16};
     115  static const vector unsigned char VSX_NOT_SHIFTED3_4 = {16,16,16,16,16,16,16,16,16,16,16,16,12,13,14,15};
     116  
     117  static const vector unsigned char VSX_NOT_SHIFTED1_3 = {16,16,16, 3, 4, 5,16,16,16,16,16,16,16,16,16,16};
     118  static const vector unsigned char VSX_NOT_SHIFTED2_3 = {16,16,16,16,16,16, 6, 7, 8,16,16,16,16,16,16,16};
     119  static const vector unsigned char VSX_NOT_SHIFTED3_3 = {16,16,16,16,16,16,16,16,16, 9,10,11,16,16,16,16};
     120  static const vector unsigned char VSX_NOT_SHIFTED4_3 = {16,16,16,16,16,16,16,16,16,16,16,16,12,13,14,16};
     121  
     122  static const vector unsigned char VSX_CHAR_ZERO = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     123  #ifdef __LITTLE_ENDIAN__
     124  
     125  static const vector unsigned char VSX_CHAR_TO_SHORT1_4 = { 4,16, 5,16, 6,16, 7,16,16,16,16,16,16,16,16,16};
     126  static const vector unsigned char VSX_CHAR_TO_SHORT2_4 = { 8,16, 9,16,10,16,11,16,16,16,16,16,16,16,16,16};
     127  static const vector unsigned char VSX_CHAR_TO_SHORT3_4 = {12,16,13,16,14,16,15,16,16,16,16,16,16,16,16,16};
     128  
     129  static const vector unsigned char VSX_SHORT_TO_CHAR1_4 = {16,16,16,16, 0, 2, 4, 6,16,16,16,16,16,16,16,16};
     130  static const vector unsigned char VSX_SHORT_TO_CHAR2_4 = {16,16,16,16,16,16,16,16, 0, 2, 4, 6,16,16,16,16};
     131  static const vector unsigned char VSX_SHORT_TO_CHAR3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 0, 2, 4, 6};
     132  
     133  static const vector unsigned char VSX_CHAR_TO_SHORT1_3 = { 3,16, 4,16, 5,16,16,16,16,16,16,16,16,16,16,16};
     134  static const vector unsigned char VSX_CHAR_TO_SHORT2_3 = { 6,16, 7,16, 8,16,16,16,16,16,16,16,16,16,16,16};
     135  static const vector unsigned char VSX_CHAR_TO_SHORT3_3 = { 9,16,10,16,11,16,16,16,16,16,16,16,16,16,16,16};
     136  static const vector unsigned char VSX_CHAR_TO_SHORT4_3 = {12,16,13,16,14,16,16,16,16,16,16,16,16,16,16,16};
     137  
     138  static const vector unsigned char VSX_SHORT_TO_CHAR1_3 = {16,16,16, 0, 2, 4,16,16,16,16,16,16,16,16,16,16};
     139  static const vector unsigned char VSX_SHORT_TO_CHAR2_3 = {16,16,16,16,16,16, 0, 2, 4,16,16,16,16,16,16,16};
     140  static const vector unsigned char VSX_SHORT_TO_CHAR3_3 = {16,16,16,16,16,16,16,16,16, 0, 2, 4,16,16,16,16};
     141  static const vector unsigned char VSX_SHORT_TO_CHAR4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 0, 2, 4,16};
     142  
     143  #elif defined(__BIG_ENDIAN__)
     144  
     145  static const vector unsigned char VSX_CHAR_TO_SHORT1_4 = {16, 4,16, 5,16, 6,16, 7,16,16,16,16,16,16,16,16};
     146  static const vector unsigned char VSX_CHAR_TO_SHORT2_4 = {16, 8,16, 9,16,10,16,11,16,16,16,16,16,16,16,16};
     147  static const vector unsigned char VSX_CHAR_TO_SHORT3_4 = {16,12,16,13,16,14,16,15,16,16,16,16,16,16,16,16};
     148  
     149  static const vector unsigned char VSX_SHORT_TO_CHAR1_4 = {16,16,16,16, 1, 3, 5, 7,16,16,16,16,16,16,16,16};
     150  static const vector unsigned char VSX_SHORT_TO_CHAR2_4 = {16,16,16,16,16,16,16,16, 1, 3, 5, 7,16,16,16,16};
     151  static const vector unsigned char VSX_SHORT_TO_CHAR3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 1, 3, 5, 7};
     152  
     153  static const vector unsigned char VSX_CHAR_TO_SHORT1_3 = {16, 3,16, 4,16, 5,16,16,16,16,16,16,16,16,16,16};
     154  static const vector unsigned char VSX_CHAR_TO_SHORT2_3 = {16, 6,16, 7,16, 8,16,16,16,16,16,16,16,16,16,16};
     155  static const vector unsigned char VSX_CHAR_TO_SHORT3_3 = {16, 9,16,10,16,11,16,16,16,16,16,16,16,16,16,16};
     156  static const vector unsigned char VSX_CHAR_TO_SHORT4_3 = {16,12,16,13,16,14,16,16,16,16,16,16,16,16,16,16};
     157  
     158  static const vector unsigned char VSX_SHORT_TO_CHAR1_3 = {16,16,16, 1, 3, 5,16,16,16,16,16,16,16,16,16,16};
     159  static const vector unsigned char VSX_SHORT_TO_CHAR2_3 = {16,16,16,16,16,16, 1, 3, 5,16,16,16,16,16,16,16};
     160  static const vector unsigned char VSX_SHORT_TO_CHAR3_3 = {16,16,16,16,16,16,16,16,16, 1, 3, 5,16,16,16,16};
     161  static const vector unsigned char VSX_SHORT_TO_CHAR4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 1, 3, 5,16};
     162  
     163  #endif
     164  
     165  #define vsx_char_to_short(vec,offset,bpp) (vector unsigned short)vec_perm((vec),VSX_CHAR_ZERO,VSX_CHAR_TO_SHORT##offset##_##bpp)
     166  #define vsx_short_to_char(vec,offset,bpp) vec_perm(((vector unsigned char)(vec)),VSX_CHAR_ZERO,VSX_SHORT_TO_CHAR##offset##_##bpp)
     167  
     168  #ifdef PNG_USE_ABS
     169  #  define vsx_abs(number) abs(number)
     170  #else
     171  #  define vsx_abs(number) (number > 0) ? (number) : -(number)
     172  #endif
     173  
     174  void png_read_filter_row_sub4_vsx(png_row_infop row_info, png_bytep row,
     175                                    png_const_bytep prev_row)
     176  {
     177     png_byte bpp = 4;
     178  
     179     vector unsigned char rp_vec;
     180     vector unsigned char part_vec;
     181  
     182     vsx_declare_common_vars(row_info,row,prev_row,bpp)
     183  
     184     PNG_UNUSED(pp)
     185  
     186     /* Altivec operations require 16-byte aligned data
     187      * but input can be unaligned. So we calculate
     188      * unaligned part as usual.
     189      */
     190     for (i = 0; i < unaligned_top; i++)
     191     {
     192        *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     193        rp++;
     194     }
     195  
     196     /* Using SIMD while we can */
     197     while( istop >= 16 )
     198     {
     199        for(i=0;i < bpp ; i++)
     200        {
     201           *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     202           rp++;
     203        }
     204        rp -= bpp;
     205  
     206        rp_vec = vec_ld(0,rp);
     207        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_4);
     208        rp_vec = vec_add(rp_vec,part_vec);
     209  
     210        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_4);
     211        rp_vec = vec_add(rp_vec,part_vec);
     212  
     213        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_4);
     214        rp_vec = vec_add(rp_vec,part_vec);
     215  
     216        vec_st(rp_vec,0,rp);
     217  
     218        rp += 16;
     219        istop -= 16;
     220     }
     221  
     222     if(istop > 0)
     223        for (i = 0; i < istop % 16; i++)
     224        {
     225           *rp = (png_byte)(((int)(*rp) + (int)(*(rp - bpp))) & 0xff);
     226           rp++;
     227        }
     228  
     229  }
     230  
     231  void png_read_filter_row_sub3_vsx(png_row_infop row_info, png_bytep row,
     232                                    png_const_bytep prev_row)
     233  {
     234     png_byte bpp = 3;
     235  
     236     vector unsigned char rp_vec;
     237     vector unsigned char part_vec;
     238  
     239     vsx_declare_common_vars(row_info,row,prev_row,bpp)
     240  
     241     PNG_UNUSED(pp)
     242  
     243     /* Altivec operations require 16-byte aligned data
     244      * but input can be unaligned. So we calculate
     245      * unaligned part as usual.
     246      */
     247     for (i = 0; i < unaligned_top; i++)
     248     {
     249        *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     250        rp++;
     251     }
     252  
     253     /* Using SIMD while we can */
     254     while( istop >= 16 )
     255     {
     256        for(i=0;i < bpp ; i++)
     257        {
     258           *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     259           rp++;
     260        }
     261        rp -= bpp;
     262  
     263        rp_vec = vec_ld(0,rp);
     264        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_3);
     265        rp_vec = vec_add(rp_vec,part_vec);
     266  
     267        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_3);
     268        rp_vec = vec_add(rp_vec,part_vec);
     269  
     270        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_3);
     271        rp_vec = vec_add(rp_vec,part_vec);
     272  
     273        part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED4_3);
     274        rp_vec = vec_add(rp_vec,part_vec);
     275  
     276        vec_st(rp_vec,0,rp);
     277        rp += 15;
     278        istop -= 16;
     279  
     280        /* Since 16 % bpp = 16 % 3 = 1, last element of array must
     281         * be proceeded manually
     282         */
     283        *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     284        rp++;
     285     }
     286  
     287     if(istop > 0)
     288        for (i = 0; i < istop % 16; i++)
     289        {
     290           *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
     291           rp++;
     292        }
     293  }
     294  
     295  void png_read_filter_row_avg4_vsx(png_row_infop row_info, png_bytep row,
     296                                    png_const_bytep prev_row)
     297  {
     298     png_byte bpp = 4;
     299  
     300     vector unsigned char rp_vec;
     301     vector unsigned char pp_vec;
     302     vector unsigned char pp_part_vec;
     303     vector unsigned char rp_part_vec;
     304     vector unsigned char avg_vec;
     305  
     306     vsx_declare_common_vars(row_info,row,prev_row,bpp)
     307     rp -= bpp;
     308     if(istop >= bpp)
     309        istop -= bpp;
     310  
     311     for (i = 0; i < bpp; i++)
     312     {
     313        *rp = (png_byte)(((int)(*rp) +
     314           ((int)(*pp++) / 2 )) & 0xff);
     315  
     316        rp++;
     317     }
     318  
     319     /* Altivec operations require 16-byte aligned data
     320      * but input can be unaligned. So we calculate
     321      * unaligned part as usual.
     322      */
     323     for (i = 0; i < unaligned_top; i++)
     324     {
     325        *rp = (png_byte)(((int)(*rp) +
     326           (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     327  
     328        rp++;
     329     }
     330  
     331     /* Using SIMD while we can */
     332     while( istop >= 16 )
     333     {
     334        for(i=0;i < bpp ; i++)
     335        {
     336           *rp = (png_byte)(((int)(*rp) +
     337              (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     338  
     339           rp++;
     340        }
     341        rp -= bpp;
     342        pp -= bpp;
     343  
     344        vec_ld_unaligned(pp_vec,pp);
     345        rp_vec = vec_ld(0,rp);
     346  
     347        rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_4);
     348        pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED1_4);
     349        avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     350        avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     351        rp_vec = vec_add(rp_vec,avg_vec);
     352  
     353        rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_4);
     354        pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED2_4);
     355        avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     356        avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     357        rp_vec = vec_add(rp_vec,avg_vec);
     358  
     359        rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_4);
     360        pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED3_4);
     361        avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     362        avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     363        rp_vec = vec_add(rp_vec,avg_vec);
     364  
     365        vec_st(rp_vec,0,rp);
     366  
     367        rp += 16;
     368        pp += 16;
     369        istop -= 16;
     370     }
     371  
     372     if(istop  > 0)
     373        for (i = 0; i < istop % 16; i++)
     374        {
     375           *rp = (png_byte)(((int)(*rp) +
     376              (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     377  
     378           rp++;
     379        }
     380  }
     381  
     382  void png_read_filter_row_avg3_vsx(png_row_infop row_info, png_bytep row,
     383                                    png_const_bytep prev_row)
     384  {
     385    png_byte bpp = 3;
     386  
     387    vector unsigned char rp_vec;
     388    vector unsigned char pp_vec;
     389    vector unsigned char pp_part_vec;
     390    vector unsigned char rp_part_vec;
     391    vector unsigned char avg_vec;
     392  
     393    vsx_declare_common_vars(row_info,row,prev_row,bpp)
     394    rp -= bpp;
     395    if(istop >= bpp)
     396       istop -= bpp;
     397  
     398    for (i = 0; i < bpp; i++)
     399    {
     400       *rp = (png_byte)(((int)(*rp) +
     401          ((int)(*pp++) / 2 )) & 0xff);
     402  
     403       rp++;
     404    }
     405  
     406    /* Altivec operations require 16-byte aligned data
     407     * but input can be unaligned. So we calculate
     408     * unaligned part as usual.
     409     */
     410    for (i = 0; i < unaligned_top; i++)
     411    {
     412       *rp = (png_byte)(((int)(*rp) +
     413          (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     414  
     415       rp++;
     416    }
     417  
     418    /* Using SIMD while we can */
     419    while( istop >= 16 )
     420    {
     421       for(i=0;i < bpp ; i++)
     422       {
     423          *rp = (png_byte)(((int)(*rp) +
     424             (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     425  
     426          rp++;
     427       }
     428       rp -= bpp;
     429       pp -= bpp;
     430  
     431       vec_ld_unaligned(pp_vec,pp);
     432       rp_vec = vec_ld(0,rp);
     433  
     434       rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_3);
     435       pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED1_3);
     436       avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     437       avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     438       rp_vec = vec_add(rp_vec,avg_vec);
     439  
     440       rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_3);
     441       pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED2_3);
     442       avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     443       avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     444       rp_vec = vec_add(rp_vec,avg_vec);
     445  
     446       rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_3);
     447       pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED3_3);
     448       avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     449       avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     450       rp_vec = vec_add(rp_vec,avg_vec);
     451  
     452       rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED4_3);
     453       pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED4_3);
     454       avg_vec = vec_avg(rp_part_vec,pp_part_vec);
     455       avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1)));
     456       rp_vec = vec_add(rp_vec,avg_vec);
     457  
     458       vec_st(rp_vec,0,rp);
     459  
     460       rp += 15;
     461       pp += 15;
     462       istop -= 16;
     463  
     464       /* Since 16 % bpp = 16 % 3 = 1, last element of array must
     465        * be proceeded manually
     466        */
     467       *rp = (png_byte)(((int)(*rp) +
     468          (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     469       rp++;
     470    }
     471  
     472    if(istop  > 0)
     473       for (i = 0; i < istop % 16; i++)
     474       {
     475          *rp = (png_byte)(((int)(*rp) +
     476             (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
     477  
     478          rp++;
     479       }
     480  }
     481  
     482  /* Bytewise c ? t : e. */
     483  #define if_then_else(c,t,e) vec_sel(e,t,c)
     484  
     485  #define vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) {\
     486        c = *(pp - bpp);\
     487        a = *(rp - bpp);\
     488        b = *pp++;\
     489        p = b - c;\
     490        pc = a - c;\
     491        pa = vsx_abs(p);\
     492        pb = vsx_abs(pc);\
     493        pc = vsx_abs(p + pc);\
     494        if (pb < pa) pa = pb, a = b;\
     495        if (pc < pa) a = c;\
     496        a += *rp;\
     497        *rp++ = (png_byte)a;\
     498        }
     499  
     500  void png_read_filter_row_paeth4_vsx(png_row_infop row_info, png_bytep row,
     501     png_const_bytep prev_row)
     502  {
     503     png_byte bpp = 4;
     504  
     505     int a, b, c, pa, pb, pc, p;
     506     vector unsigned char rp_vec;
     507     vector unsigned char pp_vec;
     508     vector unsigned short a_vec,b_vec,c_vec,nearest_vec;
     509     vector signed short pa_vec,pb_vec,pc_vec,smallest_vec;
     510  
     511     vsx_declare_common_vars(row_info,row,prev_row,bpp)
     512     rp -= bpp;
     513     if(istop >= bpp)
     514        istop -= bpp;
     515  
     516     /* Process the first pixel in the row completely (this is the same as 'up'
     517      * because there is only one candidate predictor for the first row).
     518      */
     519     for(i = 0; i < bpp ; i++)
     520     {
     521        *rp = (png_byte)( *rp + *pp);
     522        rp++;
     523        pp++;
     524     }
     525  
     526     for(i = 0; i < unaligned_top ; i++)
     527     {
     528        vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     529     }
     530  
     531     while( istop >= 16)
     532     {
     533        for(i = 0; i < bpp ; i++)
     534        {
     535           vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     536        }
     537  
     538        rp -= bpp;
     539        pp -= bpp;
     540        rp_vec = vec_ld(0,rp);
     541        vec_ld_unaligned(pp_vec,pp);
     542  
     543        a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_4),1,4);
     544        b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED1_4),1,4);
     545        c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_4),1,4);
     546        pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     547        pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     548        pc_vec = vec_add(pa_vec,pb_vec);
     549        pa_vec = vec_abs(pa_vec);
     550        pb_vec = vec_abs(pb_vec);
     551        pc_vec = vec_abs(pc_vec);
     552        smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     553        nearest_vec =  if_then_else(
     554              vec_cmpeq(pa_vec,smallest_vec),
     555              a_vec,
     556              if_then_else(
     557                vec_cmpeq(pb_vec,smallest_vec),
     558                b_vec,
     559                c_vec
     560                )
     561              );
     562        rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,1,4)));
     563  
     564        a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_4),2,4);
     565        b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED2_4),2,4);
     566        c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_4),2,4);
     567        pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     568        pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     569        pc_vec = vec_add(pa_vec,pb_vec);
     570        pa_vec = vec_abs(pa_vec);
     571        pb_vec = vec_abs(pb_vec);
     572        pc_vec = vec_abs(pc_vec);
     573        smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     574        nearest_vec =  if_then_else(
     575              vec_cmpeq(pa_vec,smallest_vec),
     576              a_vec,
     577              if_then_else(
     578                vec_cmpeq(pb_vec,smallest_vec),
     579                b_vec,
     580                c_vec
     581                )
     582              );
     583        rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,2,4)));
     584  
     585        a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_4),3,4);
     586        b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED3_4),3,4);
     587        c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_4),3,4);
     588        pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     589        pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     590        pc_vec = vec_add(pa_vec,pb_vec);
     591        pa_vec = vec_abs(pa_vec);
     592        pb_vec = vec_abs(pb_vec);
     593        pc_vec = vec_abs(pc_vec);
     594        smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     595        nearest_vec =  if_then_else(
     596              vec_cmpeq(pa_vec,smallest_vec),
     597              a_vec,
     598              if_then_else(
     599                vec_cmpeq(pb_vec,smallest_vec),
     600                b_vec,
     601                c_vec
     602                )
     603              );
     604        rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,3,4)));
     605  
     606        vec_st(rp_vec,0,rp);
     607  
     608        rp += 16;
     609        pp += 16;
     610        istop -= 16;
     611     }
     612  
     613     if(istop > 0)
     614        for (i = 0; i < istop % 16; i++)
     615        {
     616           vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     617        }
     618  }
     619  
     620  void png_read_filter_row_paeth3_vsx(png_row_infop row_info, png_bytep row,
     621     png_const_bytep prev_row)
     622  {
     623    png_byte bpp = 3;
     624  
     625    int a, b, c, pa, pb, pc, p;
     626    vector unsigned char rp_vec;
     627    vector unsigned char pp_vec;
     628    vector unsigned short a_vec,b_vec,c_vec,nearest_vec;
     629    vector signed short pa_vec,pb_vec,pc_vec,smallest_vec;
     630  
     631    vsx_declare_common_vars(row_info,row,prev_row,bpp)
     632    rp -= bpp;
     633    if(istop >= bpp)
     634       istop -= bpp;
     635  
     636    /* Process the first pixel in the row completely (this is the same as 'up'
     637     * because there is only one candidate predictor for the first row).
     638     */
     639    for(i = 0; i < bpp ; i++)
     640    {
     641       *rp = (png_byte)( *rp + *pp);
     642       rp++;
     643       pp++;
     644    }
     645  
     646    for(i = 0; i < unaligned_top ; i++)
     647    {
     648       vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     649    }
     650  
     651    while( istop >= 16)
     652    {
     653       for(i = 0; i < bpp ; i++)
     654       {
     655          vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     656       }
     657  
     658       rp -= bpp;
     659       pp -= bpp;
     660       rp_vec = vec_ld(0,rp);
     661       vec_ld_unaligned(pp_vec,pp);
     662  
     663       a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_3),1,3);
     664       b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED1_3),1,3);
     665       c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_3),1,3);
     666       pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     667       pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     668       pc_vec = vec_add(pa_vec,pb_vec);
     669       pa_vec = vec_abs(pa_vec);
     670       pb_vec = vec_abs(pb_vec);
     671       pc_vec = vec_abs(pc_vec);
     672       smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     673       nearest_vec =  if_then_else(
     674             vec_cmpeq(pa_vec,smallest_vec),
     675             a_vec,
     676             if_then_else(
     677               vec_cmpeq(pb_vec,smallest_vec),
     678               b_vec,
     679               c_vec
     680               )
     681             );
     682       rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,1,3)));
     683  
     684       a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_3),2,3);
     685       b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED2_3),2,3);
     686       c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_3),2,3);
     687       pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     688       pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     689       pc_vec = vec_add(pa_vec,pb_vec);
     690       pa_vec = vec_abs(pa_vec);
     691       pb_vec = vec_abs(pb_vec);
     692       pc_vec = vec_abs(pc_vec);
     693       smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     694       nearest_vec =  if_then_else(
     695             vec_cmpeq(pa_vec,smallest_vec),
     696             a_vec,
     697             if_then_else(
     698               vec_cmpeq(pb_vec,smallest_vec),
     699               b_vec,
     700               c_vec
     701               )
     702             );
     703       rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,2,3)));
     704  
     705       a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_3),3,3);
     706       b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED3_3),3,3);
     707       c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_3),3,3);
     708       pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     709       pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     710       pc_vec = vec_add(pa_vec,pb_vec);
     711       pa_vec = vec_abs(pa_vec);
     712       pb_vec = vec_abs(pb_vec);
     713       pc_vec = vec_abs(pc_vec);
     714       smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     715       nearest_vec =  if_then_else(
     716             vec_cmpeq(pa_vec,smallest_vec),
     717             a_vec,
     718             if_then_else(
     719               vec_cmpeq(pb_vec,smallest_vec),
     720               b_vec,
     721               c_vec
     722               )
     723             );
     724       rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,3,3)));
     725  
     726       a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED4_3),4,3);
     727       b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED4_3),4,3);
     728       c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED4_3),4,3);
     729       pa_vec = (vector signed short) vec_sub(b_vec,c_vec);
     730       pb_vec = (vector signed short) vec_sub(a_vec , c_vec);
     731       pc_vec = vec_add(pa_vec,pb_vec);
     732       pa_vec = vec_abs(pa_vec);
     733       pb_vec = vec_abs(pb_vec);
     734       pc_vec = vec_abs(pc_vec);
     735       smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec));
     736       nearest_vec =  if_then_else(
     737             vec_cmpeq(pa_vec,smallest_vec),
     738             a_vec,
     739             if_then_else(
     740               vec_cmpeq(pb_vec,smallest_vec),
     741               b_vec,
     742               c_vec
     743               )
     744             );
     745       rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,4,3)));
     746  
     747       vec_st(rp_vec,0,rp);
     748  
     749       rp += 15;
     750       pp += 15;
     751       istop -= 16;
     752  
     753       /* Since 16 % bpp = 16 % 3 = 1, last element of array must
     754        * be proceeded manually
     755        */
     756       vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     757    }
     758  
     759    if(istop > 0)
     760       for (i = 0; i < istop % 16; i++)
     761       {
     762          vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp)
     763       }
     764  }
     765  
     766  #endif /* PNG_POWERPC_VSX_OPT > 0 */
     767  #endif /* PNG_POWERPC_VSX_IMPLEMENTATION == 1 (intrinsics) */
     768  #endif /* READ */