#include <math.h>
#include <limits>
-#include <type_traits>
#include <opencv2/gapi/own/assert.hpp>
+#include <opencv2/gapi/util/type_traits.hpp>
namespace cv { namespace gapi { namespace own {
//-----------------------------
//
//-----------------------------
-template<typename DST, typename SRC>
-static inline DST saturate(SRC x)
+template<typename DST, typename SRC,
+ typename = cv::util::enable_if_t<!std::is_same<DST, SRC>::value &&
+ std::is_integral<DST>::value &&
+ std::is_integral<SRC>::value> >
+static CV_ALWAYS_INLINE DST saturate(SRC x)
{
- // only integral types please!
- GAPI_DbgAssert(std::is_integral<DST>::value &&
- std::is_integral<SRC>::value);
-
- if (std::is_same<DST, SRC>::value)
- return static_cast<DST>(x);
-
if (sizeof(DST) > sizeof(SRC))
return static_cast<DST>(x);
std::numeric_limits<DST>::max():
static_cast<DST>(x);
}
+template<typename T>
+static CV_ALWAYS_INLINE T saturate(T x)
+{
+ return x;
+}
+template<typename DST, typename SRC, typename R,
+ cv::util::enable_if_t<std::is_floating_point<DST>::value, bool> = true >
+static CV_ALWAYS_INLINE DST saturate(SRC x, R)
+{
+ return static_cast<DST>(x);
+}
+template<typename DST, typename SRC, typename R,
+ cv::util::enable_if_t<std::is_integral<DST>::value &&
+ std::is_integral<SRC>::value , bool> = true >
+static CV_ALWAYS_INLINE DST saturate(SRC x, R)
+{
+ return saturate<DST>(x);
+}
// Note, that OpenCV rounds differently:
// - like std::round() for add, subtract
// - like std::rint() for multiply, divide
-template<typename DST, typename SRC, typename R>
-static inline DST saturate(SRC x, R round)
+template<typename DST, typename SRC, typename R,
+ cv::util::enable_if_t<std::is_integral<DST>::value &&
+ std::is_floating_point<SRC>::value, bool> = true >
+static CV_ALWAYS_INLINE DST saturate(SRC x, R round)
{
- if (std::is_floating_point<DST>::value)
- {
- return static_cast<DST>(x);
- }
- else if (std::is_integral<SRC>::value)
- {
- GAPI_DbgAssert(std::is_integral<DST>::value &&
- std::is_integral<SRC>::value);
- return saturate<DST>(x);
- }
- else
- {
- GAPI_DbgAssert(std::is_integral<DST>::value &&
- std::is_floating_point<SRC>::value);
-#ifdef _WIN32
-// Suppress warning about converting x to floating-point
-// Note that x is already floating-point at this point
-#pragma warning(disable: 4244)
-#endif
- int ix = static_cast<int>(round(x));
-#ifdef _WIN32
-#pragma warning(default: 4244)
-#endif
- return saturate<DST>(ix);
- }
+ int ix = static_cast<int>(round(x));
+ return saturate<DST>(ix);
}
// explicit suffix 'd' for double type
//
//-------------------------
+#if CV_SIMD128
+template<typename DST, typename SRC>
+CV_ALWAYS_INLINE int run_convertto_simd(DST*, const SRC*, int)
+{
+ return 0;
+}
+CV_ALWAYS_INLINE int run_convertto_simd(uchar *out, const float *in, const int length)
+{
+ int l = 0;
+ for (; l <= length - 16; l += 16)
+ {
+ v_int32x4 i0, i1, i2, i3;
+ i0 = v_round( v_load( (float*)& in[l ] ) );
+ i1 = v_round( v_load( (float*)& in[l + 4] ) );
+ i2 = v_round( v_load( (float*)& in[l + 8] ) );
+ i3 = v_round( v_load( (float*)& in[l + 12] ) );
+
+ v_uint16x8 us0, us1;
+ us0 = v_pack_u(i0, i1);
+ us1 = v_pack_u(i2, i3);
+
+ v_uint8x16 uc;
+ uc = v_pack(us0, us1);
+ v_store((uchar*)& out[l], uc);
+ }
+ return l;
+}
+CV_ALWAYS_INLINE int run_convertto_simd(ushort *out, const float *in, const int length)
+{
+ int l = 0;
+ for (; l <= length - 8; l += 8)
+ {
+ v_int32x4 i0, i1;
+ i0 = v_round( v_load( (float*)& in[l ] ) );
+ i1 = v_round( v_load( (float*)& in[l + 4] ) );
+
+ v_uint16x8 us;
+ us = v_pack_u(i0, i1);
+ v_store((ushort*)& out[l], us);
+ }
+ return l;
+}
+#endif
+
+template<typename DST, typename SRC,
+ cv::util::enable_if_t<std::is_integral<DST>::value &&
+ std::is_floating_point<SRC>::value, bool> = true >
+CV_ALWAYS_INLINE void run_convertto(DST *out, const SRC *in, const int length)
+{
+ // manual SIMD if need rounding
+ static_assert(std::is_same<SRC,float>::value, "64-bit floating-point source is not supported");
+ int l = 0; // cycle index
+#if CV_SIMD128
+ l = run_convertto_simd(out, in, length);
+#endif
+ // tail of SIMD cycle
+ for (; l < length; l++)
+ {
+ out[l] = saturate<DST>(in[l], rintf);
+ }
+}
+template<typename DST, typename SRC,
+ cv::util::enable_if_t<std::is_integral<DST>::value &&
+ std::is_integral<SRC>::value , bool> = true >
+CV_ALWAYS_INLINE void run_convertto(DST *out, const SRC *in, const int length)
+{
+ for (int l = 0; l < length; l++)
+ {
+ out[l] = saturate<DST>(in[l]);
+ }
+}
+template<typename DST, typename SRC,
+ cv::util::enable_if_t<std::is_floating_point<DST>::value, bool> = true >
+CV_ALWAYS_INLINE void run_convertto(DST *out, const SRC *in, const int length)
+{
+ static_assert(!std::is_same<SRC,double>::value, "64-bit floating-point source is not supported");
+ for (int l = 0; l < length; l++)
+ {
+ out[l] = static_cast<DST>(in[l]);
+ }
+}
+
+template<typename DST, typename SRC>
+CV_ALWAYS_INLINE void run_convertto(DST *out, const SRC *in, const float alpha, const float beta,
+ const int length)
+{
+ static_assert(!std::is_same<SRC,double>::value, "64-bit floating-point source is not supported");
+ // TODO: optimize if alpha and beta and data are integral
+ for (int l = 0; l < length; l++)
+ {
+ out[l] = saturate<DST>(in[l] * alpha + beta, rintf);
+ }
+}
+
template<typename DST, typename SRC>
static void run_convertto(Buffer &dst, const View &src, double _alpha, double _beta)
{
const auto *in = src.InLine<SRC>(0);
auto *out = dst.OutLine<DST>();
- int width = dst.length();
- int chan = dst.meta().chan;
- int length = width * chan;
+ const int width = dst.length();
+ const int chan = dst.meta().chan;
+ const int length = width * chan;
// NB: don't do this if SRC or DST is 64-bit
- auto alpha = static_cast<float>( _alpha );
- auto beta = static_cast<float>( _beta );
+ const auto alpha = static_cast<float>( _alpha );
+ const auto beta = static_cast<float>( _beta );
// compute faster if no alpha no beta
- if (alpha == 1 && beta == 0)
+ if (1.f == alpha && 0.f == beta)
{
- // manual SIMD if need rounding
- if (std::is_integral<DST>::value && std::is_floating_point<SRC>::value)
- {
- GAPI_Assert(( std::is_same<SRC,float>::value ));
-
- int l = 0; // cycle index
-
- #if CV_SIMD128
- if (std::is_same<DST,uchar>::value)
- {
- for (; l <= length-16; l+=16)
- {
- v_int32x4 i0, i1, i2, i3;
- i0 = v_round( v_load( (float*)& in[l ] ) );
- i1 = v_round( v_load( (float*)& in[l + 4] ) );
- i2 = v_round( v_load( (float*)& in[l + 8] ) );
- i3 = v_round( v_load( (float*)& in[l + 12] ) );
-
- v_uint16x8 us0, us1;
- us0 = v_pack_u(i0, i1);
- us1 = v_pack_u(i2, i3);
-
- v_uint8x16 uc;
- uc = v_pack(us0, us1);
- v_store((uchar*)& out[l], uc);
- }
- }
- if (std::is_same<DST,ushort>::value)
- {
- for (; l <= length-8; l+=8)
- {
- v_int32x4 i0, i1;
- i0 = v_round( v_load( (float*)& in[l ] ) );
- i1 = v_round( v_load( (float*)& in[l + 4] ) );
-
- v_uint16x8 us;
- us = v_pack_u(i0, i1);
- v_store((ushort*)& out[l], us);
- }
- }
- #endif
-
- // tail of SIMD cycle
- for (; l < length; l++)
- {
- out[l] = saturate<DST>(in[l], rintf);
- }
- }
- else if (std::is_integral<DST>::value) // here SRC is integral
- {
- for (int l=0; l < length; l++)
- {
- out[l] = saturate<DST>(in[l]);
- }
- }
- else // DST is floating-point, SRC is any
- {
- for (int l=0; l < length; l++)
- {
- out[l] = static_cast<DST>(in[l]);
- }
- }
+ run_convertto(out, in, length);
}
else // if alpha or beta is non-trivial
{
- // TODO: optimize if alpha and beta and data are integral
- for (int l=0; l < length; l++)
- {
- out[l] = saturate<DST>(in[l]*alpha + beta, rintf);
- }
+ run_convertto(out, in, alpha, beta, length);
}
}