OpenCv源码解析:对HAL硬件加速层的支持

OpenCV的硬件加速层全称是OpenCV Hardware Acceleration Layer (HAL),一般来说,硬件厂商或开发人员可能会根据自己的实际情况,开发出独立于OpenCV的运算函数,以支持硬件优化,加快运算速度。这些功能性模块有可能是闭源的。为了实现顺利对接,OpenCV提供了一个简单的接口模块,当各厂家需要开发自己的运算模块时,只要实现这些接口即可。

根据【1】,OpenCV能用构建三种不同的模式

(1)无HAL支持模式。在这种情况下,默认采用OpenCv的函数实现;

(2)用静态链接的HAL。OpenCV会调用这些HAL提供的加速运算的函数。

(3)动态加载的HAL支持。OpenCV 会在运行时加载这些HAL模块,如果失败,就会调用默认的OpenCV中的函数实现。

OpenCV为CMake选项提供了 HAL_MODE, STATIC_HAL_INCLUDE_DIR 和STATIC_HAL_LIB选项,以方便用户选择使用模式和相应的HAL库。

可能因为版本的原因,目前的OpenCV3.4.1中给出的方案是采用内联函数的形式,也就是,如果厂家要实现这些运算,直接用自己的函数替换掉hal_replacement.hpp 即可,顾名思义,所以文件名叫replacement。我们可以在arithm.cpp文件中看到大量这样的语句,

void sub8u( const uchar* src1, size_t step1,
                   const uchar* src2, size_t step2,
                   uchar* dst, size_t step, int width, int height, void* )
{
    CALL_HAL(sub8u, cv_hal_sub8u, src1, step1, src2, step2, dst, step, width, height)
    CALL_IPP_BIN_E_21(ippiSub_8u_C1RSfs)
    (vBinOp<uchar, cv::OpSub<uchar>, IF_SIMD(VSub<uchar>)>(src1, step1, src2, step2, dst, 
        step, width, height));
}

其中CALL_HAL是一个宏定义,如下

#define CALL_HAL(name, fun, ...) \
{ \
    int res = __CV_EXPAND(fun(__VA_ARGS__)); \
    if (res == CV_HAL_ERROR_OK) \
        return; \
    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
        CV_Error_(cv::Error::StsInternal, \
            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \
}

在运行sub8u运行时,这个宏先得到运行,此时CALL_HALL中的fun函数,就是cv_hal_sub8u,它在hal_replacement中是这样定义的,

#define cv_hal_sub8u hal_ni_sub8u
inline int hal_ni_sub8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, 
    size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) 
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }

注意当没有提供HAL的实现函数时,默认的cv_hal_sub8u的返回值是CV_HAL_ERROR_NOT_IMPLEMENTED。当然,如果有提供HAL的实现函数,根据CALL_HAL这个宏,返回值必然需要是CV_HAL_ERROR_OK。

所以,这句

if (res == CV_HAL_ERROR_OK) 
    return; 
else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) 
    CV_Error…

的意思是,如果有提供HAL的实现函数并返回CV_HAL_ERROR_OK, 就直接退出(指退出void sub8u(…)这个函数);如果没有提供HAL的实现函数,此时cv_hal_sub8u必然返回CV_HAL_ERROR_NOT_IMPLEMENTED(否则报错)。

我们看到hal_ni_sub8u返回的就是CV_HAL_ERROR_NOT_IMPLEMENTED,所以接下来,OpenCV会采用默认的

 (vBinOp<uchar, cv::OpSub<uchar>, IF_SIMD(VSub<uchar>)>(src1, step1, src2, step2, dst, step, width, height));

来执行sub8u的计算。

OpenCV就是通过这种方式,实现对HAL硬件层的支持的。

 

【1】 https://github.com/jet47/opencv-hal-proposal

posted @ 2018-08-12 15:25  SpaceVision  阅读(137)  评论(0编辑  收藏  举报