neon_convert.c 1.18 KB
Newer Older
Christoph Gerum's avatar
Christoph Gerum committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include <arm_neon.h>

#define SIZE 512

void reference_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n){
  int i;
  for (i=0; i<n; i++){
    int r = *src++; // load red
    int g = *src++; // load green
    int b = *src++; // load blue 

    // build weighted average:
    int y = (r*77)+(g*151)+(b*28);

    // undo the scale by 256 and write to memory:
    *dest++ = (y>>8);
  }
}

void neon_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n){
  int i;
  uint8x8_t rfac = vdup_n_u8 (77);
  uint8x8_t gfac = vdup_n_u8 (151);
  uint8x8_t bfac = vdup_n_u8 (28);
  n/= 8;

  for (i=0; i<n; i++) {
    uint16x8_t  temp;
    uint8x8x3_t rgb  = vld3_u8 (src);
    uint8x8_t result;

    temp = vmull_u8 (rgb.val[0],      rfac);
    temp = vmlal_u8 (temp,rgb.val[1], gfac);
    temp = vmlal_u8 (temp,rgb.val[2], bfac);

    result = vshrn_n_u16 (temp, 8);
    vst1_u8 (dest, result);
    src  += 8*3;
    dest += 8;
  }
}

uint8_t src[SIZE*SIZE*3];
uint8_t dest[SIZE*SIZE];

int main(int argc, char **argv){
  
  if(argc == 1){
     neon_convert(dest, src, SIZE*SIZE);
  }
  else if(argc == 2 && strcmp(argv[1], "-r") == 0){
     reference_convert(dest, src, SIZE*SIZE);
  }
}