c16b83ba79b55fb7d2b7eeb96c27a2dce977fec5
[platform/upstream/libjpeg-turbo.git] / simd / jsimd_arm.c
1 /*
2  * jsimd_arm.c
3  *
4  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
5  * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
6  * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander.
7  * Copyright (C) 2015-2016, Matthieu Darbois.
8  *
9  * Based on the x86 SIMD extension for IJG JPEG library,
10  * Copyright (C) 1999-2006, MIYASAKA Masaru.
11  * For conditions of distribution and use, see copyright notice in jsimdext.inc
12  *
13  * This file contains the interface between the "normal" portions
14  * of the library and the SIMD implementations when running on a
15  * 32-bit ARM architecture.
16  */
17
18 #define JPEG_INTERNALS
19 #include "../jinclude.h"
20 #include "../jpeglib.h"
21 #include "../jsimd.h"
22 #include "../jdct.h"
23 #include "../jsimddct.h"
24 #include "jsimd.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #if _USE_PRODUCT_TV
31 //Changes for JPEG GAMMA enhancement in thumbnail
32 #include <unistd.h>
33 #endif
34
35 static unsigned int simd_support = ~0;
36 static unsigned int simd_huffman = 1;
37
38 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
39
40 #define SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT (1024 * 1024)
41
42 LOCAL(int)
43 check_feature (char *buffer, char *feature)
44 {
45   char *p;
46   if (*feature == 0)
47     return 0;
48   if (strncmp(buffer, "Features", 8) != 0)
49     return 0;
50   buffer += 8;
51   while (isspace(*buffer))
52     buffer++;
53
54   /* Check if 'feature' is present in the buffer as a separate word */
55   while ((p = strstr(buffer, feature))) {
56     if (p > buffer && !isspace(*(p - 1))) {
57       buffer++;
58       continue;
59     }
60     p += strlen(feature);
61     if (*p != 0 && !isspace(*p)) {
62       buffer++;
63       continue;
64     }
65     return 1;
66   }
67   return 0;
68 }
69
70 LOCAL(int)
71 parse_proc_cpuinfo (int bufsize)
72 {
73   char *buffer = (char *)malloc(bufsize);
74   FILE *fd;
75   simd_support = 0;
76
77   if (!buffer)
78     return 0;
79
80   fd = fopen("/proc/cpuinfo", "r");
81   if (fd) {
82     while (fgets(buffer, bufsize, fd)) {
83       if (!strchr(buffer, '\n') && !feof(fd)) {
84         /* "impossible" happened - insufficient size of the buffer! */
85         fclose(fd);
86         free(buffer);
87         return 0;
88       }
89       if (check_feature(buffer, "neon"))
90         simd_support |= JSIMD_ARM_NEON;
91     }
92     fclose(fd);
93   }
94   free(buffer);
95   return 1;
96 }
97
98 #endif
99
100 /*
101  * Check what SIMD accelerations are supported.
102  *
103  * FIXME: This code is racy under a multi-threaded environment.
104  */
105 LOCAL(void)
106 init_simd (void)
107 {
108   char *env = NULL;
109 #if !defined(__ARM_NEON__) && defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
110   int bufsize = 1024; /* an initial guess for the line buffer size limit */
111 #endif
112
113   if (simd_support != ~0U)
114     return;
115
116   simd_support = 0;
117
118 #if defined(__ARM_NEON__)
119   simd_support |= JSIMD_ARM_NEON;
120 #elif defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
121   /* We still have a chance to use NEON regardless of globally used
122    * -mcpu/-mfpu options passed to gcc by performing runtime detection via
123    * /proc/cpuinfo parsing on linux/android */
124   while (!parse_proc_cpuinfo(bufsize)) {
125     bufsize *= 2;
126     if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT)
127       break;
128   }
129 #endif
130
131   /* Force different settings through environment variables */
132   env = getenv("JSIMD_FORCENEON");
133   if ((env != NULL) && (strcmp(env, "1") == 0))
134     simd_support = JSIMD_ARM_NEON;
135   env = getenv("JSIMD_FORCENONE");
136   if ((env != NULL) && (strcmp(env, "1") == 0))
137     simd_support = 0;
138   env = getenv("JSIMD_NOHUFFENC");
139   if ((env != NULL) && (strcmp(env, "1") == 0))
140     simd_huffman = 0;
141 }
142
143 GLOBAL(int)
144 jsimd_can_rgb_ycc (void)
145 {
146   init_simd();
147
148   /* The code is optimised for these values only */
149   if (BITS_IN_JSAMPLE != 8)
150     return 0;
151   if (sizeof(JDIMENSION) != 4)
152     return 0;
153   if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
154     return 0;
155
156   if (simd_support & JSIMD_ARM_NEON)
157     return 1;
158
159   return 0;
160 }
161
162 GLOBAL(int)
163 jsimd_can_rgb_gray (void)
164 {
165   init_simd();
166
167   return 0;
168 }
169
170 GLOBAL(int)
171 jsimd_can_ycc_rgb (void)
172 {
173   init_simd();
174
175   /* The code is optimised for these values only */
176   if (BITS_IN_JSAMPLE != 8)
177     return 0;
178   if (sizeof(JDIMENSION) != 4)
179     return 0;
180   if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
181     return 0;
182
183   if (simd_support & JSIMD_ARM_NEON)
184     return 1;
185
186   return 0;
187 }
188
189 GLOBAL(int)
190 jsimd_can_ycc_rgb565 (void)
191 {
192   init_simd();
193
194   /* The code is optimised for these values only */
195   if (BITS_IN_JSAMPLE != 8)
196     return 0;
197   if (sizeof(JDIMENSION) != 4)
198     return 0;
199
200   if (simd_support & JSIMD_ARM_NEON)
201     return 1;
202
203   return 0;
204 }
205
206 GLOBAL(void)
207 jsimd_rgb_ycc_convert (j_compress_ptr cinfo,
208                        JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
209                        JDIMENSION output_row, int num_rows)
210 {
211   void (*neonfct)(JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
212
213   switch(cinfo->in_color_space) {
214     case JCS_EXT_RGB:
215       neonfct=jsimd_extrgb_ycc_convert_neon;
216       break;
217     case JCS_EXT_RGBX:
218     case JCS_EXT_RGBA:
219       neonfct=jsimd_extrgbx_ycc_convert_neon;
220       break;
221     case JCS_EXT_BGR:
222       neonfct=jsimd_extbgr_ycc_convert_neon;
223       break;
224     case JCS_EXT_BGRX:
225     case JCS_EXT_BGRA:
226       neonfct=jsimd_extbgrx_ycc_convert_neon;
227       break;
228     case JCS_EXT_XBGR:
229     case JCS_EXT_ABGR:
230       neonfct=jsimd_extxbgr_ycc_convert_neon;
231       break;
232     case JCS_EXT_XRGB:
233     case JCS_EXT_ARGB:
234       neonfct=jsimd_extxrgb_ycc_convert_neon;
235       break;
236     default:
237       neonfct=jsimd_extrgb_ycc_convert_neon;
238       break;
239   }
240
241   neonfct(cinfo->image_width, input_buf, output_buf, output_row, num_rows);
242 }
243
244 GLOBAL(void)
245 jsimd_rgb_gray_convert (j_compress_ptr cinfo,
246                         JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
247                         JDIMENSION output_row, int num_rows)
248 {
249 }
250
251 GLOBAL(void)
252 jsimd_ycc_rgb_convert (j_decompress_ptr cinfo,
253                        JSAMPIMAGE input_buf, JDIMENSION input_row,
254                        JSAMPARRAY output_buf, int num_rows)
255 {
256   void (*neonfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
257
258   switch(cinfo->out_color_space) {
259     case JCS_EXT_RGB:
260       neonfct=jsimd_ycc_extrgb_convert_neon;
261       break;
262     case JCS_EXT_RGBX:
263     case JCS_EXT_RGBA:
264       neonfct=jsimd_ycc_extrgbx_convert_neon;
265       break;
266     case JCS_EXT_BGR:
267       neonfct=jsimd_ycc_extbgr_convert_neon;
268       break;
269     case JCS_EXT_BGRX:
270     case JCS_EXT_BGRA:
271       neonfct=jsimd_ycc_extbgrx_convert_neon;
272       break;
273     case JCS_EXT_XBGR:
274     case JCS_EXT_ABGR:
275       neonfct=jsimd_ycc_extxbgr_convert_neon;
276       break;
277     case JCS_EXT_XRGB:
278     case JCS_EXT_ARGB:
279       neonfct=jsimd_ycc_extxrgb_convert_neon;
280       break;
281     default:
282       neonfct=jsimd_ycc_extrgb_convert_neon;
283       break;
284   }
285
286 #if _USE_PRODUCT_TV
287   if (simd_support & JSIMD_ARM_NEON) {
288     neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows);
289     PickColor* pickColor = cinfo->pick_color_data;
290     if(pickColor && pickColor->enablePickColor && output_buf) {
291       int w = cinfo->output_width;
292       unsigned char *ptr = *output_buf;
293       if(pickColor->perc <= 0) {
294         w = pickColor->x2 - pickColor->x1 + 1;
295         ptr = (*output_buf) + (pickColor->x1 * 3);
296       }
297       jsimd_pick_color(ptr, pickColor, w);
298     }
299   }
300 #else
301   neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows);
302 #endif
303 }
304
305 GLOBAL(void)
306 jsimd_ycc_rgb565_convert (j_decompress_ptr cinfo,
307                           JSAMPIMAGE input_buf, JDIMENSION input_row,
308                           JSAMPARRAY output_buf, int num_rows)
309 {
310   jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row,
311                                 output_buf, num_rows);
312 }
313
314 GLOBAL(int)
315 jsimd_can_h2v2_downsample (void)
316 {
317   init_simd();
318
319   return 0;
320 }
321
322 GLOBAL(int)
323 jsimd_can_h2v1_downsample (void)
324 {
325   init_simd();
326
327   return 0;
328 }
329
330 GLOBAL(void)
331 jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
332                        JSAMPARRAY input_data, JSAMPARRAY output_data)
333 {
334 }
335
336 GLOBAL(void)
337 jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
338                        JSAMPARRAY input_data, JSAMPARRAY output_data)
339 {
340 }
341
342 GLOBAL(int)
343 jsimd_can_h2v2_upsample (void)
344 {
345   init_simd();
346
347   return 0;
348 }
349
350 GLOBAL(int)
351 jsimd_can_h2v1_upsample (void)
352 {
353   init_simd();
354
355   return 0;
356 }
357
358 GLOBAL(void)
359 jsimd_h2v2_upsample (j_decompress_ptr cinfo,
360                      jpeg_component_info *compptr,
361                      JSAMPARRAY input_data,
362                      JSAMPARRAY *output_data_ptr)
363 {
364 }
365
366 GLOBAL(void)
367 jsimd_h2v1_upsample (j_decompress_ptr cinfo,
368                      jpeg_component_info *compptr,
369                      JSAMPARRAY input_data,
370                      JSAMPARRAY *output_data_ptr)
371 {
372 }
373
374 GLOBAL(int)
375 jsimd_can_h2v2_fancy_upsample (void)
376 {
377   init_simd();
378
379   return 0;
380 }
381
382 GLOBAL(int)
383 jsimd_can_h2v1_fancy_upsample (void)
384 {
385   init_simd();
386
387   /* The code is optimised for these values only */
388   if (BITS_IN_JSAMPLE != 8)
389     return 0;
390   if (sizeof(JDIMENSION) != 4)
391     return 0;
392
393   if (simd_support & JSIMD_ARM_NEON)
394     return 1;
395
396   return 0;
397 }
398
399 GLOBAL(void)
400 jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo,
401                            jpeg_component_info *compptr,
402                            JSAMPARRAY input_data,
403                            JSAMPARRAY *output_data_ptr)
404 {
405 }
406
407 GLOBAL(void)
408 jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo,
409                            jpeg_component_info *compptr,
410                            JSAMPARRAY input_data,
411                            JSAMPARRAY *output_data_ptr)
412 {
413   jsimd_h2v1_fancy_upsample_neon(cinfo->max_v_samp_factor,
414                                  compptr->downsampled_width, input_data,
415                                  output_data_ptr);
416 }
417
418 GLOBAL(int)
419 jsimd_can_h2v2_merged_upsample (void)
420 {
421   init_simd();
422
423   return 0;
424 }
425
426 GLOBAL(int)
427 jsimd_can_h2v1_merged_upsample (void)
428 {
429   init_simd();
430
431   return 0;
432 }
433
434 GLOBAL(void)
435 jsimd_h2v2_merged_upsample (j_decompress_ptr cinfo,
436                             JSAMPIMAGE input_buf,
437                             JDIMENSION in_row_group_ctr,
438                             JSAMPARRAY output_buf)
439 {
440 }
441
442 GLOBAL(void)
443 jsimd_h2v1_merged_upsample (j_decompress_ptr cinfo,
444                             JSAMPIMAGE input_buf,
445                             JDIMENSION in_row_group_ctr,
446                             JSAMPARRAY output_buf)
447 {
448 }
449
450 GLOBAL(int)
451 jsimd_can_convsamp (void)
452 {
453   init_simd();
454
455   /* The code is optimised for these values only */
456   if (DCTSIZE != 8)
457     return 0;
458   if (BITS_IN_JSAMPLE != 8)
459     return 0;
460   if (sizeof(JDIMENSION) != 4)
461     return 0;
462   if (sizeof(DCTELEM) != 2)
463     return 0;
464
465   if (simd_support & JSIMD_ARM_NEON)
466     return 1;
467
468   return 0;
469 }
470
471 GLOBAL(int)
472 jsimd_can_convsamp_float (void)
473 {
474   init_simd();
475
476   return 0;
477 }
478
479 GLOBAL(void)
480 jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col,
481                 DCTELEM *workspace)
482 {
483   jsimd_convsamp_neon(sample_data, start_col, workspace);
484 }
485
486 GLOBAL(void)
487 jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col,
488                       FAST_FLOAT *workspace)
489 {
490 }
491
492 GLOBAL(int)
493 jsimd_can_fdct_islow (void)
494 {
495   init_simd();
496
497   return 0;
498 }
499
500 GLOBAL(int)
501 jsimd_can_fdct_ifast (void)
502 {
503   init_simd();
504
505   /* The code is optimised for these values only */
506   if (DCTSIZE != 8)
507     return 0;
508   if (sizeof(DCTELEM) != 2)
509     return 0;
510
511   if (simd_support & JSIMD_ARM_NEON)
512     return 1;
513
514   return 0;
515 }
516
517 GLOBAL(int)
518 jsimd_can_fdct_float (void)
519 {
520   init_simd();
521
522   return 0;
523 }
524
525 GLOBAL(void)
526 jsimd_fdct_islow (DCTELEM *data)
527 {
528 }
529
530 GLOBAL(void)
531 jsimd_fdct_ifast (DCTELEM *data)
532 {
533   jsimd_fdct_ifast_neon(data);
534 }
535
536 GLOBAL(void)
537 jsimd_fdct_float (FAST_FLOAT *data)
538 {
539 }
540
541 GLOBAL(int)
542 jsimd_can_quantize (void)
543 {
544   init_simd();
545
546   /* The code is optimised for these values only */
547   if (DCTSIZE != 8)
548     return 0;
549   if (sizeof(JCOEF) != 2)
550     return 0;
551   if (sizeof(DCTELEM) != 2)
552     return 0;
553
554   if (simd_support & JSIMD_ARM_NEON)
555     return 1;
556
557   return 0;
558 }
559
560 GLOBAL(int)
561 jsimd_can_quantize_float (void)
562 {
563   init_simd();
564
565   return 0;
566 }
567
568 GLOBAL(void)
569 jsimd_quantize (JCOEFPTR coef_block, DCTELEM *divisors,
570                 DCTELEM *workspace)
571 {
572   jsimd_quantize_neon(coef_block, divisors, workspace);
573 }
574
575 GLOBAL(void)
576 jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT *divisors,
577                       FAST_FLOAT *workspace)
578 {
579 }
580
581 GLOBAL(int)
582 jsimd_can_idct_2x2 (void)
583 {
584   init_simd();
585
586   /* The code is optimised for these values only */
587   if (DCTSIZE != 8)
588     return 0;
589   if (sizeof(JCOEF) != 2)
590     return 0;
591   if (BITS_IN_JSAMPLE != 8)
592     return 0;
593   if (sizeof(JDIMENSION) != 4)
594     return 0;
595   if (sizeof(ISLOW_MULT_TYPE) != 2)
596     return 0;
597
598   if (simd_support & JSIMD_ARM_NEON)
599     return 1;
600
601   return 0;
602 }
603
604 GLOBAL(int)
605 jsimd_can_idct_4x4 (void)
606 {
607   init_simd();
608
609   /* The code is optimised for these values only */
610   if (DCTSIZE != 8)
611     return 0;
612   if (sizeof(JCOEF) != 2)
613     return 0;
614   if (BITS_IN_JSAMPLE != 8)
615     return 0;
616   if (sizeof(JDIMENSION) != 4)
617     return 0;
618   if (sizeof(ISLOW_MULT_TYPE) != 2)
619     return 0;
620
621   if (simd_support & JSIMD_ARM_NEON)
622     return 1;
623
624   return 0;
625 }
626
627 GLOBAL(void)
628 jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info *compptr,
629                 JCOEFPTR coef_block, JSAMPARRAY output_buf,
630                 JDIMENSION output_col)
631 {
632   jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf,
633                       output_col);
634 }
635
636 GLOBAL(void)
637 jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info *compptr,
638                 JCOEFPTR coef_block, JSAMPARRAY output_buf,
639                 JDIMENSION output_col)
640 {
641   jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf,
642                       output_col);
643 }
644
645 GLOBAL(int)
646 jsimd_can_idct_islow (void)
647 {
648   init_simd();
649
650   /* The code is optimised for these values only */
651   if (DCTSIZE != 8)
652     return 0;
653   if (sizeof(JCOEF) != 2)
654     return 0;
655   if (BITS_IN_JSAMPLE != 8)
656     return 0;
657   if (sizeof(JDIMENSION) != 4)
658     return 0;
659   if (sizeof(ISLOW_MULT_TYPE) != 2)
660     return 0;
661
662   if (simd_support & JSIMD_ARM_NEON)
663     return 1;
664
665   return 0;
666 }
667
668 GLOBAL(int)
669 jsimd_can_idct_ifast (void)
670 {
671   init_simd();
672
673   /* The code is optimised for these values only */
674   if (DCTSIZE != 8)
675     return 0;
676   if (sizeof(JCOEF) != 2)
677     return 0;
678   if (BITS_IN_JSAMPLE != 8)
679     return 0;
680   if (sizeof(JDIMENSION) != 4)
681     return 0;
682   if (sizeof(IFAST_MULT_TYPE) != 2)
683     return 0;
684   if (IFAST_SCALE_BITS != 2)
685     return 0;
686
687   if (simd_support & JSIMD_ARM_NEON)
688     return 1;
689
690   return 0;
691 }
692
693 GLOBAL(int)
694 jsimd_can_idct_float (void)
695 {
696   init_simd();
697
698   return 0;
699 }
700
701 GLOBAL(void)
702 jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info *compptr,
703                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
704                   JDIMENSION output_col)
705 {
706   jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf,
707                         output_col);
708 }
709
710 GLOBAL(void)
711 jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info *compptr,
712                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
713                   JDIMENSION output_col)
714 {
715   jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf,
716                         output_col);
717 }
718
719 GLOBAL(void)
720 jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info *compptr,
721                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
722                   JDIMENSION output_col)
723 {
724 }
725
726 GLOBAL(int)
727 jsimd_can_huff_encode_one_block (void)
728 {
729   init_simd();
730
731   if (DCTSIZE != 8)
732     return 0;
733   if (sizeof(JCOEF) != 2)
734     return 0;
735
736   if (simd_support & JSIMD_ARM_NEON && simd_huffman)
737     return 1;
738
739   return 0;
740 }
741
742 GLOBAL(JOCTET*)
743 jsimd_huff_encode_one_block (void *state, JOCTET *buffer, JCOEFPTR block,
744                              int last_dc_val, c_derived_tbl *dctbl,
745                              c_derived_tbl *actbl)
746 {
747   return jsimd_huff_encode_one_block_neon(state, buffer, block, last_dc_val,
748                                           dctbl, actbl);
749 }