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