From 95e38e457fc805fab15b34679a00cf2e96e41da1 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 10 Feb 2014 16:34:45 +0400 Subject: [PATCH] core/umat: usage flags (with proposals from PR #2195) --- modules/core/include/opencv2/core/mat.hpp | 40 +++++++++++------ modules/core/include/opencv2/core/mat.inl.hpp | 40 +++++++++-------- modules/core/perf/opencl/perf_usage_flags.cpp | 42 ++++++++++++++++++ modules/core/src/matrix.cpp | 8 ++-- modules/core/src/ocl.cpp | 63 +++++++++++++++++++-------- modules/core/src/umatrix.cpp | 17 +++++--- modules/python/src2/cv2.cpp | 8 ++-- 7 files changed, 154 insertions(+), 64 deletions(-) create mode 100644 modules/core/perf/opencl/perf_usage_flags.cpp diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index db1e8fa..eb206fc 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -266,6 +266,18 @@ CV_EXPORTS InputOutputArray noArray(); /////////////////////////////////// MatAllocator ////////////////////////////////////// +//! Usage flags for allocator +enum UMatUsageFlags +{ + USAGE_DEFAULT = 0, + + // default allocation policy is platform and usage specific + USAGE_ALLOCATE_HOST_MEMORY = 1 << 0, + USAGE_ALLOCATE_DEVICE_MEMORY = 1 << 1, + + __UMAT_USAGE_FLAGS_32BIT = 0x7fffffff // Binary compatibility hint +}; + struct CV_EXPORTS UMatData; /*! @@ -283,8 +295,8 @@ public: // uchar*& datastart, uchar*& data, size_t* step) = 0; //virtual void deallocate(int* refcount, uchar* datastart, uchar* data) = 0; virtual UMatData* allocate(int dims, const int* sizes, int type, - void* data, size_t* step, int flags) const = 0; - virtual bool allocate(UMatData* data, int accessflags) const = 0; + void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const = 0; + virtual bool allocate(UMatData* data, int accessflags, UMatUsageFlags usageFlags) const = 0; virtual void deallocate(UMatData* data) const = 0; virtual void map(UMatData* data, int accessflags) const; virtual void unmap(UMatData* data) const; @@ -369,6 +381,7 @@ struct CV_EXPORTS UMatData int flags; void* handle; void* userdata; + int allocatorFlags_; }; @@ -671,7 +684,7 @@ public: Mat& operator = (const MatExpr& expr); //! retrieve UMat from Mat - UMat getUMat(int accessFlags) const; + UMat getUMat(int accessFlags, UMatUsageFlags usageFlags = USAGE_DEFAULT) const; //! returns a new matrix header for the specified row Mat row(int y) const; @@ -1136,18 +1149,18 @@ class CV_EXPORTS UMat { public: //! default constructor - UMat(); + UMat(UMatUsageFlags usageFlags = USAGE_DEFAULT); //! constructs 2D matrix of the specified size and type // (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) - UMat(int rows, int cols, int type); - UMat(Size size, int type); + UMat(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); //! constucts 2D matrix and fills it with the specified value _s. - UMat(int rows, int cols, int type, const Scalar& s); - UMat(Size size, int type, const Scalar& s); + UMat(int rows, int cols, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(Size size, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); //! constructs n-dimensional matrix - UMat(int ndims, const int* sizes, int type); - UMat(int ndims, const int* sizes, int type, const Scalar& s); + UMat(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(int ndims, const int* sizes, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); //! copy constructor UMat(const UMat& m); @@ -1237,9 +1250,9 @@ public: //! allocates new matrix data unless the matrix already has specified size and type. // previous data is unreferenced if needed. - void create(int rows, int cols, int type); - void create(Size size, int type); - void create(int ndims, const int* sizes, int type); + void create(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); //! increases the reference counter; use with care to avoid memleaks void addref(); @@ -1311,6 +1324,7 @@ public: //! custom allocator MatAllocator* allocator; + UMatUsageFlags usageFlags; // usage flags for allocator //! and the standard allocator static MatAllocator* getStdAllocator(); diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index d171488..6850771 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -3070,50 +3070,50 @@ const Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, const MatExpr& b) //////////////////////////////// UMat //////////////////////////////// inline -UMat::UMat() -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) {} inline -UMat::UMat(int _rows, int _cols, int _type) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create(_rows, _cols, _type); } inline -UMat::UMat(int _rows, int _cols, int _type, const Scalar& _s) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(int _rows, int _cols, int _type, const Scalar& _s, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create(_rows, _cols, _type); *this = _s; } inline -UMat::UMat(Size _sz, int _type) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(Size _sz, int _type, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create( _sz.height, _sz.width, _type ); } inline -UMat::UMat(Size _sz, int _type, const Scalar& _s) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(Size _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create(_sz.height, _sz.width, _type); *this = _s; } inline -UMat::UMat(int _dims, const int* _sz, int _type) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(int _dims, const int* _sz, int _type, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create(_dims, _sz, _type); } inline -UMat::UMat(int _dims, const int* _sz, int _type, const Scalar& _s) -: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows) +UMat::UMat(int _dims, const int* _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags) +: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows) { create(_dims, _sz, _type); *this = _s; @@ -3122,7 +3122,7 @@ UMat::UMat(int _dims, const int* _sz, int _type, const Scalar& _s) inline UMat::UMat(const UMat& m) : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator), -u(m.u), offset(m.offset), size(&rows) + usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows) { addref(); if( m.dims <= 2 ) @@ -3173,6 +3173,8 @@ UMat& UMat::operator = (const UMat& m) else copySize(m); allocator = m.allocator; + if (usageFlags == USAGE_DEFAULT) + usageFlags = m.usageFlags; u = m.u; offset = m.offset; } @@ -3233,19 +3235,19 @@ void UMat::assignTo( UMat& m, int _type ) const } inline -void UMat::create(int _rows, int _cols, int _type) +void UMat::create(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags) { _type &= TYPE_MASK; if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && u ) return; int sz[] = {_rows, _cols}; - create(2, sz, _type); + create(2, sz, _type, _usageFlags); } inline -void UMat::create(Size _sz, int _type) +void UMat::create(Size _sz, int _type, UMatUsageFlags _usageFlags) { - create(_sz.height, _sz.width, _type); + create(_sz.height, _sz.width, _type, _usageFlags); } inline diff --git a/modules/core/perf/opencl/perf_usage_flags.cpp b/modules/core/perf/opencl/perf_usage_flags.cpp new file mode 100644 index 0000000..275ff56 --- /dev/null +++ b/modules/core/perf/opencl/perf_usage_flags.cpp @@ -0,0 +1,42 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. + +#include "perf_precomp.hpp" +#include "opencv2/ts/ocl_perf.hpp" + +#ifdef HAVE_OPENCL + +namespace cvtest { +namespace ocl { + +typedef TestBaseWithParam > UsageFlagsBoolFixture; + +OCL_PERF_TEST_P(UsageFlagsBoolFixture, UsageFlags_AllocHostMem, ::testing::Combine(OCL_TEST_SIZES, Bool())) +{ + Size sz = get<0>(GetParam()); + bool allocHostMem = get<1>(GetParam()); + + UMat src(sz, CV_8UC1, Scalar::all(128)); + + OCL_TEST_CYCLE() + { + UMat dst(allocHostMem ? USAGE_ALLOCATE_HOST_MEMORY : USAGE_DEFAULT); + + cv::add(src, Scalar::all(1), dst); + { + Mat canvas = dst.getMat(ACCESS_RW); + cv::putText(canvas, "Test", Point(20, 20), FONT_HERSHEY_PLAIN, 1, Scalar::all(255)); + } + UMat final; + cv::subtract(dst, Scalar::all(1), final); + } + + SANITY_CHECK_NOTHING() +} + +} } // namespace cvtest::ocl + +#endif // HAVE_OPENCL diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index e897999..03b6490 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -169,7 +169,7 @@ class StdMatAllocator : public MatAllocator { public: UMatData* allocate(int dims, const int* sizes, int type, - void* data0, size_t* step, int /*flags*/) const + void* data0, size_t* step, int /*flags*/, UMatUsageFlags /*usageFlags*/) const { size_t total = CV_ELEM_SIZE(type); for( int i = dims-1; i >= 0; i-- ) @@ -196,7 +196,7 @@ public: return u; } - bool allocate(UMatData* u, int /*accessFlags*/) const + bool allocate(UMatData* u, int /*accessFlags*/, UMatUsageFlags /*usageFlags*/) const { if(!u) return false; return true; @@ -398,13 +398,13 @@ void Mat::create(int d, const int* _sizes, int _type) a = a0; try { - u = a->allocate(dims, size, _type, 0, step.p, 0); + u = a->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT); CV_Assert(u != 0); } catch(...) { if(a != a0) - u = a0->allocate(dims, size, _type, 0, step.p, 0); + u = a0->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT); CV_Assert(u != 0); } CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) ); diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index a4b4494..c7f18dc 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -3534,19 +3534,26 @@ private: class OpenCLAllocator : public MatAllocator { mutable OpenCLBufferPoolImpl bufferPool; + enum AllocatorFlags + { + ALLOCATOR_FLAGS_BUFFER_POOL_USED = 1 << 0 + }; public: OpenCLAllocator() { matStdAllocator = Mat::getStdAllocator(); } - UMatData* defaultAllocate(int dims, const int* sizes, int type, void* data, size_t* step, int flags) const + UMatData* defaultAllocate(int dims, const int* sizes, int type, void* data, size_t* step, + int flags, UMatUsageFlags usageFlags) const { - UMatData* u = matStdAllocator->allocate(dims, sizes, type, data, step, flags); + UMatData* u = matStdAllocator->allocate(dims, sizes, type, data, step, flags, usageFlags); return u; } - void getBestFlags(const Context& ctx, int /*flags*/, int& createFlags, int& flags0) const + void getBestFlags(const Context& ctx, int /*flags*/, UMatUsageFlags usageFlags, int& createFlags, int& flags0) const { const Device& dev = ctx.device(0); - createFlags = CL_MEM_READ_WRITE; + createFlags = 0; + if ((usageFlags & USAGE_ALLOCATE_HOST_MEMORY) != 0) + createFlags |= CL_MEM_ALLOC_HOST_PTR; if( dev.hostUnifiedMemory() ) flags0 = 0; @@ -3555,10 +3562,10 @@ public: } UMatData* allocate(int dims, const int* sizes, int type, - void* data, size_t* step, int flags) const + void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const { if(!useOpenCL()) - return defaultAllocate(dims, sizes, type, data, step, flags); + return defaultAllocate(dims, sizes, type, data, step, flags, usageFlags); CV_Assert(data == 0); size_t total = CV_ELEM_SIZE(type); for( int i = dims-1; i >= 0; i-- ) @@ -3570,24 +3577,39 @@ public: Context& ctx = Context::getDefault(); int createFlags = 0, flags0 = 0; - getBestFlags(ctx, flags, createFlags, flags0); + getBestFlags(ctx, flags, usageFlags, createFlags, flags0); - CV_Assert(createFlags == CL_MEM_READ_WRITE); size_t capacity = 0; - void* handle = bufferPool.allocate(total, capacity); - if (!handle) - return defaultAllocate(dims, sizes, type, data, step, flags); + void* handle = NULL; + int allocatorFlags = 0; + if (createFlags == 0) + { + handle = bufferPool.allocate(total, capacity); + if (!handle) + return defaultAllocate(dims, sizes, type, data, step, flags, usageFlags); + allocatorFlags = ALLOCATOR_FLAGS_BUFFER_POOL_USED; + } + else + { + capacity = total; + cl_int retval = 0; + handle = clCreateBuffer((cl_context)ctx.ptr(), + CL_MEM_READ_WRITE|createFlags, total, 0, &retval); + if( !handle || retval != CL_SUCCESS ) + return defaultAllocate(dims, sizes, type, data, step, flags, usageFlags); + } UMatData* u = new UMatData(this); u->data = 0; u->size = total; u->capacity = capacity; u->handle = handle; u->flags = flags0; - CV_DbgAssert(!u->tempUMat()); // for bufferPool.release() consistency + u->allocatorFlags_ = allocatorFlags; + CV_DbgAssert(!u->tempUMat()); // for bufferPool.release() consistency in deallocate() return u; } - bool allocate(UMatData* u, int accessFlags) const + bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const { if(!u) return false; @@ -3599,16 +3621,16 @@ public: CV_Assert(u->origdata != 0); Context& ctx = Context::getDefault(); int createFlags = 0, flags0 = 0; - getBestFlags(ctx, accessFlags, createFlags, flags0); + getBestFlags(ctx, accessFlags, usageFlags, createFlags, flags0); cl_context ctx_handle = (cl_context)ctx.ptr(); cl_int retval = 0; int tempUMatFlags = UMatData::TEMP_UMAT; - u->handle = clCreateBuffer(ctx_handle, CL_MEM_USE_HOST_PTR|createFlags, + u->handle = clCreateBuffer(ctx_handle, CL_MEM_USE_HOST_PTR|CL_MEM_READ_WRITE, u->size, u->origdata, &retval); if((!u->handle || retval != CL_SUCCESS) && !(accessFlags & ACCESS_FAST)) { - u->handle = clCreateBuffer(ctx_handle, CL_MEM_COPY_HOST_PTR|createFlags, + u->handle = clCreateBuffer(ctx_handle, CL_MEM_COPY_HOST_PTR|CL_MEM_READ_WRITE|createFlags, u->size, u->origdata, &retval); tempUMatFlags = UMatData::TEMP_COPIED_UMAT; } @@ -3705,7 +3727,14 @@ public: fastFree(u->data); u->data = 0; } - bufferPool.release((cl_mem)u->handle, u->capacity); + if (u->allocatorFlags_ & ALLOCATOR_FLAGS_BUFFER_POOL_USED) + { + bufferPool.release((cl_mem)u->handle, u->capacity); + } + else + { + clReleaseMemObject((cl_mem)u->handle); + } u->handle = 0; u->capacity = 0; delete u; diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index 1dd7b4d..789e7f5 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -60,6 +60,7 @@ UMatData::UMatData(const MatAllocator* allocator) flags = 0; handle = 0; userdata = 0; + allocatorFlags_ = 0; } UMatData::~UMatData() @@ -71,6 +72,7 @@ UMatData::~UMatData() flags = 0; handle = 0; userdata = 0; + allocatorFlags_ = 0; } void UMatData::lock() @@ -204,8 +206,7 @@ static void finalizeHdr(UMat& m) m.rows = m.cols = -1; } - -UMat Mat::getUMat(int accessFlags) const +UMat Mat::getUMat(int accessFlags, UMatUsageFlags usageFlags) const { UMat hdr; if(!data) @@ -216,10 +217,10 @@ UMat Mat::getUMat(int accessFlags) const MatAllocator *a = allocator, *a0 = getStdAllocator(); if(!a) a = a0; - temp_u = a->allocate(dims, size.p, type(), data, step.p, accessFlags); + temp_u = a->allocate(dims, size.p, type(), data, step.p, accessFlags, usageFlags); temp_u->refcount = 1; } - UMat::getStdAllocator()->allocate(temp_u, accessFlags); + UMat::getStdAllocator()->allocate(temp_u, accessFlags, usageFlags); hdr.flags = flags; setSize(hdr, dims, size.p, step.p); finalizeHdr(hdr); @@ -229,8 +230,10 @@ UMat Mat::getUMat(int accessFlags) const return hdr; } -void UMat::create(int d, const int* _sizes, int _type) +void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlags) { + this->usageFlags = _usageFlags; + int i; CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes); _type = CV_MAT_TYPE(_type); @@ -260,13 +263,13 @@ void UMat::create(int d, const int* _sizes, int _type) a = a0; try { - u = a->allocate(dims, size, _type, 0, step.p, 0); + u = a->allocate(dims, size, _type, 0, step.p, 0, usageFlags); CV_Assert(u != 0); } catch(...) { if(a != a0) - u = a0->allocate(dims, size, _type, 0, step.p, 0); + u = a0->allocate(dims, size, _type, 0, step.p, 0, usageFlags); CV_Assert(u != 0); } CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) ); diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index cd9c55e..dfb1d68 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -199,13 +199,13 @@ public: return u; } - UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags) const + UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const { if( data != 0 ) { CV_Error(Error::StsAssert, "The data should normally be NULL!"); // probably this is safe to do in such extreme case - return stdAllocator->allocate(dims0, sizes, type, data, step, flags); + return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags); } PyEnsureGIL gil; @@ -228,9 +228,9 @@ public: return allocate(o, dims0, sizes, type, step); } - bool allocate(UMatData* u, int accessFlags) const + bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const { - return stdAllocator->allocate(u, accessFlags); + return stdAllocator->allocate(u, accessFlags, usageFlags); } void deallocate(UMatData* u) const -- 2.7.4