Commit a011035e authored by Paul Murphy's avatar Paul Murphy Committed by Alexander Alekhin

Merge pull request #15257 from pmur:resize

* resize: HResizeLinear reduce duplicate work

There appears to be a 2x unroll of the HResizeLinear against k,
however the k value is only incremented by 1 during the unroll. This
results in k - 1 duplicate passes when k > 1.

Likewise, the final pass may not respect the work done by the vector
loop. Start it with the offset returned by the vector op if
implemented. Note, no vector ops are implemented today.

The performance is most noticable on a linear downscale. A set of
performance tests are added to characterize this.  The performance
improvement is 10-50% depending on the scaling.

* imgproc: vectorize HResizeLinear

Performance is mostly gated by the gather operations
for x inputs.

Likewise, provide a 2x unroll against k, this reduces the
number of alpha gathers by 1/2 for larger k.

While not a 4x improvement, it still performs substantially
better under P9 for a 1.4x improvement. P8 baseline is
1.05-1.10x due to reduced VSX instruction set.

For float types, this results in a more modest
1.2x improvement.

* Update U8 processing for non-bitexact linear resize

* core: hal: vsx: improve v_load_expand_q

With a little help, we can do this quickly without gprs on
all VSX enabled targets.

* resize: Fix cn == 3 step per feedback

Per feedback, ensure we don't overrun. This was caught via the
failure observed in Test_TensorFlow.inception_accuracy.
parent 734de34b
......@@ -346,11 +346,37 @@ OPENCV_HAL_IMPL_VSX_EXPAND(v_int16x8, v_int32x4, short, vec_unpackl, vec_unpackh
OPENCV_HAL_IMPL_VSX_EXPAND(v_uint32x4, v_uint64x2, uint, vec_unpacklu, vec_unpackhu)
OPENCV_HAL_IMPL_VSX_EXPAND(v_int32x4, v_int64x2, int, vec_unpackl, vec_unpackh)
/* Load and zero expand a 4 byte value into the second dword, first is don't care. */
#if !defined(CV_COMPILER_VSX_BROKEN_ASM)
#define _LXSIWZX(out, ptr, T) __asm__ ("lxsiwzx %x0, 0, %1\r\n" : "=wa"(out) : "r" (ptr) : "memory");
#else
/* This is compiler-agnostic, but will introduce an unneeded splat on the critical path. */
#define _LXSIWZX(out, ptr, T) out = (T)vec_udword2_sp(*(uint32_t*)(ptr));
#endif
inline v_uint32x4 v_load_expand_q(const uchar* ptr)
{ return v_uint32x4(vec_uint4_set(ptr[0], ptr[1], ptr[2], ptr[3])); }
{
// Zero-extend the extra 24B instead of unpacking. Usually faster in small kernel
// Likewise note, value is zero extended and upper 4 bytes are zero'ed.
vec_uchar16 pmu = {8, 12, 12, 12, 9, 12, 12, 12, 10, 12, 12, 12, 11, 12, 12, 12};
vec_uchar16 out;
_LXSIWZX(out, ptr, vec_uchar16);
out = vec_perm(out, out, pmu);
return v_uint32x4((vec_uint4)out);
}
inline v_int32x4 v_load_expand_q(const schar* ptr)
{ return v_int32x4(vec_int4_set(ptr[0], ptr[1], ptr[2], ptr[3])); }
{
vec_char16 out;
vec_short8 outs;
vec_int4 outw;
_LXSIWZX(out, ptr, vec_char16);
outs = vec_unpackl(out);
outw = vec_unpackh(outs);
return v_int32x4(outw);
}
/* pack */
#define OPENCV_HAL_IMPL_VSX_PACK(_Tpvec, _Tp, _Tpwvec, _Tpvn, _Tpdel, sfnc, pkfnc, addfnc, pack) \
......
......@@ -7,6 +7,31 @@ namespace opencv_test {
typedef tuple<MatType, Size, Size> MatInfo_Size_Size_t;
typedef TestBaseWithParam<MatInfo_Size_Size_t> MatInfo_Size_Size;
typedef tuple<Size,Size> Size_Size_t;
typedef tuple<MatType, Size_Size_t> MatInfo_SizePair_t;
typedef TestBaseWithParam<MatInfo_SizePair_t> MatInfo_SizePair;
#define MATTYPE_NE_VALUES CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, \
CV_16UC1, CV_16UC2, CV_16UC3, CV_16UC4, \
CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4
// For gradient-ish testing of the other matrix formats
template<typename T>
static void fillFPGradient(Mat& img)
{
const int ch = img.channels();
int r, c, i;
for(r=0; r<img.rows; r++)
{
for(c=0; c<img.cols; c++)
{
T vals[] = {(T)r, (T)c, (T)(r*c), (T)(r*c/(r+c+1))};
T *p = (T*)img.ptr(r, c);
for(i=0; i<ch; i++) p[i] = (T)vals[i];
}
}
}
PERF_TEST_P(MatInfo_Size_Size, resizeUpLinear,
testing::Values(
......@@ -38,6 +63,33 @@ PERF_TEST_P(MatInfo_Size_Size, resizeUpLinear,
#endif
}
PERF_TEST_P(MatInfo_SizePair, resizeUpLinearNonExact,
testing::Combine
(
testing::Values( MATTYPE_NE_VALUES ),
testing::Values( Size_Size_t(szVGA, szqHD), Size_Size_t(szVGA, sz720p) )
)
)
{
int matType = get<0>(GetParam());
Size_Size_t sizes = get<1>(GetParam());
Size from = get<0>(sizes);
Size to = get<1>(sizes);
cv::Mat src(from, matType), dst(to, matType);
switch(src.depth())
{
case CV_8U: cvtest::fillGradient(src); break;
case CV_16U: fillFPGradient<ushort>(src); break;
case CV_32F: fillFPGradient<float>(src); break;
}
declare.in(src).out(dst);
TEST_CYCLE_MULTIRUN(10) resize(src, dst, to, 0, 0, INTER_LINEAR);
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear,
testing::Values(
MatInfo_Size_Size_t(CV_8UC1, szVGA, szQVGA),
......@@ -80,6 +132,40 @@ PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear,
#endif
}
PERF_TEST_P(MatInfo_SizePair, resizeDownLinearNonExact,
testing::Combine
(
testing::Values( MATTYPE_NE_VALUES ),
testing::Values
(
Size_Size_t(szVGA, szQVGA),
Size_Size_t(szqHD, szVGA),
Size_Size_t(sz720p, Size(120 * sz720p.width / sz720p.height, 120)),
Size_Size_t(sz720p, szVGA),
Size_Size_t(sz720p, szQVGA)
)
)
)
{
int matType = get<0>(GetParam());
Size_Size_t sizes = get<1>(GetParam());
Size from = get<0>(sizes);
Size to = get<1>(sizes);
cv::Mat src(from, matType), dst(to, matType);
switch(src.depth())
{
case CV_8U: cvtest::fillGradient(src); break;
case CV_16U: fillFPGradient<ushort>(src); break;
case CV_32F: fillFPGradient<float>(src); break;
}
declare.in(src).out(dst);
TEST_CYCLE_MULTIRUN(10) resize(src, dst, to, 0, 0, INTER_LINEAR);
SANITY_CHECK_NOTHING();
}
typedef tuple<MatType, Size, int> MatInfo_Size_Scale_t;
typedef TestBaseWithParam<MatInfo_Size_Scale_t> MatInfo_Size_Scale;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment