core/umat: usage flags (with proposals from PR #2195)
authorAlexander Alekhin <alexander.alekhin@itseez.com>
Mon, 10 Feb 2014 12:34:45 +0000 (16:34 +0400)
committerAlexander Alekhin <alexander.alekhin@itseez.com>
Fri, 14 Feb 2014 11:40:16 +0000 (15:40 +0400)
modules/core/include/opencv2/core/mat.hpp
modules/core/include/opencv2/core/mat.inl.hpp
modules/core/perf/opencl/perf_usage_flags.cpp [new file with mode: 0644]
modules/core/src/matrix.cpp
modules/core/src/ocl.cpp
modules/core/src/umatrix.cpp
modules/python/src2/cv2.cpp

index db1e8fa..eb206fc 100644 (file)
@@ -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();
 
index d171488..6850771 100644 (file)
@@ -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 (file)
index 0000000..275ff56
--- /dev/null
@@ -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<std::tr1::tuple<cv::Size, bool> > 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
index e897999..03b6490 100644 (file)
@@ -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) );
index a4b4494..c7f18dc 100644 (file)
@@ -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;
index 1dd7b4d..789e7f5 100644 (file)
@@ -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) );
index cd9c55e..dfb1d68 100644 (file)
@@ -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