46f03b97b87f3f035dda7a95576c99e731eaae70
[profile/ivi/opencv.git] / modules / core / src / umatrix.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44
45 ///////////////////////////////// UMat implementation ///////////////////////////////
46
47 namespace cv {
48
49 // it should be a prime number for the best hash function
50 enum { UMAT_NLOCKS = 31 };
51 static Mutex umatLocks[UMAT_NLOCKS];
52
53 UMatData::UMatData(const MatAllocator* allocator)
54 {
55     prevAllocator = currAllocator = allocator;
56     urefcount = refcount = 0;
57     data = origdata = 0;
58     size = 0;
59     flags = 0;
60     handle = 0;
61     userdata = 0;
62 }
63
64 void UMatData::lock()
65 {
66     umatLocks[(size_t)(void*)this % UMAT_NLOCKS].lock();
67 }
68
69 void UMatData::unlock()
70 {
71     umatLocks[(size_t)(void*)this % UMAT_NLOCKS].unlock();
72 }
73
74
75 MatAllocator* UMat::getStdAllocator()
76 {
77     return ocl::getOpenCLAllocator();
78 }
79
80 void swap( UMat& a, UMat& b )
81 {
82     std::swap(a.flags, b.flags);
83     std::swap(a.dims, b.dims);
84     std::swap(a.rows, b.rows);
85     std::swap(a.cols, b.cols);
86     std::swap(a.allocator, b.allocator);
87     std::swap(a.u, b.u);
88     std::swap(a.offset, b.offset);
89
90     std::swap(a.size.p, b.size.p);
91     std::swap(a.step.p, b.step.p);
92     std::swap(a.step.buf[0], b.step.buf[0]);
93     std::swap(a.step.buf[1], b.step.buf[1]);
94
95     if( a.step.p == b.step.buf )
96     {
97         a.step.p = a.step.buf;
98         a.size.p = &a.rows;
99     }
100
101     if( b.step.p == a.step.buf )
102     {
103         b.step.p = b.step.buf;
104         b.size.p = &b.rows;
105     }
106 }
107
108
109 static inline void setSize( UMat& m, int _dims, const int* _sz,
110                             const size_t* _steps, bool autoSteps=false )
111 {
112     CV_Assert( 0 <= _dims && _dims <= CV_MAX_DIM );
113     if( m.dims != _dims )
114     {
115         if( m.step.p != m.step.buf )
116         {
117             fastFree(m.step.p);
118             m.step.p = m.step.buf;
119             m.size.p = &m.rows;
120         }
121         if( _dims > 2 )
122         {
123             m.step.p = (size_t*)fastMalloc(_dims*sizeof(m.step.p[0]) + (_dims+1)*sizeof(m.size.p[0]));
124             m.size.p = (int*)(m.step.p + _dims) + 1;
125             m.size.p[-1] = _dims;
126             m.rows = m.cols = -1;
127         }
128     }
129
130     m.dims = _dims;
131     if( !_sz )
132         return;
133
134     size_t esz = CV_ELEM_SIZE(m.flags), total = esz;
135     int i;
136     for( i = _dims-1; i >= 0; i-- )
137     {
138         int s = _sz[i];
139         CV_Assert( s >= 0 );
140         m.size.p[i] = s;
141
142         if( _steps )
143             m.step.p[i] = i < _dims-1 ? _steps[i] : esz;
144         else if( autoSteps )
145         {
146             m.step.p[i] = total;
147             int64 total1 = (int64)total*s;
148             if( (uint64)total1 != (size_t)total1 )
149                 CV_Error( CV_StsOutOfRange, "The total matrix size does not fit to \"size_t\" type" );
150             total = (size_t)total1;
151         }
152     }
153
154     if( _dims == 1 )
155     {
156         m.dims = 2;
157         m.cols = 1;
158         m.step[1] = esz;
159     }
160 }
161
162 static void updateContinuityFlag(UMat& m)
163 {
164     int i, j;
165     for( i = 0; i < m.dims; i++ )
166     {
167         if( m.size[i] > 1 )
168             break;
169     }
170
171     for( j = m.dims-1; j > i; j-- )
172     {
173         if( m.step[j]*m.size[j] < m.step[j-1] )
174             break;
175     }
176
177     uint64 t = (uint64)m.step[0]*m.size[0];
178     if( j <= i && t == (size_t)t )
179         m.flags |= UMat::CONTINUOUS_FLAG;
180     else
181         m.flags &= ~UMat::CONTINUOUS_FLAG;
182 }
183
184
185 static void finalizeHdr(UMat& m)
186 {
187     updateContinuityFlag(m);
188     int d = m.dims;
189     if( d > 2 )
190         m.rows = m.cols = -1;
191 }
192
193
194 UMat Mat::getUMat(int accessFlags) const
195 {
196     UMat hdr;
197     if(!u)
198         return hdr;
199     UMat::getStdAllocator()->allocate(u, accessFlags);
200     hdr.flags = flags;
201     setSize(hdr, dims, size.p, step.p);
202     finalizeHdr(hdr);
203     hdr.u = u;
204     hdr.offset = data - datastart;
205     return hdr;
206 }
207
208 void UMat::create(int d, const int* _sizes, int _type)
209 {
210     int i;
211     CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
212     _type = CV_MAT_TYPE(_type);
213
214     if( u && (d == dims || (d == 1 && dims <= 2)) && _type == type() )
215     {
216         if( d == 2 && rows == _sizes[0] && cols == _sizes[1] )
217             return;
218         for( i = 0; i < d; i++ )
219             if( size[i] != _sizes[i] )
220                 break;
221         if( i == d && (d > 1 || size[1] == 1))
222             return;
223     }
224
225     release();
226     if( d == 0 )
227         return;
228     flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
229     setSize(*this, d, _sizes, 0, true);
230     offset = 0;
231
232     if( total() > 0 )
233     {
234         MatAllocator *a = allocator, *a0 = getStdAllocator();
235         if(!a)
236             a = a0;
237         try
238         {
239             u = a->allocate(dims, size, _type, step.p);
240             CV_Assert(u != 0);
241         }
242         catch(...)
243         {
244             if(a != a0)
245                 u = a0->allocate(dims, size, _type, step.p);
246             CV_Assert(u != 0);
247         }
248         CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) );
249     }
250
251     finalizeHdr(*this);
252 }
253
254 void UMat::copySize(const UMat& m)
255 {
256     setSize(*this, m.dims, 0, 0);
257     for( int i = 0; i < dims; i++ )
258     {
259         size[i] = m.size[i];
260         step[i] = m.step[i];
261     }
262 }
263
264 void UMat::deallocate()
265 {
266     u->currAllocator->deallocate(u);
267 }
268
269
270 UMat::UMat(const UMat& m, const Range& _rowRange, const Range& _colRange)
271     : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows)
272 {
273     CV_Assert( m.dims >= 2 );
274     if( m.dims > 2 )
275     {
276         AutoBuffer<Range> rs(m.dims);
277         rs[0] = _rowRange;
278         rs[1] = _colRange;
279         for( int i = 2; i < m.dims; i++ )
280             rs[i] = Range::all();
281         *this = m(rs);
282         return;
283     }
284
285     *this = m;
286     if( _rowRange != Range::all() && _rowRange != Range(0,rows) )
287     {
288         CV_Assert( 0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows );
289         rows = _rowRange.size();
290         offset += step*_rowRange.start;
291         flags |= SUBMATRIX_FLAG;
292     }
293
294     if( _colRange != Range::all() && _colRange != Range(0,cols) )
295     {
296         CV_Assert( 0 <= _colRange.start && _colRange.start <= _colRange.end && _colRange.end <= m.cols );
297         cols = _colRange.size();
298         offset += _colRange.start*elemSize();
299         flags &= cols < m.cols ? ~CONTINUOUS_FLAG : -1;
300         flags |= SUBMATRIX_FLAG;
301     }
302
303     if( rows == 1 )
304         flags |= CONTINUOUS_FLAG;
305
306     if( rows <= 0 || cols <= 0 )
307     {
308         release();
309         rows = cols = 0;
310     }
311 }
312
313
314 UMat::UMat(const UMat& m, const Rect& roi)
315     : flags(m.flags), dims(2), rows(roi.height), cols(roi.width),
316     allocator(m.allocator), u(m.u), offset(m.offset + roi.y*m.step[0]), size(&rows)
317 {
318     CV_Assert( m.dims <= 2 );
319     flags &= roi.width < m.cols ? ~CONTINUOUS_FLAG : -1;
320     flags |= roi.height == 1 ? CONTINUOUS_FLAG : 0;
321
322     size_t esz = CV_ELEM_SIZE(flags);
323     offset += roi.x*esz;
324     CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
325               0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
326     if( u )
327         CV_XADD(&(u->urefcount), 1);
328     if( roi.width < m.cols || roi.height < m.rows )
329         flags |= SUBMATRIX_FLAG;
330
331     step[0] = m.step[0]; step[1] = esz;
332
333     if( rows <= 0 || cols <= 0 )
334     {
335         release();
336         rows = cols = 0;
337     }
338 }
339
340
341 UMat::UMat(const UMat& m, const Range* ranges)
342     : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), u(0), offset(0), size(&rows)
343 {
344     int i, d = m.dims;
345
346     CV_Assert(ranges);
347     for( i = 0; i < d; i++ )
348     {
349         Range r = ranges[i];
350         CV_Assert( r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]) );
351     }
352     *this = m;
353     for( i = 0; i < d; i++ )
354     {
355         Range r = ranges[i];
356         if( r != Range::all() && r != Range(0, size.p[i]))
357         {
358             size.p[i] = r.end - r.start;
359             offset += r.start*step.p[i];
360             flags |= SUBMATRIX_FLAG;
361         }
362     }
363     updateContinuityFlag(*this);
364 }
365
366 UMat UMat::diag(int d) const
367 {
368     CV_Assert( dims <= 2 );
369     UMat m = *this;
370     size_t esz = elemSize();
371     int len;
372
373     if( d >= 0 )
374     {
375         len = std::min(cols - d, rows);
376         m.offset += esz*d;
377     }
378     else
379     {
380         len = std::min(rows + d, cols);
381         m.offset -= step[0]*d;
382     }
383     CV_DbgAssert( len > 0 );
384
385     m.size[0] = m.rows = len;
386     m.size[1] = m.cols = 1;
387     m.step[0] += (len > 1 ? esz : 0);
388
389     if( m.rows > 1 )
390         m.flags &= ~CONTINUOUS_FLAG;
391     else
392         m.flags |= CONTINUOUS_FLAG;
393
394     if( size() != Size(1,1) )
395         m.flags |= SUBMATRIX_FLAG;
396
397     return m;
398 }
399
400 void UMat::locateROI( Size& wholeSize, Point& ofs ) const
401 {
402     CV_Assert( dims <= 2 && step[0] > 0 );
403     size_t esz = elemSize(), minstep;
404     ptrdiff_t delta1 = (ptrdiff_t)offset, delta2 = (ptrdiff_t)u->size;
405
406     if( delta1 == 0 )
407         ofs.x = ofs.y = 0;
408     else
409     {
410         ofs.y = (int)(delta1/step[0]);
411         ofs.x = (int)((delta1 - step[0]*ofs.y)/esz);
412         CV_DbgAssert( offset == (size_t)(ofs.y*step[0] + ofs.x*esz) );
413     }
414     minstep = (ofs.x + cols)*esz;
415     wholeSize.height = (int)((delta2 - minstep)/step[0] + 1);
416     wholeSize.height = std::max(wholeSize.height, ofs.y + rows);
417     wholeSize.width = (int)((delta2 - step*(wholeSize.height-1))/esz);
418     wholeSize.width = std::max(wholeSize.width, ofs.x + cols);
419 }
420
421
422 UMat& UMat::adjustROI( int dtop, int dbottom, int dleft, int dright )
423 {
424     CV_Assert( dims <= 2 && step[0] > 0 );
425     Size wholeSize; Point ofs;
426     size_t esz = elemSize();
427     locateROI( wholeSize, ofs );
428     int row1 = std::max(ofs.y - dtop, 0), row2 = std::min(ofs.y + rows + dbottom, wholeSize.height);
429     int col1 = std::max(ofs.x - dleft, 0), col2 = std::min(ofs.x + cols + dright, wholeSize.width);
430     offset += (row1 - ofs.y)*step + (col1 - ofs.x)*esz;
431     rows = row2 - row1; cols = col2 - col1;
432     size.p[0] = rows; size.p[1] = cols;
433     if( esz*cols == step[0] || rows == 1 )
434         flags |= CONTINUOUS_FLAG;
435     else
436         flags &= ~CONTINUOUS_FLAG;
437     return *this;
438 }
439
440
441 UMat UMat::reshape(int new_cn, int new_rows) const
442 {
443     int cn = channels();
444     UMat hdr = *this;
445
446     if( dims > 2 && new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 )
447     {
448         hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
449         hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags);
450         hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn;
451         return hdr;
452     }
453
454     CV_Assert( dims <= 2 );
455
456     if( new_cn == 0 )
457         new_cn = cn;
458
459     int total_width = cols * cn;
460
461     if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 )
462         new_rows = rows * total_width / new_cn;
463
464     if( new_rows != 0 && new_rows != rows )
465     {
466         int total_size = total_width * rows;
467         if( !isContinuous() )
468             CV_Error( CV_BadStep,
469             "The matrix is not continuous, thus its number of rows can not be changed" );
470
471         if( (unsigned)new_rows > (unsigned)total_size )
472             CV_Error( CV_StsOutOfRange, "Bad new number of rows" );
473
474         total_width = total_size / new_rows;
475
476         if( total_width * new_rows != total_size )
477             CV_Error( CV_StsBadArg, "The total number of matrix elements "
478                                     "is not divisible by the new number of rows" );
479
480         hdr.rows = new_rows;
481         hdr.step[0] = total_width * elemSize1();
482     }
483
484     int new_width = total_width / new_cn;
485
486     if( new_width * new_cn != total_width )
487         CV_Error( CV_BadNumChannels,
488         "The total width is not divisible by the new number of channels" );
489
490     hdr.cols = new_width;
491     hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
492     hdr.step[1] = CV_ELEM_SIZE(hdr.flags);
493     return hdr;
494 }
495
496 UMat UMat::diag(const UMat& d)
497 {
498     CV_Assert( d.cols == 1 || d.rows == 1 );
499     int len = d.rows + d.cols - 1;
500     UMat m(len, len, d.type(), Scalar(0));
501     UMat md = m.diag();
502     if( d.cols == 1 )
503         d.copyTo(md);
504     else
505         transpose(d, md);
506     return m;
507 }
508
509 int UMat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) const
510 {
511     return (depth() == _depth || _depth <= 0) &&
512         (isContinuous() || !_requireContinuous) &&
513         ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) ||
514                         (cols == _elemChannels && channels() == 1))) ||
515         (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) &&
516          (isContinuous() || step.p[1] == step.p[2]*size.p[2])))
517     ? (int)(total()*channels()/_elemChannels) : -1;
518 }
519
520
521 UMat UMat::cross(InputArray) const
522 {
523     CV_Error(CV_StsNotImplemented, "");
524     return UMat();
525 }
526
527
528 UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
529 {
530     if(_newndims == dims)
531     {
532         if(_newsz == 0)
533             return reshape(_cn);
534         if(_newndims == 2)
535             return reshape(_cn, _newsz[0]);
536     }
537
538     CV_Error(CV_StsNotImplemented, "");
539     // TBD
540     return UMat();
541 }
542
543
544 Mat UMat::getMat(int accessFlags) const
545 {
546     if(!u)
547         return Mat();
548     u->currAllocator->map(u, accessFlags);
549     CV_Assert(u->data != 0);
550     Mat hdr(dims, size.p, type(), u->data + offset, step.p);
551     hdr.u = u;
552     hdr.datastart = u->data;
553     hdr.data = hdr.datastart + offset;
554     hdr.datalimit = hdr.dataend = u->data + u->size;
555     CV_XADD(&hdr.u->refcount, 1);
556     return hdr;
557 }
558
559 void* UMat::handle(int /*accessFlags*/) const
560 {
561     if( !u )
562         return 0;
563
564     // check flags: if CPU copy is newer, copy it back to GPU.
565     if( u->deviceCopyObsolete() )
566     {
567         CV_Assert(u->refcount == 0);
568         u->currAllocator->unmap(u);
569     }
570     /*else if( u->refcount > 0 && (accessFlags & ACCESS_WRITE) )
571     {
572         CV_Error(Error::StsError,
573                  "it's not allowed to access UMat handle for writing "
574                  "while it's mapped; call Mat::release() first for all its mappings");
575     }*/
576     return u->handle;
577 }
578
579 void UMat::ndoffset(size_t* ofs) const
580 {
581     // offset = step[0]*ofs[0] + step[1]*ofs[1] + step[2]*ofs[2] + ...;
582     size_t val = offset;
583     for( int i = 0; i < dims; i++ )
584     {
585         size_t s = step.p[i];
586         ofs[i] = val / s;
587         val -= ofs[i]*s;
588     }
589 }
590
591 void UMat::copyTo(OutputArray _dst) const
592 {
593     int dtype = _dst.type();
594     if( _dst.fixedType() && dtype != type() )
595     {
596         CV_Assert( channels() == CV_MAT_CN(dtype) );
597         convertTo( _dst, dtype );
598         return;
599     }
600
601     if( empty() )
602     {
603         _dst.release();
604         return;
605     }
606
607     size_t i, sz[CV_MAX_DIM], srcofs[CV_MAX_DIM], dstofs[CV_MAX_DIM], esz = elemSize();
608     for( i = 0; i < (size_t)dims; i++ )
609         sz[i] = size.p[i];
610     sz[dims-1] *= esz;
611     ndoffset(srcofs);
612     srcofs[dims-1] *= esz;
613
614     _dst.create( dims, size.p, type() );
615     if( _dst.kind() == _InputArray::UMAT )
616     {
617         UMat dst = _dst.getUMat();
618         void* srchandle = handle(ACCESS_READ);
619         void* dsthandle = dst.handle(ACCESS_WRITE);
620         if( srchandle == dsthandle && dst.offset == offset )
621             return;
622         dst.ndoffset(dstofs);
623         CV_Assert(u->currAllocator == dst.u->currAllocator);
624         u->currAllocator->copy(u, dst.u, dims, sz, srcofs, step.p, dstofs, dst.step.p, false);
625     }
626     else
627     {
628         Mat dst = _dst.getMat();
629         u->currAllocator->download(u, dst.data, dims, sz, srcofs, step.p, dst.step.p);
630     }
631 }
632
633 void UMat::convertTo(OutputArray, int, double, double) const
634 {
635     CV_Error(Error::StsNotImplemented, "");
636 }
637
638 UMat& UMat::setTo(InputArray _value, InputArray _mask)
639 {
640     bool haveMask = !_mask.empty();
641     int t = type(), cn = CV_MAT_CN(t);
642     if( dims <= 2 && cn <= 4 && ocl::useOpenCL() )
643     {
644         Mat value = _value.getMat();
645         CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::UMAT) );
646         double buf[4];
647         convertAndUnrollScalar(value, t, (uchar*)buf, 1);
648
649         char opts[1024];
650         sprintf(opts, "-D dstT=%s", ocl::memopTypeToStr(t));
651
652         ocl::Kernel setK(haveMask ? "setMask" : "set", ocl::core::copyset_oclsrc, opts);
653         if( !setK.empty() )
654         {
655             ocl::KernelArg scalararg(0, 0, 0, buf, CV_ELEM_SIZE(t));
656             UMat mask;
657
658             if( haveMask )
659             {
660                 mask = _mask.getUMat();
661                 CV_Assert( mask.size() == size() && mask.type() == CV_8U );
662                 ocl::KernelArg maskarg = ocl::KernelArg::ReadOnlyNoSize(mask);
663                 ocl::KernelArg dstarg = ocl::KernelArg::ReadWrite(*this);
664                 setK.args(maskarg, dstarg, scalararg);
665             }
666             else
667             {
668                 ocl::KernelArg dstarg = ocl::KernelArg::WriteOnly(*this);
669                 setK.args(dstarg, scalararg);
670             }
671
672             size_t globalsize[] = { cols, rows };
673             if( setK.run(2, globalsize, 0, false) )
674                 return *this;
675         }
676     }
677     Mat m = getMat(haveMask ? ACCESS_RW : ACCESS_WRITE);
678     m.setTo(_value, _mask);
679     return *this;
680 }
681
682 UMat& UMat::operator = (const Scalar&)
683 {
684     CV_Error(Error::StsNotImplemented, "");
685     return *this;
686 }
687
688 }
689
690 /* End of file. */