diff options
Diffstat (limited to 'simd/jsimd_arm64.c')
-rw-r--r-- | simd/jsimd_arm64.c | 354 |
1 files changed, 306 insertions, 48 deletions
diff --git a/simd/jsimd_arm64.c b/simd/jsimd_arm64.c index 65724cb9..09449bb6 100644 --- a/simd/jsimd_arm64.c +++ b/simd/jsimd_arm64.c @@ -2,7 +2,8 @@ * jsimd_arm64.c * * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB - * Copyright 2009-2011, 2013-2014 D. R. Commander + * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander. + * Copyright (C) 2015-2016, Matthieu Darbois. * * Based on the x86 SIMD extension for IJG JPEG library, * Copyright (C) 1999-2006, MIYASAKA Masaru. @@ -25,7 +26,84 @@ #include <string.h> #include <ctype.h> +#define JSIMD_FASTLD3 1 +#define JSIMD_FASTST3 2 +#define JSIMD_FASTTBL 4 + static unsigned int simd_support = ~0; +static unsigned int simd_huffman = 1; +static unsigned int simd_features = JSIMD_FASTLD3 | JSIMD_FASTST3 | + JSIMD_FASTTBL; + +#if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__) + +#define SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT (1024 * 1024) + +LOCAL(int) +check_cpuinfo (char *buffer, const char *field, char *value) +{ + char *p; + if (*value == 0) + return 0; + if (strncmp(buffer, field, strlen(field)) != 0) + return 0; + buffer += strlen(field); + while (isspace(*buffer)) + buffer++; + + /* Check if 'value' is present in the buffer as a separate word */ + while ((p = strstr(buffer, value))) { + if (p > buffer && !isspace(*(p - 1))) { + buffer++; + continue; + } + p += strlen(value); + if (*p != 0 && !isspace(*p)) { + buffer++; + continue; + } + return 1; + } + return 0; +} + +LOCAL(int) +parse_proc_cpuinfo (int bufsize) +{ + char *buffer = (char *)malloc(bufsize); + FILE *fd; + + if (!buffer) + return 0; + + fd = fopen("/proc/cpuinfo", "r"); + if (fd) { + while (fgets(buffer, bufsize, fd)) { + if (!strchr(buffer, '\n') && !feof(fd)) { + /* "impossible" happened - insufficient size of the buffer! */ + fclose(fd); + free(buffer); + return 0; + } + if (check_cpuinfo(buffer, "CPU part", "0xd03") || + check_cpuinfo(buffer, "CPU part", "0xd07")) + /* The Cortex-A53 has a slow tbl implementation. We can gain a few + percent speedup by disabling the use of that instruction. The + speedup on Cortex-A57 is more subtle but still measurable. */ + simd_features &= ~JSIMD_FASTTBL; + else if (check_cpuinfo(buffer, "CPU part", "0x0a1")) + /* The SIMD version of Huffman encoding is slower than the C version on + Cavium ThunderX. Also, ld3 and st3 are abyssmally slow on that + CPU. */ + simd_huffman = simd_features = 0; + } + fclose(fd); + } + free(buffer); + return 1; +} + +#endif /* * Check what SIMD accelerations are supported. @@ -33,16 +111,19 @@ static unsigned int simd_support = ~0; * FIXME: This code is racy under a multi-threaded environment. */ -/* +/* * ARMv8 architectures support NEON extensions by default. * It is no longer optional as it was with ARMv7. - */ + */ LOCAL(void) init_simd (void) { char *env = NULL; +#if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__) + int bufsize = 1024; /* an initial guess for the line buffer size limit */ +#endif if (simd_support != ~0U) return; @@ -50,14 +131,34 @@ init_simd (void) simd_support = 0; simd_support |= JSIMD_ARM_NEON; +#if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__) + while (!parse_proc_cpuinfo(bufsize)) { + bufsize *= 2; + if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT) + break; + } +#endif /* Force different settings through environment variables */ env = getenv("JSIMD_FORCENEON"); if ((env != NULL) && (strcmp(env, "1") == 0)) - simd_support &= JSIMD_ARM_NEON; + simd_support = JSIMD_ARM_NEON; env = getenv("JSIMD_FORCENONE"); if ((env != NULL) && (strcmp(env, "1") == 0)) simd_support = 0; + env = getenv("JSIMD_NOHUFFENC"); + if ((env != NULL) && (strcmp(env, "1") == 0)) + simd_huffman = 0; + env = getenv("JSIMD_FASTLD3"); + if ((env != NULL) && (strcmp(env, "1") == 0)) + simd_features |= JSIMD_FASTLD3; + if ((env != NULL) && (strcmp(env, "0") == 0)) + simd_features &= ~JSIMD_FASTLD3; + env = getenv("JSIMD_FASTST3"); + if ((env != NULL) && (strcmp(env, "1") == 0)) + simd_features |= JSIMD_FASTST3; + if ((env != NULL) && (strcmp(env, "0") == 0)) + simd_features &= ~JSIMD_FASTST3; } GLOBAL(int) @@ -65,6 +166,17 @@ jsimd_can_rgb_ycc (void) { init_simd(); + /* The code is optimised for these values only */ + if (BITS_IN_JSAMPLE != 8) + return 0; + if (sizeof(JDIMENSION) != 4) + return 0; + if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4)) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -117,6 +229,46 @@ jsimd_rgb_ycc_convert (j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows) { + void (*neonfct)(JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); + + switch(cinfo->in_color_space) { + case JCS_EXT_RGB: + if (simd_features & JSIMD_FASTLD3) + neonfct=jsimd_extrgb_ycc_convert_neon; + else + neonfct=jsimd_extrgb_ycc_convert_neon_slowld3; + break; + case JCS_EXT_RGBX: + case JCS_EXT_RGBA: + neonfct=jsimd_extrgbx_ycc_convert_neon; + break; + case JCS_EXT_BGR: + if (simd_features & JSIMD_FASTLD3) + neonfct=jsimd_extbgr_ycc_convert_neon; + else + neonfct=jsimd_extbgr_ycc_convert_neon_slowld3; + break; + case JCS_EXT_BGRX: + case JCS_EXT_BGRA: + neonfct=jsimd_extbgrx_ycc_convert_neon; + break; + case JCS_EXT_XBGR: + case JCS_EXT_ABGR: + neonfct=jsimd_extxbgr_ycc_convert_neon; + break; + case JCS_EXT_XRGB: + case JCS_EXT_ARGB: + neonfct=jsimd_extxrgb_ycc_convert_neon; + break; + default: + if (simd_features & JSIMD_FASTLD3) + neonfct=jsimd_extrgb_ycc_convert_neon; + else + neonfct=jsimd_extrgb_ycc_convert_neon_slowld3; + break; + } + + neonfct(cinfo->image_width, input_buf, output_buf, output_row, num_rows); } GLOBAL(void) @@ -135,14 +287,20 @@ jsimd_ycc_rgb_convert (j_decompress_ptr cinfo, switch(cinfo->out_color_space) { case JCS_EXT_RGB: - neonfct=jsimd_ycc_extrgb_convert_neon; + if (simd_features & JSIMD_FASTST3) + neonfct=jsimd_ycc_extrgb_convert_neon; + else + neonfct=jsimd_ycc_extrgb_convert_neon_slowst3; break; case JCS_EXT_RGBX: case JCS_EXT_RGBA: neonfct=jsimd_ycc_extrgbx_convert_neon; break; case JCS_EXT_BGR: - neonfct=jsimd_ycc_extbgr_convert_neon; + if (simd_features & JSIMD_FASTST3) + neonfct=jsimd_ycc_extbgr_convert_neon; + else + neonfct=jsimd_ycc_extbgr_convert_neon_slowst3; break; case JCS_EXT_BGRX: case JCS_EXT_BGRA: @@ -157,12 +315,14 @@ jsimd_ycc_rgb_convert (j_decompress_ptr cinfo, neonfct=jsimd_ycc_extxrgb_convert_neon; break; default: - neonfct=jsimd_ycc_extrgb_convert_neon; + if (simd_features & JSIMD_FASTST3) + neonfct=jsimd_ycc_extrgb_convert_neon; + else + neonfct=jsimd_ycc_extrgb_convert_neon_slowst3; break; } - if (simd_support & JSIMD_ARM_NEON) - neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows); + neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows); } GLOBAL(void) @@ -170,9 +330,8 @@ jsimd_ycc_rgb565_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) { - if (simd_support & JSIMD_ARM_NEON) - jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row, - output_buf, num_rows); + jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row, + output_buf, num_rows); } GLOBAL(int) @@ -180,6 +339,17 @@ jsimd_can_h2v2_downsample (void) { init_simd(); + /* The code is optimised for these values only */ + if (BITS_IN_JSAMPLE != 8) + return 0; + if (DCTSIZE != 8) + return 0; + if (sizeof(JDIMENSION) != 4) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -188,19 +358,36 @@ jsimd_can_h2v1_downsample (void) { init_simd(); + /* The code is optimised for these values only */ + if (BITS_IN_JSAMPLE != 8) + return 0; + if (DCTSIZE != 8) + return 0; + if (sizeof(JDIMENSION) != 4) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } GLOBAL(void) -jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, +jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, JSAMPARRAY input_data, JSAMPARRAY output_data) { + jsimd_h2v2_downsample_neon(cinfo->image_width, cinfo->max_v_samp_factor, + compptr->v_samp_factor, compptr->width_in_blocks, + input_data, output_data); } GLOBAL(void) -jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, +jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, JSAMPARRAY input_data, JSAMPARRAY output_data) { + jsimd_h2v1_downsample_neon(cinfo->image_width, cinfo->max_v_samp_factor, + compptr->v_samp_factor, compptr->width_in_blocks, + input_data, output_data); } GLOBAL(int) @@ -221,17 +408,17 @@ jsimd_can_h2v1_upsample (void) GLOBAL(void) jsimd_h2v2_upsample (j_decompress_ptr cinfo, - jpeg_component_info * compptr, + jpeg_component_info *compptr, JSAMPARRAY input_data, - JSAMPARRAY * output_data_ptr) + JSAMPARRAY *output_data_ptr) { } GLOBAL(void) jsimd_h2v1_upsample (j_decompress_ptr cinfo, - jpeg_component_info * compptr, + jpeg_component_info *compptr, JSAMPARRAY input_data, - JSAMPARRAY * output_data_ptr) + JSAMPARRAY *output_data_ptr) { } @@ -253,17 +440,17 @@ jsimd_can_h2v1_fancy_upsample (void) GLOBAL(void) jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo, - jpeg_component_info * compptr, + jpeg_component_info *compptr, JSAMPARRAY input_data, - JSAMPARRAY * output_data_ptr) + JSAMPARRAY *output_data_ptr) { } GLOBAL(void) jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo, - jpeg_component_info * compptr, + jpeg_component_info *compptr, JSAMPARRAY input_data, - JSAMPARRAY * output_data_ptr) + JSAMPARRAY *output_data_ptr) { } @@ -304,6 +491,19 @@ jsimd_can_convsamp (void) { init_simd(); + /* The code is optimised for these values only */ + if (DCTSIZE != 8) + return 0; + if (BITS_IN_JSAMPLE != 8) + return 0; + if (sizeof(JDIMENSION) != 4) + return 0; + if (sizeof(DCTELEM) != 2) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -317,13 +517,14 @@ jsimd_can_convsamp_float (void) GLOBAL(void) jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, - DCTELEM * workspace) + DCTELEM *workspace) { + jsimd_convsamp_neon(sample_data, start_col, workspace); } GLOBAL(void) jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, - FAST_FLOAT * workspace) + FAST_FLOAT *workspace) { } @@ -332,6 +533,15 @@ jsimd_can_fdct_islow (void) { init_simd(); + /* The code is optimised for these values only */ + if (DCTSIZE != 8) + return 0; + if (sizeof(DCTELEM) != 2) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -340,6 +550,15 @@ jsimd_can_fdct_ifast (void) { init_simd(); + /* The code is optimised for these values only */ + if (DCTSIZE != 8) + return 0; + if (sizeof(DCTELEM) != 2) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -352,17 +571,19 @@ jsimd_can_fdct_float (void) } GLOBAL(void) -jsimd_fdct_islow (DCTELEM * data) +jsimd_fdct_islow (DCTELEM *data) { + jsimd_fdct_islow_neon(data); } GLOBAL(void) -jsimd_fdct_ifast (DCTELEM * data) +jsimd_fdct_ifast (DCTELEM *data) { + jsimd_fdct_ifast_neon(data); } GLOBAL(void) -jsimd_fdct_float (FAST_FLOAT * data) +jsimd_fdct_float (FAST_FLOAT *data) { } @@ -371,6 +592,17 @@ jsimd_can_quantize (void) { init_simd(); + /* The code is optimised for these values only */ + if (DCTSIZE != 8) + return 0; + if (sizeof(JCOEF) != 2) + return 0; + if (sizeof(DCTELEM) != 2) + return 0; + + if (simd_support & JSIMD_ARM_NEON) + return 1; + return 0; } @@ -383,14 +615,15 @@ jsimd_can_quantize_float (void) } GLOBAL(void) -jsimd_quantize (JCOEFPTR coef_block, DCTELEM * divisors, - DCTELEM * workspace) +jsimd_quantize (JCOEFPTR coef_block, DCTELEM *divisors, + DCTELEM *workspace) { + jsimd_quantize_neon(coef_block, divisors, workspace); } GLOBAL(void) -jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors, - FAST_FLOAT * workspace) +jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT *divisors, + FAST_FLOAT *workspace) { } @@ -441,23 +674,21 @@ jsimd_can_idct_4x4 (void) } GLOBAL(void) -jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, +jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info *compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col) { - if (simd_support & JSIMD_ARM_NEON) - jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf, - output_col); + jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf, + output_col); } GLOBAL(void) -jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, +jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info *compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col) { - if (simd_support & JSIMD_ARM_NEON) - jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf, - output_col); + jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf, + output_col); } GLOBAL(int) @@ -517,28 +748,55 @@ jsimd_can_idct_float (void) } GLOBAL(void) -jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, +jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info *compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col) { - if (simd_support & JSIMD_ARM_NEON) - jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf, - output_col); + jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf, + output_col); } GLOBAL(void) -jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, +jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info *compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col) { - if (simd_support & JSIMD_ARM_NEON) - jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf, - output_col); + jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf, + output_col); } GLOBAL(void) -jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, +jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info *compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col) { } + +GLOBAL(int) +jsimd_can_huff_encode_one_block (void) +{ + init_simd(); + + if (DCTSIZE != 8) + return 0; + if (sizeof(JCOEF) != 2) + return 0; + + if (simd_support & JSIMD_ARM_NEON && simd_huffman) + return 1; + + return 0; +} + +GLOBAL(JOCTET*) +jsimd_huff_encode_one_block (void *state, JOCTET *buffer, JCOEFPTR block, + int last_dc_val, c_derived_tbl *dctbl, + c_derived_tbl *actbl) +{ + if (simd_features & JSIMD_FASTTBL) + return jsimd_huff_encode_one_block_neon(state, buffer, block, last_dc_val, + dctbl, actbl); + else + return jsimd_huff_encode_one_block_neon_slowtbl(state, buffer, block, + last_dc_val, dctbl, actbl); +} |