From feaa10ca9d10b84a929013f1dcf908e313c710b9 Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Fri, 18 Sep 2026 15:19:08 +0200 Subject: [PATCH] Add compile-time fast paths for _InputArray/_OutputArray Add inline fast paths in mat.inl.hpp guarded by CV_IS_COMPILE_TIME_CONSTANT(flags) When `flags` is known at compile time (e.g. after inlining or under LTO/ThinLTO), the compiler folds away the kind switch and directly accesses the underlying cv::Mat / Matx / std::vector / noArray(), falling back to out-of-line `*_` helpers when `flags` is dynamic so non-LTO builds incur zero binary size bloat. As an example, I tweaked cv::resize: - Evaluate `if (condition)` before entering `try { if (cv::ocl::isOpenCLActivated() ...)` in CV_OCL_RUN_ (ocl_defs.hpp), avoiding OpenCL activation checks and try/catch overhead when `condition` is false. - use InputArray functions in cv::resize for constant folding --- modules/core/include/opencv2/core/mat.hpp | 13 ++ modules/core/include/opencv2/core/mat.inl.hpp | 116 +++++++++++++++++- .../include/opencv2/core/opencl/ocl_defs.hpp | 29 +++-- modules/core/src/matrix_wrap.cpp | 37 ++---- modules/imgproc/src/resize.cpp | 4 +- modules/video/src/optflowgf.cpp | 2 +- 6 files changed, 157 insertions(+), 44 deletions(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 8a75fee675..ef76141430 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -378,6 +378,15 @@ protected: void init(int _flags, const void* _obj); void init(int _flags, const void* _obj, Size _sz); + +private: + int dims_(int i=-1) const; + int cols_(int i=-1) const; + int rows_(int i=-1) const; + Size size_(int i=-1) const; + int type_(int i=-1) const; + int depth_(int i=-1) const; + bool empty_() const; }; CV_ENUM_FLAGS(_InputArray::KindFlag) __CV_ENUM_FLAGS_BITWISE_AND(_InputArray::KindFlag, int, _InputArray::KindFlag) @@ -520,6 +529,10 @@ public: void move(UMat& u) const; void move(Mat& m) const; + +private: + void create_(Size sz, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; + void create_(int rows, int cols, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; }; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index b9eebb5080..4b6d067be6 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -158,6 +158,9 @@ inline void _InputArray::init(int _flags, const void* _obj, Size _sz) { flags = _flags; obj = (void*)_obj; sz = _sz; } inline void* _InputArray::getObj() const { return obj; } +inline _InputArray::KindFlag _InputArray::kind() const { + return static_cast(flags & KIND_MASK); +} inline int _InputArray::getFlags() const { return flags; } inline Size _InputArray::getSz() const { return sz; } @@ -249,13 +252,94 @@ _InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr) inline _InputArray::~_InputArray() {} +#if defined(__GNUC__) || defined(__clang__) +# define CV_IS_COMPILE_TIME_CONSTANT(x) __builtin_constant_p(x) +#else +# define CV_IS_COMPILE_TIME_CONSTANT(x) 0 +#endif + inline Mat _InputArray::getMat(int i) const { - if( kind() == MAT && i < 0 ) - return *(const Mat*)obj; + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) + return *static_cast(getObj()); + if (k == MATX) + return Mat(sz, flags, getObj()); + if (k == NONE) + return Mat(); + } return getMat_(i); } +inline int _InputArray::depth(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + if (flags & FIXED_TYPE) return CV_MAT_DEPTH(flags); + if ((flags & KIND_MASK) == MAT) + return static_cast(getObj())->depth(); + } + return depth_(i); +} + +inline int _InputArray::type(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + if (flags & FIXED_TYPE) return CV_MAT_TYPE(flags); + if ((flags & KIND_MASK) == MAT) + return static_cast(getObj())->type(); + } + return type_(i); +} + +inline int _InputArray::channels(int i) const { return CV_MAT_CN(type(i)); } + +inline bool _InputArray::empty() const { + if (CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) return static_cast(getObj())->empty(); + if (k == MATX) return false; + if (k == STD_VECTOR) + return static_cast*>(getObj())->empty(); + if (k == NONE) return true; + } + return empty_(); +} + +inline int _InputArray::dims(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) return static_cast(getObj())->dims; + if (k == MATX || k == STD_VECTOR) return 2; + } + return dims_(i); +} + +inline int _InputArray::rows(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) return static_cast(getObj())->rows; + if (k == MATX) return sz.height; + } + return rows_(i); +} + +inline int _InputArray::cols(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) return static_cast(getObj())->cols; + if (k == MATX) return sz.width; + } + return cols_(i); +} + +inline Size _InputArray::size(int i) const { + if (i < 0 && CV_IS_COMPILE_TIME_CONSTANT(flags)) { + const int k = flags & KIND_MASK; + if (k == MAT) return static_cast(getObj())->size(); + if (k == MATX) return sz; + } + return size_(i); +} + inline bool _InputArray::isMat() const { return kind() == _InputArray::MAT; } inline bool _InputArray::isUMat() const { return kind() == _InputArray::UMAT; } inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; } @@ -428,6 +512,34 @@ std::vector >& _OutputArray::getVecVecRef() const return *(std::vector >*)obj; } +inline void _OutputArray::create(Size _sz, int _type, int i, + bool allowTransposed, + _OutputArray::DepthMask fixedDepthMask) const { + if (i < 0 && !allowTransposed && fixedDepthMask == 0 && + CV_IS_COMPILE_TIME_CONSTANT(flags)) { + if ((flags & (KIND_MASK | FIXED_SIZE | FIXED_TYPE)) == MAT) { + static_cast(getObj())->create(_sz, _type); + return; + } + } + create_(_sz, _type, i, allowTransposed, fixedDepthMask); +} + +inline void _OutputArray::create(int _rows, int _cols, int _type, int i, + bool allowTransposed, + _OutputArray::DepthMask fixedDepthMask) const { + if (i < 0 && !allowTransposed && fixedDepthMask == 0 && + CV_IS_COMPILE_TIME_CONSTANT(flags)) { + if ((flags & (KIND_MASK | FIXED_SIZE | FIXED_TYPE)) == MAT) { + static_cast(getObj())->create(_rows, _cols, _type); + return; + } + } + create_(_rows, _cols, _type, i, allowTransposed, fixedDepthMask); +} + +#undef CV_IS_COMPILE_TIME_CONSTANT + /////////////////////////////////////////////////////////////////////////////////////////// inline _InputOutputArray::_InputOutputArray() { init(0+ACCESS_RW, 0); } diff --git a/modules/core/include/opencv2/core/opencl/ocl_defs.hpp b/modules/core/include/opencv2/core/opencl/ocl_defs.hpp index a2b7337662..1d5c0d8c7c 100644 --- a/modules/core/include/opencv2/core/opencl/ocl_defs.hpp +++ b/modules/core/include/opencv2/core/opencl/ocl_defs.hpp @@ -28,7 +28,7 @@ inline bool isOpenCLActivated() { return false; } #ifdef CV_OPENCL_RUN_VERBOSE #define CV_OCL_RUN_(condition, func, ...) \ { \ - if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + if ((condition) && cv::ocl::isOpenCLActivated() && func) \ { \ printf("%s: OpenCL implementation is running\n", CV_Func); \ fflush(stdout); \ @@ -44,7 +44,7 @@ inline bool isOpenCLActivated() { return false; } #elif defined CV_OPENCL_RUN_ASSERT #define CV_OCL_RUN_(condition, func, ...) \ { \ - if (cv::ocl::isOpenCLActivated() && (condition)) \ + if ((condition) && cv::ocl::isOpenCLActivated()) \ { \ if(func) \ { \ @@ -59,18 +59,21 @@ inline bool isOpenCLActivated() { return false; } } #else #define CV_OCL_RUN_(condition, func, ...) \ -try \ -{ \ - if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + if (condition) \ { \ - CV_IMPL_ADD(CV_IMPL_OCL); \ - return __VA_ARGS__; \ - } \ -} \ -catch (const cv::Exception& e) \ -{ \ - CV_UNUSED(e); /* TODO: Add some logging here */ \ -} + try \ + { \ + if (cv::ocl::isOpenCLActivated() && func) \ + { \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + return __VA_ARGS__; \ + } \ + } \ + catch (const cv::Exception& e) \ + { \ + CV_UNUSED(e); /* TODO: Add some logging here */ \ + } \ + } #endif #else diff --git a/modules/core/src/matrix_wrap.cpp b/modules/core/src/matrix_wrap.cpp index e7362196c5..c0fee242fd 100644 --- a/modules/core/src/matrix_wrap.cpp +++ b/modules/core/src/matrix_wrap.cpp @@ -462,17 +462,7 @@ ogl::Buffer _InputArray::getOGlBuffer() const return *gl_buf; } -_InputArray::KindFlag _InputArray::kind() const -{ - KindFlag k = flags & KIND_MASK; -#if CV_VERSION_MAJOR < 5 - CV_DbgAssert(k != EXPR); - CV_DbgAssert(k != STD_ARRAY); -#endif - return k; -} - -int _InputArray::rows(int i) const +int _InputArray::rows_(int i) const { #ifdef HAVE_CUDA _InputArray::KindFlag k = kind(); @@ -483,10 +473,10 @@ int _InputArray::rows(int i) const } #endif - return size(i).height; + return size_(i).height; } -int _InputArray::cols(int i) const +int _InputArray::cols_(int i) const { #ifdef HAVE_CUDA _InputArray::KindFlag k = kind(); @@ -497,10 +487,10 @@ int _InputArray::cols(int i) const } #endif - return size(i).width; + return size_(i).width; } -Size _InputArray::size(int i) const +Size _InputArray::size_(int i) const { _InputArray::KindFlag k = kind(); @@ -832,7 +822,7 @@ bool _InputArray::sameSize(const _InputArray& arr) const return sz1 == arr.size(); } -int _InputArray::dims(int i) const +int _InputArray::dims_(int i) const { _InputArray::KindFlag k = kind(); @@ -1011,7 +1001,7 @@ size_t _InputArray::total(int i) const return size(i).area(); } -int _InputArray::type(int i) const +int _InputArray::type_(int i) const { _InputArray::KindFlag k = kind(); @@ -1110,17 +1100,12 @@ int _InputArray::type(int i) const CV_Error(Error::StsNotImplemented, "Unknown/unsupported array type"); } -int _InputArray::depth(int i) const +int _InputArray::depth_(int i) const { return CV_MAT_DEPTH(type(i)); } -int _InputArray::channels(int i) const -{ - return CV_MAT_CN(type(i)); -} - -bool _InputArray::empty() const +bool _InputArray::empty_() const { _InputArray::KindFlag k = kind(); @@ -1463,7 +1448,7 @@ bool _OutputArray::fixedType() const return (flags & FIXED_TYPE) == FIXED_TYPE; } -void _OutputArray::create(Size _sz, int mtype, int i, bool allowTransposed, _OutputArray::DepthMask fixedDepthMask) const +void _OutputArray::create_(Size _sz, int mtype, int i, bool allowTransposed, _OutputArray::DepthMask fixedDepthMask) const { _InputArray::KindFlag k = kind(); if( k == MAT && i < 0 && !allowTransposed && fixedDepthMask == 0 ) @@ -1529,7 +1514,7 @@ void _OutputArray::create(Size _sz, int mtype, int i, bool allowTransposed, _Out create(2, sizes, mtype, i, allowTransposed, fixedDepthMask); } -void _OutputArray::create(int _rows, int _cols, int mtype, int i, bool allowTransposed, _OutputArray::DepthMask fixedDepthMask) const +void _OutputArray::create_(int _rows, int _cols, int mtype, int i, bool allowTransposed, _OutputArray::DepthMask fixedDepthMask) const { _InputArray::KindFlag k = kind(); if( k == MAT && i < 0 && !allowTransposed && fixedDepthMask == 0 ) diff --git a/modules/imgproc/src/resize.cpp b/modules/imgproc/src/resize.cpp index 3e9239c05c..06e080bde6 100644 --- a/modules/imgproc/src/resize.cpp +++ b/modules/imgproc/src/resize.cpp @@ -3611,7 +3611,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, srcUMat = _src.getUMat(); Mat src = _src.getMat(); - _dst.create(dsize, src.type()); + _dst.create(dsize, _src.type()); Mat dst = _dst.getMat(); if (dsize == ssize) @@ -3621,5 +3621,5 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, return; } - hal::resize(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, inv_scale_x, inv_scale_y, interpolation); + hal::resize(_src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, inv_scale_x, inv_scale_y, interpolation); } diff --git a/modules/video/src/optflowgf.cpp b/modules/video/src/optflowgf.cpp index 5827ebea28..ed27ba7d36 100644 --- a/modules/video/src/optflowgf.cpp +++ b/modules/video/src/optflowgf.cpp @@ -1100,7 +1100,7 @@ void FarnebackOpticalFlowImpl::calc(InputArray _prev0, InputArray _next0, { CV_INSTRUMENT_REGION(); - CV_OCL_RUN(_flow0.isUMat() && + CV_OCL_RUN(ocl::isOpenCLActivated() && _flow0.isUMat() && ocl::Image2D::isFormatSupported(CV_32F, 1, false), calc_ocl(_prev0,_next0,_flow0)) Mat prev0 = _prev0.getMat(), next0 = _next0.getMat();