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