1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00
Files
opencv/3rdparty/hal_rvv/hal_rvv_1p0/dxt.hpp
T
Liutong HAN 6eaaaa410e Merge pull request #27056 from hanliutong:rvv-hal-copyright
[RVV HAL] Add copyright and replace '#pragma once'. #27056

Add copyright and in RVV HAL, since other companies or teams may join the development and add their copyright.

And the '#pragma once' are replaced.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
2025-03-15 17:25:31 +03:00

569 lines
28 KiB
C++

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#ifndef OPENCV_HAL_RVV_DXT_HPP_INCLUDED
#define OPENCV_HAL_RVV_DXT_HPP_INCLUDED
#include <riscv_vector.h>
#include "hal_rvv_1p0/types.hpp"
#include "opencv2/core/types.hpp"
namespace cv { namespace cv_hal_rvv { namespace dxt {
#undef cv_hal_dft
#define cv_hal_dft cv::cv_hal_rvv::dxt::dft
template<typename T> struct rvv;
template<> struct rvv<float> : RVV_F32MF2
{
using T = RVV_F32MF2::VecType;
using TabType = RVV_U32M8;
using TabTypeF = RVV_SameLen<float, TabType>;
static inline void vlseg(const float* a, T& b, T& c, size_t d) { auto x = __riscv_vlseg2e32_v_f32mf2x2(a, d); b = __riscv_vget_v_f32mf2x2_f32mf2(x, 0), c = __riscv_vget_v_f32mf2x2_f32mf2(x, 1); }
static inline void vlsseg(const float* a, ptrdiff_t b, T& c, T& d, size_t e) { auto x = __riscv_vlsseg2e32_v_f32mf2x2(a, b, e); c = __riscv_vget_v_f32mf2x2_f32mf2(x, 0), d = __riscv_vget_v_f32mf2x2_f32mf2(x, 1); }
static inline void vsseg(float* a, T b, T c, size_t d) { __riscv_vsseg2e32(a, __riscv_vset_v_f32mf2_f32mf2x2(__riscv_vset_v_f32mf2_f32mf2x2(vfloat32mf2x2_t(), 0, b), 1, c), d); }
};
template<> struct rvv<double> : RVV_F64M1
{
using T = RVV_F64M1::VecType;
using TabType = RVV_U32M4;
using TabTypeF = RVV_SameLen<double, TabType>;
static inline void vlseg(const double* a, T& b, T& c, size_t d) { auto x = __riscv_vlseg2e64_v_f64m1x2(a, d); b = __riscv_vget_v_f64m1x2_f64m1(x, 0), c = __riscv_vget_v_f64m1x2_f64m1(x, 1); }
static inline void vlsseg(const double* a, ptrdiff_t b, T& c, T& d, size_t e) { auto x = __riscv_vlsseg2e64_v_f64m1x2(a, b, e); c = __riscv_vget_v_f64m1x2_f64m1(x, 0), d = __riscv_vget_v_f64m1x2_f64m1(x, 1); }
static inline void vsseg(double* a, T b, T c, size_t d) { __riscv_vsseg2e64(a, __riscv_vset_v_f64m1_f64m1x2(__riscv_vset_v_f64m1_f64m1x2(vfloat64m1x2_t(), 0, b), 1, c), d); }
};
// the algorithm is copied from core/src/dxt.cpp,
// in the function template static void cv::DFT and cv::DFT_R2, cv::DFT_R3, cv::DFT_R5
template <typename T>
inline int dft(const Complex<T>* src, Complex<T>* dst, int nf, int *factors, T scale, int* itab,
const Complex<T>* wave, int tab_size, int len, bool isInverse, bool noPermute)
{
int n = len;
int f_idx, nx;
int dw0 = tab_size, dw;
int i, j, k;
Complex<T> t;
using VT = typename rvv<T>::VecType;
using TabType = typename rvv<T>::TabType;
using TabTypeF = typename rvv<T>::TabTypeF;
int tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n;
int vl;
// 0. shuffle data
if( dst != src )
{
if( !isInverse )
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_itab = TabType::vload_stride(reinterpret_cast<const uint*>(itab + i * tab_step), sizeof(int) * tab_step, vl);
vec_itab = __riscv_vmul(vec_itab, sizeof(T) * 2, vl);
auto vec_src_re = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_itab = __riscv_vadd(vec_itab, sizeof(T), vl);
auto vec_src_im = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
else
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_itab = TabType::vload_stride(reinterpret_cast<const uint*>(itab + i * tab_step), sizeof(int) * tab_step, vl);
vec_itab = __riscv_vmul(vec_itab, sizeof(T) * 2, vl);
auto vec_src_re = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_itab = __riscv_vadd(vec_itab, sizeof(T), vl);
auto vec_src_im = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
}
else
{
// copied from core/src/dxt.cpp, it is slow to swap elements by intrinsics
if( !noPermute )
{
if( nf == 1 )
{
if( (n & 3) == 0 )
{
int n2 = n/2;
Complex<T>* dsth = dst + n2;
for( i = 0; i < n2; i += 2, itab += tab_step*2 )
{
j = itab[0];
t = dst[i+1], dst[i+1] = dsth[j], dsth[j] = t;
if( j > i )
{
t = dst[i], dst[i] = dst[j], dst[j] = t;
t = dsth[i+1], dsth[i+1] = dsth[j+1], dsth[j+1] = t;
}
}
}
// else do nothing
}
else
{
for( i = 0; i < n; i++, itab += tab_step )
{
j = itab[0];
if( j > i )
t = dst[i], dst[i] = dst[j], dst[j] = t;
}
}
}
if( isInverse )
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
}
n = 1;
// 1. power-2 transforms
if( (factors[0] & 1) == 0 )
{
// radix-4 transform
for( ; n*4 <= factors[0]; )
{
nx = n;
n *= 4;
dw0 /= 4;
for( i = 0; i < len; i += n )
{
Complex<T> *v0, *v1;
T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4;
v0 = dst + i;
v1 = v0 + nx*2;
r0 = v1[0].re; i0 = v1[0].im;
r4 = v1[nx].re; i4 = v1[nx].im;
r1 = r0 + r4; i1 = i0 + i4;
r3 = i0 - i4; i3 = r4 - r0;
r2 = v0[0].re; i2 = v0[0].im;
r4 = v0[nx].re; i4 = v0[nx].im;
r0 = r2 + r4; i0 = i2 + i4;
r2 -= r4; i2 -= i4;
v0[0].re = r0 + r1; v0[0].im = i0 + i1;
v1[0].re = r0 - r1; v1[0].im = i0 - i1;
v0[nx].re = r2 + r3; v0[nx].im = i2 + i3;
v1[nx].re = r2 - r3; v1[nx].im = i2 - i3;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v0 = dst + i + j;
v1 = v0 + nx*2;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v1), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 3), sizeof(T) * dw0 * 6, vec_w_re, vec_w_im, vl);
auto vec_r3 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i3 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_i0, vec_i3, vl);
auto vec_i1 = __riscv_vfadd(vec_r0, vec_r3, vl);
vec_r3 = __riscv_vfsub(vec_r0, vec_r3, vl);
vec_i3 = __riscv_vfsub(vec_i3, vec_i0, vl);
VT vec_r4, vec_i4;
rvv<T>::vlseg(reinterpret_cast<const T*>(v0), vec_r4, vec_i4, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v0 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
vec_r0 = __riscv_vfadd(vec_r4, vec_r2, vl);
vec_i0 = __riscv_vfadd(vec_i4, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1), __riscv_vfsub(vec_r0, vec_r1, vl), __riscv_vfsub(vec_i0, vec_i1, vl), vl);
vec_r2 = __riscv_vfsub(vec_r4, vec_r2, vl);
vec_i2 = __riscv_vfsub(vec_i4, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0 + nx), __riscv_vfadd(vec_r2, vec_r3, vl), __riscv_vfadd(vec_i2, vec_i3, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1 + nx), __riscv_vfsub(vec_r2, vec_r3, vl), __riscv_vfsub(vec_i2, vec_i3, vl), vl);
}
}
}
for( ; n < factors[0]; )
{
// do the remaining radix-2 transform
nx = n;
n *= 2;
dw0 /= 2;
for( i = 0; i < len; i += n )
{
Complex<T>* v = dst + i;
T r0 = v[0].re + v[nx].re;
T i0 = v[0].im + v[nx].im;
T r1 = v[0].re - v[nx].re;
T i1 = v[0].im - v[nx].im;
v[0].re = r0; v[0].im = i0;
v[nx].re = r1; v[nx].im = i1;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v = dst + i + j;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r1 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i1 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
VT vec_r0, vec_i0;
rvv<T>::vlseg(reinterpret_cast<const T*>(v), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx), __riscv_vfsub(vec_r0, vec_r1, vl), __riscv_vfsub(vec_i0, vec_i1, vl), vl);
}
}
}
}
// 2. all the other transforms
for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ )
{
int factor = factors[f_idx];
nx = n;
n *= factor;
dw0 /= factor;
if( factor == 3 )
{
const T sin_120 = 0.86602540378443864676372317075294;
for( i = 0; i < len; i += n )
{
Complex<T>* v = dst + i;
T r1 = v[nx].re + v[nx*2].re;
T i1 = v[nx].im + v[nx*2].im;
T r0 = v[0].re;
T i0 = v[0].im;
T r2 = sin_120*(v[nx].im - v[nx*2].im);
T i2 = sin_120*(v[nx*2].re - v[nx].re);
v[0].re = r0 + r1; v[0].im = i0 + i1;
r0 -= (T)0.5*r1; i0 -= (T)0.5*i1;
v[nx].re = r0 + r2; v[nx].im = i0 + i2;
v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v = dst + i + j;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx * 2), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_r0, vec_i2, vl);
auto vec_i1 = __riscv_vfadd(vec_i0, vec_r2, vl);
vec_r2 = __riscv_vfmul(__riscv_vfsub(vec_i0, vec_r2, vl), sin_120, vl);
vec_i2 = __riscv_vfmul(__riscv_vfsub(vec_i2, vec_r0, vl), sin_120, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, __riscv_vfmul(vec_r1, 0.5, vl), vl);
vec_i0 = __riscv_vfsub(vec_i0, __riscv_vfmul(vec_i1, 0.5, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx), __riscv_vfadd(vec_r0, vec_r2, vl), __riscv_vfadd(vec_i0, vec_i2, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx * 2), __riscv_vfsub(vec_r0, vec_r2, vl), __riscv_vfsub(vec_i0, vec_i2, vl), vl);
}
}
}
else if( factor == 5 )
{
const T fft5_2 = 0.559016994374947424102293417182819;
const T fft5_3 = -0.951056516295153572116439333379382;
const T fft5_4 = -1.538841768587626701285145288018455;
const T fft5_5 = 0.363271264002680442947733378740309;
for( i = 0; i < len; i += n )
{
for( j = 0; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
Complex<T>* v0 = dst + i + j;
Complex<T>* v1 = v0 + nx*2;
Complex<T>* v2 = v1 + nx*2;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v0 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r3 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i3 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v2), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 4), sizeof(T) * dw0 * 8, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_r3, vec_r2, vl);
auto vec_i1 = __riscv_vfadd(vec_i3, vec_i2, vl);
vec_r3 = __riscv_vfsub(vec_r3, vec_r2, vl);
vec_i3 = __riscv_vfsub(vec_i3, vec_i2, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 3), sizeof(T) * dw0 * 6, vec_w_re, vec_w_im, vl);
auto vec_r4 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i4 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
vec_r2 = __riscv_vfadd(vec_r4, vec_r0, vl);
vec_i2 = __riscv_vfadd(vec_i4, vec_i0, vl);
vec_r4 = __riscv_vfsub(vec_r4, vec_r0, vl);
vec_i4 = __riscv_vfsub(vec_i4, vec_i0, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v0), vec_r0, vec_i0, vl);
auto vec_r5 = __riscv_vfadd(vec_r1, vec_r2, vl);
auto vec_i5 = __riscv_vfadd(vec_i1, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0), __riscv_vfadd(vec_r0, vec_r5, vl), __riscv_vfadd(vec_i0, vec_i5, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, __riscv_vfmul(vec_r5, 0.25, vl), vl);
vec_i0 = __riscv_vfsub(vec_i0, __riscv_vfmul(vec_i5, 0.25, vl), vl);
vec_r1 = __riscv_vfmul(__riscv_vfsub(vec_r1, vec_r2, vl), fft5_2, vl);
vec_i1 = __riscv_vfmul(__riscv_vfsub(vec_i1, vec_i2, vl), fft5_2, vl);
vec_r2 = __riscv_vfmul(__riscv_vfadd(vec_i3, vec_i4, vl), -fft5_3, vl);
vec_i2 = __riscv_vfmul(__riscv_vfadd(vec_r3, vec_r4, vl), fft5_3, vl);
vec_i3 = __riscv_vfmul(vec_i3, -fft5_5, vl);
vec_r3 = __riscv_vfmul(vec_r3, fft5_5, vl);
vec_i4 = __riscv_vfmul(vec_i4, -fft5_4, vl);
vec_r4 = __riscv_vfmul(vec_r4, fft5_4, vl);
vec_r5 = __riscv_vfadd(vec_r2, vec_i3, vl);
vec_i5 = __riscv_vfadd(vec_i2, vec_r3, vl);
vec_r2 = __riscv_vfsub(vec_r2, vec_i4, vl);
vec_i2 = __riscv_vfsub(vec_i2, vec_r4, vl);
vec_r3 = __riscv_vfadd(vec_r0, vec_r1, vl);
vec_i3 = __riscv_vfadd(vec_i0, vec_i1, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0 + nx), __riscv_vfadd(vec_r3, vec_r2, vl), __riscv_vfadd(vec_i3, vec_i2, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v2), __riscv_vfsub(vec_r3, vec_r2, vl), __riscv_vfsub(vec_i3, vec_i2, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, vec_r1, vl);
vec_i0 = __riscv_vfsub(vec_i0, vec_i1, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1), __riscv_vfadd(vec_r0, vec_r5, vl), __riscv_vfadd(vec_i0, vec_i5, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1 + nx), __riscv_vfsub(vec_r0, vec_r5, vl), __riscv_vfsub(vec_i0, vec_i5, vl), vl);
}
}
}
else
{
// radix-"factor" - an odd number
int p, q, factor2 = (factor - 1)/2;
int dd, dw_f = tab_size/factor;
std::vector<Complex<T> > buf(factor2 * 2);
Complex<T>* a = buf.data();
Complex<T>* b = a + factor2;
for( i = 0; i < len; i += n )
{
for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
{
Complex<T>* v = dst + i + j;
Complex<T> v_0 = v[0];
Complex<T> vn_0 = v_0;
if( j == 0 )
{
for( p = 1; p <= factor2; p += vl )
{
vl = rvv<T>::setvl(factor2 + 1 - p);
VT vec_a_re, vec_a_im, vec_b_re, vec_b_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + nx * p), sizeof(T) * nx * 2, vec_a_re, vec_a_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + n - nx * p), (ptrdiff_t)sizeof(T) * nx * -2, vec_b_re, vec_b_im, vl);
auto vec_r0 = __riscv_vfadd(vec_a_re, vec_b_re, vl);
auto vec_r1 = __riscv_vfsub(vec_a_re, vec_b_re, vl);
auto vec_i0 = __riscv_vfsub(vec_a_im, vec_b_im, vl);
auto vec_i1 = __riscv_vfadd(vec_a_im, vec_b_im, vl);
vn_0.re += __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
vn_0.im += __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
rvv<T>::vsseg(reinterpret_cast<T*>(a + p - 1), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(b + p - 1), vec_r1, vec_i1, vl);
}
}
else
{
const Complex<T>* wave_ = wave + dw*factor;
for( p = 1; p <= factor2; p += vl )
{
vl = rvv<T>::setvl(factor2 + 1 - p);
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + nx * p), sizeof(T) * nx * 2, vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + p * dw), sizeof(T) * dw * 2, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + n - nx * p), (ptrdiff_t)sizeof(T) * nx * -2, vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave_ - p * dw), (ptrdiff_t)sizeof(T) * dw * -2, vec_w_re, vec_w_im, vl);
auto vec_r1 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i1 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_r0 = __riscv_vfadd(vec_r2, vec_r1, vl);
auto vec_i0 = __riscv_vfsub(vec_i2, vec_i1, vl);
vec_r1 = __riscv_vfsub(vec_r2, vec_r1, vl);
vec_i1 = __riscv_vfadd(vec_i2, vec_i1, vl);
vn_0.re += __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
vn_0.im += __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
rvv<T>::vsseg(reinterpret_cast<T*>(a + p - 1), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(b + p - 1), vec_r1, vec_i1, vl);
}
}
v[0] = vn_0;
for( p = 1, k = nx; p <= factor2; p++, k += nx )
{
Complex<T> s0 = v_0, s1 = v_0;
dd = dw_f*p;
vl = __riscv_vsetvlmax_e32mf2();
auto vec_dd = __riscv_vid_v_u32mf2(vl);
vec_dd = __riscv_vmul(vec_dd, dd, vl);
vec_dd = __riscv_vremu(vec_dd, tab_size, vl);
for( q = 0; q < factor2; q += vl )
{
vl = rvv<T>::setvl(factor2 - q);
auto vec_d = __riscv_vadd(vec_dd, (q + 1) * dd % tab_size, vl);
auto vmask = __riscv_vmsgeu(vec_d, tab_size, vl);
vec_d = __riscv_vsub_mu(vmask, vec_d, vec_d, tab_size, vl);
vec_d = __riscv_vmul(vec_d, sizeof(T) * 2, vl);
auto vec_w = __riscv_vloxei32(reinterpret_cast<const T*>(wave), vec_d, vl);
VT vec_a_re, vec_a_im, vec_b_re, vec_b_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(a + q), sizeof(T) * 2, vec_a_re, vec_a_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(b + q), sizeof(T) * 2, vec_b_re, vec_b_im, vl);
auto vec_r0 = __riscv_vfmul(vec_w, vec_a_re, vl);
auto vec_r1 = __riscv_vfmul(vec_w, vec_b_im, vl);
vec_w = __riscv_vloxei32(reinterpret_cast<const T*>(wave) + 1, vec_d, vl);
auto vec_i0 = __riscv_vfmul(vec_w, vec_a_im, vl);
auto vec_i1 = __riscv_vfmul(vec_w, vec_b_re, vl);
T r0 = __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T i0 = __riscv_vfmv_f(__riscv_vfredosum(vec_i0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T r1 = __riscv_vfmv_f(__riscv_vfredosum(vec_r1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T i1 = __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
s1.re += r0 + i0; s0.re += r0 - i0;
s1.im += r1 - i1; s0.im += r1 + i1;
}
v[k] = s0;
v[n-k] = s1;
}
}
}
}
}
if( scale != 1 )
{
T re_scale = scale, im_scale = scale;
if( isInverse )
im_scale = -im_scale;
for( i = 0; i < len; i += vl )
{
vl = TabType::setvl(len - i);
auto vec_src_re = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i), sizeof(T) * 2, vl);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_re = __riscv_vfmul(vec_src_re, re_scale, vl);
vec_src_im = __riscv_vfmul(vec_src_im, im_scale, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
else if( isInverse )
{
for( i = 0; i < len; i += vl )
{
vl = TabType::setvl(len - i);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
return CV_HAL_ERROR_OK;
}
inline int dft(const uchar* src, uchar* dst, int depth, int nf, int *factors, double scale, int* itab, void* wave,
int tab_size, int n, bool isInverse, bool noPermute)
{
if( n == 0 )
return CV_HAL_ERROR_OK;
switch( depth )
{
case CV_32F:
return dft(reinterpret_cast<const Complex<float>*>(src), reinterpret_cast<Complex<float>*>(dst), nf, factors, (float)scale,
itab, reinterpret_cast<const Complex<float>*>(wave), tab_size, n, isInverse, noPermute);
case CV_64F:
return dft(reinterpret_cast<const Complex<double>*>(src), reinterpret_cast<Complex<double>*>(dst), nf, factors, (double)scale,
itab, reinterpret_cast<const Complex<double>*>(wave), tab_size, n, isInverse, noPermute);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
}}}
#endif