Repository: opencv/opencv
File: hal/riscv-rvv/src/features2d/fast.cpp (C++)

Code before:
    uint8_t result = (uint8_t)__riscv_vmv_x(res);
    return result - 1;
}


inline int fast_16(const uchar* src_data, size_t src_step, int width, int height, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression) 
{

    const int patternSize = 16;
    const int K = patternSize/2, N = patternSize + K + 1;
    const int quarterPatternSize = patternSize/4;

    int i, j, k;
    int16_t pixel[25];
    vuint16m2_t v_offset;
    makeOffsets(pixel, v_offset, (int)src_step, patternSize);

    uchar* buf[3] = { 0 };
    int* cpbuf[3] = { 0 };
    utils::BufferArea area;
    for (unsigned idx = 0; idx < 3; ++idx)
    {
        area.allocate(buf[idx], width);
        area.allocate(cpbuf[idx], width + 1);
    }
    area.commit();

    for (unsigned idx = 0; idx < 3; ++idx)
    {
        memset(buf[idx], 0, width);
    }

    int vlmax = __riscv_vsetvlmax_e8m4 ();
    vuint8m4_t v_c_delta = __riscv_vmv_v_x_u8m4(0x80, vlmax);
    vuint8m4_t v_c_threshold = __riscv_vmv_v_x_u8m4((char) threshold, vlmax);
    vuint8m4_t v_c_k = __riscv_vmv_v_x_u8m4((uint8_t)K, vlmax);
    vuint8m4_t v_c_zero = __riscv_vmv_v_x_u8m4(0, vlmax);

    for( i = 3; i < height - 2; i++)
    {

        const uchar* ptr = src_data + i * src_step + 3;
        uchar* curr = buf[(i - 3)%3];
        int* cornerpos = cpbuf[(i - 3)%3] + 1;
        memset(curr, 0, width);
        int ncorners = 0;

        if( i < height - 3 )
        {
            j = 3;
            {

Review comment (suggestion):
I suspect that you can also use `std::vector` as buffer container just like carotene does.

Code after:

        if( i < height - 3 )
        {
            j = 3;
            {
                int margin = width - 3;
                int vl = __riscv_vsetvl_e8m4(margin - j);
                for (; j < margin; j += vl, ptr += vl)
                {
                    vl = __riscv_vsetvl_e8m4(margin - j);
                    vuint8m4_t v_pixels = __riscv_vle8_v_u8m4(ptr, vl);
                    // pixels add threshold
                    vuint8m4_t v_pat = __riscv_vsaddu(v_pixels, v_c_threshold, vl);
                    // pixels sub threshold
                    vuint8m4_t v_pst = __riscv_vssubu(v_pixels, v_c_threshold, vl);
                    vint8m4_t v0 = __riscv_vreinterpret_i8m4(__riscv_vxor(v_pat, v_c_delta, vl));
                    vint8m4_t v1 = __riscv_vreinterpret_i8m4(__riscv_vxor(v_pst, v_c_delta, vl));

                    v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[0], vl);
                    vint8m4_t x0 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
                    v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[quarterPatternSize], vl);
                    vint8m4_t x1 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
                    v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[2*quarterPatternSize], vl);
                    vint8m4_t x2 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
                    v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[3*quarterPatternSize], vl);
                    vint8m4_t x3 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));

                    vbool2_t m0, m1;
                    m0 = __riscv_vmand(__riscv_vmslt(v0, x0, vl), __riscv_vmslt(v0, x1, vl), vl);
                    m1 = __riscv_vmand(__riscv_vmslt(x0, v1, vl), __riscv_vmslt(x1, v1, vl), vl);
                    m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x1, vl), __riscv_vmslt(v0, x2, vl), vl), vl);
                    m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x1, v1, vl), __riscv_vmslt(x2, v1, vl), vl), vl);
                    m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x2, vl), __riscv_vmslt(v0, x3, vl), vl), vl);
                    m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x2, v1, vl), __riscv_vmslt(x3, v1, vl), vl), vl);
                    m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x3, vl), __riscv_vmslt(v0, x0, vl), vl), vl);
                    m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x3, v1, vl), __riscv_vmslt(x0, v1, vl), vl), vl);
                    m0 = __riscv_vmor(m0, m1, vl);

                    unsigned long mask_cnt = __riscv_vcpop(m0, vl);
                    if(!mask_cnt)
                        continue;

                    // TODO: Test if skipping to the first possible key point pixel if faster
                    // Memory access maybe expensive since the data is not aligned
                    // long first_set = __riscv_vfirst(m0, vl);
                    // if( first_set == -1 ) {
                    //     j -= first_set;
                    //     ptr -= first_set;
                    // }

                    vuint8m4_t c0 = __riscv_vmv_v_x_u8m4(0, vl);