From 39fbe07189c6a3dd137e807b761f7cf27cb50a4c Mon Sep 17 00:00:00 2001 From: Zhang Jinhan Date: Thu, 10 Sep 2026 13:38:10 +0800 Subject: [PATCH] core:rvv: add 32F to 16S convertScale HAL Add an RVV HAL implementation for CV_32F to CV_16S conversion. The RISC-V convertScale HAL already handles several source/destination depth combinations, but CV_32F to CV_16S currently returns CV_HAL_ERROR_NOT_IMPLEMENTED and falls back to the generic core path. Implement the missing conversion using native RVV intrinsics. The identity-scale case skips the multiply-add, while scaled conversions apply alpha and beta before narrowing to signed 16-bit output. The implementation is VLEN-agnostic and uses vsetvl for tail handling. Functional test: ```text ./build-rvv/bin/opencv_test_core \ --gtest_filter='*ConvertScale*' ``` Performance was measured with opencv_perf_core on SpacemiT K3 (RVV 1.0, VLEN=256), comparing against an unmodified 5.x baseline. CV_32F -> CV_16S median time: ```text 1920x1080 C1, alpha=1: 26.16 ms -> 1.46 ms (17.92x) 1920x1080 C1, alpha=1/255: 24.10 ms -> 1.45 ms (16.62x) 1920x1080 C4, alpha=1: 103.76 ms -> 6.06 ms (17.12x) 1920x1080 C4, alpha=1/255: 96.03 ms -> 5.68 ms (16.91x) ``` All four corresponding opencv_perf_core cases pass. Co-authored-by: Yang Wang [yangwang@iscas.ac.cn](mailto:yangwang@iscas.ac.cn) Co-authored-by: Yuansheng [yuansheng@iscas.ac.cn](mailto:yuansheng@iscas.ac.cn) --- hal/riscv-rvv/src/core/convert_scale.cpp | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/hal/riscv-rvv/src/core/convert_scale.cpp b/hal/riscv-rvv/src/core/convert_scale.cpp index 003bf40a32..12317df08e 100644 --- a/hal/riscv-rvv/src/core/convert_scale.cpp +++ b/hal/riscv-rvv/src/core/convert_scale.cpp @@ -293,6 +293,76 @@ inline int convertScale_32F32F(const uchar* src, size_t src_step, uchar* dst, si return CV_HAL_ERROR_OK; } +inline int convertScale_32F16S(const uchar* src, size_t src_step, + uchar* dst, size_t dst_step, + int width, int height, + double alpha, double beta) +{ + if (alpha == 1.0 && beta == 0.0) + { + for (int i = 0; i < height; i++) + { + const float* src_row = + reinterpret_cast(src + i * src_step); + + short* dst_row = + reinterpret_cast(dst + i * dst_step); + + int vl; + + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + + auto vec_src = + __riscv_vle32_v_f32m8(src_row + j, vl); + + auto vec_dst = + __riscv_vfncvt_x(vec_src, vl); + + __riscv_vse16_v_i16m4( + dst_row + j, vec_dst, vl); + } + } + + return CV_HAL_ERROR_OK; + } + + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const float* src_row = + reinterpret_cast(src + i * src_step); + + short* dst_row = + reinterpret_cast(dst + i * dst_step); + + int vl; + + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + + auto vec_src = + __riscv_vle32_v_f32m8(src_row + j, vl); + + auto vec_fma = + __riscv_vfmadd(vec_src, a, vec_b, vl); + + auto vec_dst = + __riscv_vfncvt_x(vec_fma, vl); + + __riscv_vse16_v_i16m4( + dst_row + j, vec_dst, vl); + } + } + + return CV_HAL_ERROR_OK; +} + int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, int sdepth, int ddepth, double alpha, double beta) { @@ -342,6 +412,8 @@ int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, { case CV_8U: return convertScale_32F8U(src, src_step, dst, dst_step, width, height, alpha, beta); + case CV_16S: + return convertScale_32F16S(src, src_step, dst, dst_step, width, height, alpha, beta); case CV_32F: return convertScale_32F32F(src, src_step, dst, dst_step, width, height, alpha, beta); }