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