From 55fdef85811954bca1ff7f933cbebde0eb6d54e8 Mon Sep 17 00:00:00 2001 From: velonica0 Date: Tue, 28 Jul 2026 00:55:01 -0700 Subject: [PATCH] dnn:rvv: implement RVV HAL kernels for max and average pooling --- hal/riscv-rvv/CMakeLists.txt | 7 +-- hal/riscv-rvv/include/dnn.hpp | 27 ++++++----- hal/riscv-rvv/src/dnn/pooling.cpp | 77 +++++++++++-------------------- 3 files changed, 44 insertions(+), 67 deletions(-) diff --git a/hal/riscv-rvv/CMakeLists.txt b/hal/riscv-rvv/CMakeLists.txt index aa8751e76a..82cbcbb4c6 100644 --- a/hal/riscv-rvv/CMakeLists.txt +++ b/hal/riscv-rvv/CMakeLists.txt @@ -18,12 +18,7 @@ target_include_directories(${HAL_LIB_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/modules/core/include ${CMAKE_SOURCE_DIR}/modules/imgproc/include - ${CMAKE_SOURCE_DIR}/modules/features/include - ${CMAKE_SOURCE_DIR}/modules/dnn/include - # dnn's internal ConvState descriptor (src/layers/conv2_common.hpp) crosses the - # HAL boundary as an opaque pointer; the dnn kernels cast it back here. See the - # "descriptor ABI" discussion in the DNN HAL proposal. - ${CMAKE_SOURCE_DIR}/modules/dnn/src) + ${CMAKE_SOURCE_DIR}/modules/features/include) set(RVV_HAL_FOUND TRUE CACHE INTERNAL "") set(RVV_HAL_VERSION "0.0.1" CACHE INTERNAL "") diff --git a/hal/riscv-rvv/include/dnn.hpp b/hal/riscv-rvv/include/dnn.hpp index 4afccbb3df..f5776c7e83 100644 --- a/hal/riscv-rvv/include/dnn.hpp +++ b/hal/riscv-rvv/include/dnn.hpp @@ -9,27 +9,30 @@ namespace cv { namespace rvv_hal { namespace dnn { #if CV_HAL_RVV_1P0_ENABLED -// `state` is an opaque pointer to the DNN engine's cv::dnn::ConvState descriptor. -// It is passed as const void* on purpose: this header is pulled into every module -// through the generated custom_hal.hpp, so it must not depend on internal dnn -// headers. The implementations in src/dnn/ include conv2_common.hpp and cast back. -// -// Each hook computes only the block-plane range [task_start, task_end) of the -// output tensor (blocked NCHWc, N*C1 planes of C0 channels); OpenCV owns the -// parallel_for_ and never expects the HAL to spawn threads. +// Blocked NCHWc pooling, CV_32F. The geometry crosses the boundary as a flat, stable +// C argument list (no dnn types): C0 channel block; insize/outsize = the [3] input/output +// spatial dims in a fixed Z,Y,X frame (unused leading dims = 1); strides[3]; pads[6] +// (begin[0..2]+end[3..5]); inner[6] = the padding-free interior bounds; coordtab[ksize*3] +// = per-tap (dz,dy,dx); ofstab[ksize] = per-tap flat input offset for the interior. +// Each hook computes only the block-plane range [task_start, task_end) (N*C1 planes); +// OpenCV owns the parallel_for_ and never expects the HAL to spawn threads. /* ############ maxpool32f ############ */ -int maxpool32f(const float* inp_data, float* out_data, - const void* state, int task_start, int task_end); +int maxpool32f(const float* inp_data, float* out_data, int C0, + const int* insize, const int* outsize, const int* strides, + const int* pads, const int* inner, const int* coordtab, + const int* ofstab, int ksize, int task_start, int task_end); #undef cv_hal_dnn_maxpool32f #define cv_hal_dnn_maxpool32f cv::rvv_hal::dnn::maxpool32f /* ############ avgpool32f ############ */ -int avgpool32f(const float* inp_data, float* out_data, - const void* state, int count_include_pad, +int avgpool32f(const float* inp_data, float* out_data, int C0, + const int* insize, const int* outsize, const int* strides, + const int* pads, const int* inner, const int* coordtab, + const int* ofstab, int ksize, int count_include_pad, int task_start, int task_end); #undef cv_hal_dnn_avgpool32f diff --git a/hal/riscv-rvv/src/dnn/pooling.cpp b/hal/riscv-rvv/src/dnn/pooling.cpp index 847a462c5e..69187cb625 100644 --- a/hal/riscv-rvv/src/dnn/pooling.cpp +++ b/hal/riscv-rvv/src/dnn/pooling.cpp @@ -6,7 +6,6 @@ #if CV_HAL_RVV_1P0_ENABLED #include -#include "layers/conv2_common.hpp" // cv::dnn::ConvState (opaque across the HAL boundary) #endif namespace cv { namespace rvv_hal { namespace dnn { @@ -30,32 +29,22 @@ namespace cv { namespace rvv_hal { namespace dnn { // * stride-x > 1: pixels' tap data are strided; we fall back to processing C0 // channels per vector, register-blocked 4 output columns at a time for ILP. -int maxpool32f(const float* inp_data, float* out_data, - const void* state, int task_start, int task_end) +int maxpool32f(const float* inp_data, float* out_data, int C0, + const int* insize, const int* outsize, const int* strides, + const int* pads, const int* inner, const int* coordtab, + const int* ofstab, int ksize, int task_start, int task_end) { - const cv::dnn::ConvState* cs = static_cast(state); - constexpr int MAX_POOL_DIMS = cv::dnn::ConvState::MAX_CONV_DIMS; - if (cs->nspatialdims > MAX_POOL_DIMS) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - - const int sdims = cs->nspatialdims; - const int C0 = cs->inpshape.back(); - const int Di = sdims > 2 ? cs->inpshape[sdims - 1] : 1; - const int Hi = sdims > 1 ? cs->inpshape[sdims] : 1; - const int Wi = cs->inpshape[sdims + 1]; - const int D = sdims > 2 ? cs->outshape[sdims - 1] : 1; - const int H = sdims > 1 ? cs->outshape[sdims] : 1; - const int W = cs->outshape[sdims + 1]; + constexpr int MAX_POOL_DIMS = 3; // coordtab/pads/inner use a fixed Z,Y,X frame + const int Di = insize[0], Hi = insize[1], Wi = insize[2]; + const int D = outsize[0], H = outsize[1], W = outsize[2]; const int64_t iplanesize = (int64_t)Di*Hi*Wi*C0; const int64_t planesize = (int64_t)D*H*W*C0; - const int SZ = cs->strides[0], SY = cs->strides[1], SX = cs->strides[2]; - const int padZ0 = cs->pads[0], padY0 = cs->pads[1], padX0 = cs->pads[2]; - const int inner_z0 = cs->inner[0], inner_z1 = cs->inner[MAX_POOL_DIMS]; - const int inner_y0 = cs->inner[1], inner_y1 = cs->inner[MAX_POOL_DIMS + 1]; - const int inner_x0 = cs->inner[2], inner_x1 = cs->inner[MAX_POOL_DIMS + 2]; - const int ksize = (int)cs->ofstab.size(); - const int* zyxtab = cs->coordtab.data(); - const int* ofstab = cs->ofstab.data(); + const int SZ = strides[0], SY = strides[1], SX = strides[2]; + const int padZ0 = pads[0], padY0 = pads[1], padX0 = pads[2]; + const int inner_z0 = inner[0], inner_z1 = inner[MAX_POOL_DIMS]; + const int inner_y0 = inner[1], inner_y1 = inner[MAX_POOL_DIMS + 1]; + const int inner_x0 = inner[2], inner_x1 = inner[MAX_POOL_DIMS + 2]; + const int* zyxtab = coordtab; for (int nc = task_start; nc < task_end; nc++) { const float* inp = inp_data + nc * iplanesize; @@ -159,35 +148,25 @@ int maxpool32f(const float* inp_data, float* out_data, return CV_HAL_ERROR_OK; } -int avgpool32f(const float* inp_data, float* out_data, - const void* state, int count_include_pad, +int avgpool32f(const float* inp_data, float* out_data, int C0, + const int* insize, const int* outsize, const int* strides, + const int* pads, const int* inner, const int* coordtab, + const int* ofstab, int ksize, int count_include_pad, int task_start, int task_end) { - const cv::dnn::ConvState* cs = static_cast(state); - constexpr int MAX_POOL_DIMS = cv::dnn::ConvState::MAX_CONV_DIMS; - if (cs->nspatialdims > MAX_POOL_DIMS) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - - const int sdims = cs->nspatialdims; - const int C0 = cs->inpshape.back(); - const int Di = sdims > 2 ? cs->inpshape[sdims - 1] : 1; - const int Hi = sdims > 1 ? cs->inpshape[sdims] : 1; - const int Wi = cs->inpshape[sdims + 1]; - const int D = sdims > 2 ? cs->outshape[sdims - 1] : 1; - const int H = sdims > 1 ? cs->outshape[sdims] : 1; - const int W = cs->outshape[sdims + 1]; + constexpr int MAX_POOL_DIMS = 3; // coordtab/pads/inner use a fixed Z,Y,X frame + const int Di = insize[0], Hi = insize[1], Wi = insize[2]; + const int D = outsize[0], H = outsize[1], W = outsize[2]; const int64_t iplanesize = (int64_t)Di*Hi*Wi*C0; const int64_t planesize = (int64_t)D*H*W*C0; - const int SZ = cs->strides[0], SY = cs->strides[1], SX = cs->strides[2]; - const int padZ0 = cs->pads[0], padY0 = cs->pads[1], padX0 = cs->pads[2]; - const int padZ1 = cs->pads[MAX_POOL_DIMS], padY1 = cs->pads[MAX_POOL_DIMS + 1], - padX1 = cs->pads[MAX_POOL_DIMS + 2]; - const int inner_z0 = cs->inner[0], inner_z1 = cs->inner[MAX_POOL_DIMS]; - const int inner_y0 = cs->inner[1], inner_y1 = cs->inner[MAX_POOL_DIMS + 1]; - const int inner_x0 = cs->inner[2], inner_x1 = cs->inner[MAX_POOL_DIMS + 2]; - const int ksize = (int)cs->ofstab.size(); - const int* zyxtab = cs->coordtab.data(); - const int* ofstab = cs->ofstab.data(); + const int SZ = strides[0], SY = strides[1], SX = strides[2]; + const int padZ0 = pads[0], padY0 = pads[1], padX0 = pads[2]; + const int padZ1 = pads[MAX_POOL_DIMS], padY1 = pads[MAX_POOL_DIMS + 1], + padX1 = pads[MAX_POOL_DIMS + 2]; + const int inner_z0 = inner[0], inner_z1 = inner[MAX_POOL_DIMS]; + const int inner_y0 = inner[1], inner_y1 = inner[MAX_POOL_DIMS + 1]; + const int inner_x0 = inner[2], inner_x1 = inner[MAX_POOL_DIMS + 2]; + const int* zyxtab = coordtab; const float iksize = 1.f/ksize; // interior has no padding: denom == ksize either way for (int nc = task_start; nc < task_end; nc++) {