Edit

kc3-lang/libjpeg-turbo/simd/arm/jfdctfst-neon.c

Branch :

  • Show log

    Commit

  • Author : DRC
    Date : 2025-08-26 21:11:07
    Hash : 4e151a4a
    Message : Remove vestigial filenames from SIMD code headers These were a relic of libjpeg/SIMD, which attempted to follow the conventions of the libjpeg source code, but they are no longer relevant (or even accurate in some cases.)

  • simd/arm/jfdctfst-neon.c
  • /*
     * Fast integer FDCT (Arm Neon)
     *
     * Copyright (C) 2020, Arm Limited.  All Rights Reserved.
     * Copyright (C) 2024, D. R. Commander.  All Rights Reserved.
     *
     * This software is provided 'as-is', without any express or implied
     * warranty.  In no event will the authors be held liable for any damages
     * arising from the use of this software.
     *
     * Permission is granted to anyone to use this software for any purpose,
     * including commercial applications, and to alter it and redistribute it
     * freely, subject to the following restrictions:
     *
     * 1. The origin of this software must not be misrepresented; you must not
     *    claim that you wrote the original software. If you use this software
     *    in a product, an acknowledgment in the product documentation would be
     *    appreciated but is not required.
     * 2. Altered source versions must be plainly marked as such, and must not be
     *    misrepresented as being the original software.
     * 3. This notice may not be removed or altered from any source distribution.
     */
    
    #define JPEG_INTERNALS
    #include "../../src/jinclude.h"
    #include "../../src/jpeglib.h"
    #include "../../src/jsimd.h"
    #include "../../src/jdct.h"
    #include "../../src/jsimddct.h"
    #include "../jsimd.h"
    #include "align.h"
    #include "neon-compat.h"
    
    #include <arm_neon.h>
    
    
    /* jsimd_fdct_ifast_neon() performs a fast, not so accurate forward DCT
     * (Discrete Cosine Transform) on one block of samples.  It uses the same
     * calculations and produces exactly the same output as IJG's original
     * jpeg_fdct_ifast() function, which can be found in jfdctfst.c.
     *
     * Scaled integer constants are used to avoid floating-point arithmetic:
     *    0.382683433 = 12544 * 2^-15
     *    0.541196100 = 17795 * 2^-15
     *    0.707106781 = 23168 * 2^-15
     *    0.306562965 =  9984 * 2^-15
     *
     * See jfdctfst.c for further details of the DCT algorithm.  Where possible,
     * the variable names and comments here in jsimd_fdct_ifast_neon() match up
     * with those in jpeg_fdct_ifast().
     */
    
    #define F_0_382  12544
    #define F_0_541  17792
    #define F_0_707  23168
    #define F_0_306  9984
    
    
    ALIGN(16) static const int16_t jsimd_fdct_ifast_neon_consts[] = {
      F_0_382, F_0_541, F_0_707, F_0_306
    };
    
    void jsimd_fdct_ifast_neon(DCTELEM *data)
    {
      /* Load an 8x8 block of samples into Neon registers.  De-interleaving loads
       * are used, followed by vuzp to transpose the block such that we have a
       * column of samples per vector - allowing all rows to be processed at once.
       */
      int16x8x4_t data1 = vld4q_s16(data);
      int16x8x4_t data2 = vld4q_s16(data + 4 * DCTSIZE);
    
      int16x8x2_t cols_04 = vuzpq_s16(data1.val[0], data2.val[0]);
      int16x8x2_t cols_15 = vuzpq_s16(data1.val[1], data2.val[1]);
      int16x8x2_t cols_26 = vuzpq_s16(data1.val[2], data2.val[2]);
      int16x8x2_t cols_37 = vuzpq_s16(data1.val[3], data2.val[3]);
    
      int16x8_t col0 = cols_04.val[0];
      int16x8_t col1 = cols_15.val[0];
      int16x8_t col2 = cols_26.val[0];
      int16x8_t col3 = cols_37.val[0];
      int16x8_t col4 = cols_04.val[1];
      int16x8_t col5 = cols_15.val[1];
      int16x8_t col6 = cols_26.val[1];
      int16x8_t col7 = cols_37.val[1];
    
      /* Pass 1: process rows. */
    
      /* Load DCT conversion constants. */
      const int16x4_t consts = vld1_s16(jsimd_fdct_ifast_neon_consts);
    
      int16x8_t tmp0 = vaddq_s16(col0, col7);
      int16x8_t tmp7 = vsubq_s16(col0, col7);
      int16x8_t tmp1 = vaddq_s16(col1, col6);
      int16x8_t tmp6 = vsubq_s16(col1, col6);
      int16x8_t tmp2 = vaddq_s16(col2, col5);
      int16x8_t tmp5 = vsubq_s16(col2, col5);
      int16x8_t tmp3 = vaddq_s16(col3, col4);
      int16x8_t tmp4 = vsubq_s16(col3, col4);
    
      /* Even part */
      int16x8_t tmp10 = vaddq_s16(tmp0, tmp3);    /* phase 2 */
      int16x8_t tmp13 = vsubq_s16(tmp0, tmp3);
      int16x8_t tmp11 = vaddq_s16(tmp1, tmp2);
      int16x8_t tmp12 = vsubq_s16(tmp1, tmp2);
    
      col0 = vaddq_s16(tmp10, tmp11);             /* phase 3 */
      col4 = vsubq_s16(tmp10, tmp11);
    
      int16x8_t z1 = vqdmulhq_lane_s16(vaddq_s16(tmp12, tmp13), consts, 2);
      col2 = vaddq_s16(tmp13, z1);                /* phase 5 */
      col6 = vsubq_s16(tmp13, z1);
    
      /* Odd part */
      tmp10 = vaddq_s16(tmp4, tmp5);              /* phase 2 */
      tmp11 = vaddq_s16(tmp5, tmp6);
      tmp12 = vaddq_s16(tmp6, tmp7);
    
      int16x8_t z5 = vqdmulhq_lane_s16(vsubq_s16(tmp10, tmp12), consts, 0);
      int16x8_t z2 = vqdmulhq_lane_s16(tmp10, consts, 1);
      z2 = vaddq_s16(z2, z5);
      int16x8_t z4 = vqdmulhq_lane_s16(tmp12, consts, 3);
      z5 = vaddq_s16(tmp12, z5);
      z4 = vaddq_s16(z4, z5);
      int16x8_t z3 = vqdmulhq_lane_s16(tmp11, consts, 2);
    
      int16x8_t z11 = vaddq_s16(tmp7, z3);        /* phase 5 */
      int16x8_t z13 = vsubq_s16(tmp7, z3);
    
      col5 = vaddq_s16(z13, z2);                  /* phase 6 */
      col3 = vsubq_s16(z13, z2);
      col1 = vaddq_s16(z11, z4);
      col7 = vsubq_s16(z11, z4);
    
      /* Transpose to work on columns in pass 2. */
      int16x8x2_t cols_01 = vtrnq_s16(col0, col1);
      int16x8x2_t cols_23 = vtrnq_s16(col2, col3);
      int16x8x2_t cols_45 = vtrnq_s16(col4, col5);
      int16x8x2_t cols_67 = vtrnq_s16(col6, col7);
    
      int32x4x2_t cols_0145_l = vtrnq_s32(vreinterpretq_s32_s16(cols_01.val[0]),
                                          vreinterpretq_s32_s16(cols_45.val[0]));
      int32x4x2_t cols_0145_h = vtrnq_s32(vreinterpretq_s32_s16(cols_01.val[1]),
                                          vreinterpretq_s32_s16(cols_45.val[1]));
      int32x4x2_t cols_2367_l = vtrnq_s32(vreinterpretq_s32_s16(cols_23.val[0]),
                                          vreinterpretq_s32_s16(cols_67.val[0]));
      int32x4x2_t cols_2367_h = vtrnq_s32(vreinterpretq_s32_s16(cols_23.val[1]),
                                          vreinterpretq_s32_s16(cols_67.val[1]));
    
      int32x4x2_t rows_04 = vzipq_s32(cols_0145_l.val[0], cols_2367_l.val[0]);
      int32x4x2_t rows_15 = vzipq_s32(cols_0145_h.val[0], cols_2367_h.val[0]);
      int32x4x2_t rows_26 = vzipq_s32(cols_0145_l.val[1], cols_2367_l.val[1]);
      int32x4x2_t rows_37 = vzipq_s32(cols_0145_h.val[1], cols_2367_h.val[1]);
    
      int16x8_t row0 = vreinterpretq_s16_s32(rows_04.val[0]);
      int16x8_t row1 = vreinterpretq_s16_s32(rows_15.val[0]);
      int16x8_t row2 = vreinterpretq_s16_s32(rows_26.val[0]);
      int16x8_t row3 = vreinterpretq_s16_s32(rows_37.val[0]);
      int16x8_t row4 = vreinterpretq_s16_s32(rows_04.val[1]);
      int16x8_t row5 = vreinterpretq_s16_s32(rows_15.val[1]);
      int16x8_t row6 = vreinterpretq_s16_s32(rows_26.val[1]);
      int16x8_t row7 = vreinterpretq_s16_s32(rows_37.val[1]);
    
      /* Pass 2: process columns. */
    
      tmp0 = vaddq_s16(row0, row7);
      tmp7 = vsubq_s16(row0, row7);
      tmp1 = vaddq_s16(row1, row6);
      tmp6 = vsubq_s16(row1, row6);
      tmp2 = vaddq_s16(row2, row5);
      tmp5 = vsubq_s16(row2, row5);
      tmp3 = vaddq_s16(row3, row4);
      tmp4 = vsubq_s16(row3, row4);
    
      /* Even part */
      tmp10 = vaddq_s16(tmp0, tmp3);              /* phase 2 */
      tmp13 = vsubq_s16(tmp0, tmp3);
      tmp11 = vaddq_s16(tmp1, tmp2);
      tmp12 = vsubq_s16(tmp1, tmp2);
    
      row0 = vaddq_s16(tmp10, tmp11);             /* phase 3 */
      row4 = vsubq_s16(tmp10, tmp11);
    
      z1 = vqdmulhq_lane_s16(vaddq_s16(tmp12, tmp13), consts, 2);
      row2 = vaddq_s16(tmp13, z1);                /* phase 5 */
      row6 = vsubq_s16(tmp13, z1);
    
      /* Odd part */
      tmp10 = vaddq_s16(tmp4, tmp5);              /* phase 2 */
      tmp11 = vaddq_s16(tmp5, tmp6);
      tmp12 = vaddq_s16(tmp6, tmp7);
    
      z5 = vqdmulhq_lane_s16(vsubq_s16(tmp10, tmp12), consts, 0);
      z2 = vqdmulhq_lane_s16(tmp10, consts, 1);
      z2 = vaddq_s16(z2, z5);
      z4 = vqdmulhq_lane_s16(tmp12, consts, 3);
      z5 = vaddq_s16(tmp12, z5);
      z4 = vaddq_s16(z4, z5);
      z3 = vqdmulhq_lane_s16(tmp11, consts, 2);
    
      z11 = vaddq_s16(tmp7, z3);                  /* phase 5 */
      z13 = vsubq_s16(tmp7, z3);
    
      row5 = vaddq_s16(z13, z2);                  /* phase 6 */
      row3 = vsubq_s16(z13, z2);
      row1 = vaddq_s16(z11, z4);
      row7 = vsubq_s16(z11, z4);
    
      vst1q_s16(data + 0 * DCTSIZE, row0);
      vst1q_s16(data + 1 * DCTSIZE, row1);
      vst1q_s16(data + 2 * DCTSIZE, row2);
      vst1q_s16(data + 3 * DCTSIZE, row3);
      vst1q_s16(data + 4 * DCTSIZE, row4);
      vst1q_s16(data + 5 * DCTSIZE, row5);
      vst1q_s16(data + 6 * DCTSIZE, row6);
      vst1q_s16(data + 7 * DCTSIZE, row7);
    }