1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 00:03:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Alekhin
2021-10-15 15:59:36 +00:00
537 changed files with 39768 additions and 10712 deletions
+166
View File
@@ -14,6 +14,7 @@
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1
#include <opencv2/core/utils/logger.hpp>
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef CV_CXX11
#include <mutex>
@@ -236,6 +237,171 @@ struct AsyncArray::Impl
}
};
} // namespace
#else // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
// no threading
struct AsyncArray::Impl
{
int refcount;
void addrefFuture() CV_NOEXCEPT { refcount_future++; refcount++; }
void releaseFuture() CV_NOEXCEPT { refcount_future--; if (0 == --refcount) delete this; }
int refcount_future;
void addrefPromise() CV_NOEXCEPT { refcount_promise++; refcount++; } \
void releasePromise() CV_NOEXCEPT { refcount_promise--; if (0 == --refcount) delete this; }
int refcount_promise;
mutable bool has_result; // Mat, UMat or exception
mutable cv::Ptr<Mat> result_mat;
mutable cv::Ptr<UMat> result_umat;
bool has_exception;
#if CV__EXCEPTION_PTR
std::exception_ptr exception;
#endif
cv::Exception cv_exception;
mutable bool result_is_fetched;
bool future_is_returned;
Impl()
: refcount(1), refcount_future(0), refcount_promise(1)
, has_result(false)
, has_exception(false)
, result_is_fetched(false)
, future_is_returned(false)
{
// nothing
}
~Impl()
{
if (has_result && !result_is_fetched)
{
CV_LOG_INFO(NULL, "Asynchronous result has not been fetched");
}
}
bool get(OutputArray dst, int64 timeoutNs) const
{
CV_Assert(!result_is_fetched);
if (!has_result)
{
CV_UNUSED(timeoutNs);
CV_Error(Error::StsError, "Result is not produced (unable to wait for result in OPENCV_DISABLE_THREAD_SUPPORT mode)");
}
if (!result_mat.empty())
{
dst.move(*result_mat.get());
result_mat.release();
result_is_fetched = true;
return true;
}
if (!result_umat.empty())
{
dst.move(*result_umat.get());
result_umat.release();
result_is_fetched = true;
return true;
}
#if CV__EXCEPTION_PTR
if (has_exception && exception)
{
result_is_fetched = true;
std::rethrow_exception(exception);
}
#endif
if (has_exception)
{
result_is_fetched = true;
throw cv_exception;
}
CV_Error(Error::StsInternal, "AsyncArray: invalid state of 'has_result = true'");
return false;
}
bool valid() const CV_NOEXCEPT
{
if (result_is_fetched)
return false;
if (refcount_promise == 0 && !has_result)
return false;
return true;
}
bool wait_for(int64 timeoutNs) const
{
CV_Assert(valid());
if (has_result)
return has_result;
if (timeoutNs == 0)
return has_result;
CV_Error(Error::StsError, "Unable to wait in OPENCV_DISABLE_THREAD_SUPPORT mode");
}
AsyncArray getArrayResult()
{
CV_Assert(refcount_future == 0);
AsyncArray result;
addrefFuture();
result.p = this;
future_is_returned = true;
return result;
}
void setValue(InputArray value)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
int k = value.kind();
if (k == _InputArray::UMAT)
{
result_umat = makePtr<UMat>();
value.copyTo(*result_umat.get());
}
else
{
result_mat = makePtr<Mat>();
value.copyTo(*result_mat.get());
}
has_result = true;
}
#if CV__EXCEPTION_PTR
void setException(std::exception_ptr e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
exception = e;
has_result = true;
}
#endif
void setException(const cv::Exception e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
cv_exception = e;
has_result = true;
}
};
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
AsyncArray::AsyncArray() CV_NOEXCEPT
: p(NULL)
+48
View File
@@ -5,6 +5,7 @@
#include "precomp.hpp"
#include "opencv2/core/bindings_utils.hpp"
#include <sstream>
#include <iomanip>
#include <opencv2/core/utils/filesystem.hpp>
#include <opencv2/core/utils/filesystem.private.hpp>
@@ -210,6 +211,53 @@ CV_EXPORTS_W String dumpInputOutputArrayOfArrays(InputOutputArrayOfArrays argume
return ss.str();
}
static inline std::ostream& operator<<(std::ostream& os, const cv::Rect& rect)
{
return os << "[x=" << rect.x << ", y=" << rect.y << ", w=" << rect.width << ", h=" << rect.height << ']';
}
template <class T, class Formatter>
static inline String dumpVector(const std::vector<T>& vec, Formatter format)
{
std::ostringstream oss("[", std::ios::ate);
if (!vec.empty())
{
oss << format << vec[0];
for (std::size_t i = 1; i < vec.size(); ++i)
{
oss << ", " << format << vec[i];
}
}
oss << "]";
return oss.str();
}
static inline std::ostream& noFormat(std::ostream& os)
{
return os;
}
static inline std::ostream& floatFormat(std::ostream& os)
{
return os << std::fixed << std::setprecision(2);
}
String dumpVectorOfInt(const std::vector<int>& vec)
{
return dumpVector(vec, &noFormat);
}
String dumpVectorOfDouble(const std::vector<double>& vec)
{
return dumpVector(vec, &floatFormat);
}
String dumpVectorOfRect(const std::vector<Rect>& vec)
{
return dumpVector(vec, &noFormat);
}
namespace fs {
cv::String getCacheDirectoryForDownloads()
{
+46 -21
View File
@@ -24,11 +24,6 @@
#ifdef HAVE_OPENCL
#include <sstream>
#include "opencl_kernels_core.hpp"
#include "opencv2/core/opencl/runtime/opencl_clblas.hpp"
#include "opencv2/core/opencl/runtime/opencl_core.hpp"
namespace cv
{
@@ -37,52 +32,75 @@ static bool intel_gpu_gemm(
UMat B, Size sizeB,
UMat D, Size sizeD,
double alpha, double beta,
bool atrans, bool btrans)
bool atrans, bool btrans,
bool& isPropagatedC2D
)
{
CV_UNUSED(sizeB);
int M = sizeD.height, N = sizeD.width, K = ((atrans)? sizeA.height : sizeA.width);
std::string kernelName;
bool ret = true;
if (M < 4 || N < 4 || K < 4) // vload4
return false;
size_t lx = 8, ly = 4;
size_t dx = 4, dy = 8;
CV_LOG_VERBOSE(NULL, 0, "M=" << M << " N=" << N << " K=" << K);
std::string kernelName;
unsigned int lx = 8, ly = 4;
unsigned int dx = 4, dy = 8;
if(!atrans && !btrans)
{
if (M % 32 == 0 && N % 32 == 0 && K % 16 == 0)
{
kernelName = "intelblas_gemm_buffer_NN_sp";
}
else
{
if (M % 2 != 0)
return false;
// vload4(0, dst_write0) - 4 cols
// multiply by lx: 8
if (N % (4*8) != 0)
return false;
kernelName = "intelblas_gemm_buffer_NN";
}
}
else if(atrans && !btrans)
{
if (M % 32 != 0)
return false;
if (N % 32 != 0)
return false;
kernelName = "intelblas_gemm_buffer_TN";
}
else if(!atrans && btrans)
{
if (K % 4 != 0)
return false;
kernelName = "intelblas_gemm_buffer_NT";
ly = 16;
dx = 1;
}
else
{
if (M % 32 != 0)
return false;
if (N % 32 != 0)
return false;
if (K % 16 != 0)
return false;
kernelName = "intelblas_gemm_buffer_TT";
}
const size_t gx = (size_t)(N + dx - 1) / dx;
const size_t gy = (size_t)(M + dy - 1) / dy;
CV_LOG_DEBUG(NULL, "kernel: " << kernelName << " (M=" << M << " N=" << N << " K=" << K << ")");
const size_t gx = divUp((size_t)N, dx);
const size_t gy = divUp((size_t)M, dy);
size_t local[] = {lx, ly, 1};
size_t global[] = {(gx + lx - 1) / lx * lx, (gy + ly - 1) / ly * ly, 1};
int stride = (M * N < 1024 * 1024) ? 10000000 : 256;
size_t global[] = {roundUp(gx, lx), roundUp(gy, ly), 1};
ocl::Queue q;
String errmsg;
@@ -110,10 +128,13 @@ static bool intel_gpu_gemm(
(int)(D.step / sizeof(float))
);
ret = k.run(2, global, local, false, q);
bool ret = k.run(2, global, local, false, q);
return ret;
}
else
{
int stride = (M * N < 1024 * 1024) ? 10000000 : 256;
for(int start_index = 0; start_index < K; start_index += stride)
{
ocl::Kernel k(kernelName.c_str(), program);
@@ -132,12 +153,16 @@ static bool intel_gpu_gemm(
(int) start_index, // 14 start_index
stride);
ret = k.run(2, global, local, false, q);
if (!ret) return ret;
bool ret = k.run(2, global, local, false, q);
if (!ret)
{
if (start_index != 0)
isPropagatedC2D = false; // D array content is changed, need to rewrite
return false;
}
}
return true;
}
return ret;
}
} // namespace cv
+89 -70
View File
@@ -42,6 +42,8 @@
//M*/
#include "precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#include "opencl_kernels_core.hpp"
#include "opencv2/core/opencl/runtime/opencl_clblas.hpp"
#include "opencv2/core/opencl/runtime/opencl_core.hpp"
@@ -155,10 +157,12 @@ static bool ocl_gemm_amdblas( InputArray matA, InputArray matB, double alpha,
static bool ocl_gemm( InputArray matA, InputArray matB, double alpha,
InputArray matC, double beta, OutputArray matD, int flags )
{
int depth = matA.depth(), cn = matA.channels();
int type = CV_MAKETYPE(depth, cn);
int type = matA.type();
int depth = CV_MAT_DEPTH(type);
int cn = CV_MAT_CN(type);
CV_Assert_N( type == matB.type(), (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2) );
CV_CheckTypeEQ(type, matB.type(), "");
CV_CheckType(type, type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2, "");
const ocl::Device & dev = ocl::Device::getDefault();
bool doubleSupport = dev.doubleFPConfig() > 0;
@@ -170,88 +174,103 @@ static bool ocl_gemm( InputArray matA, InputArray matB, double alpha,
Size sizeA = matA.size(), sizeB = matB.size(), sizeC = haveC ? matC.size() : Size(0, 0);
bool atrans = (flags & GEMM_1_T) != 0, btrans = (flags & GEMM_2_T) != 0, ctrans = (flags & GEMM_3_T) != 0;
CV_Assert( !haveC || matC.type() == type );
if (haveC)
CV_CheckTypeEQ(type, matC.type(), "");
Size sizeD(((btrans) ? sizeB.height : sizeB.width),
((atrans) ? sizeA.width : sizeA.height));
if (atrans)
sizeA = Size(sizeA.height, sizeA.width);
if (btrans)
sizeB = Size(sizeB.height, sizeB.width);
if (haveC && ctrans)
sizeC = Size(sizeC.height, sizeC.width);
CV_CheckEQ(sizeA.width, sizeB.height, "");
if (haveC)
CV_CheckEQ(sizeC, sizeD, "");
UMat A = matA.getUMat();
UMat B = matB.getUMat();
Size sizeD(((btrans)? sizeB.height : sizeB.width),
((atrans)? sizeA.width : sizeA.height));
matD.create(sizeD, type);
UMat D = matD.getUMat();
UMat A = matA.getUMat(), B = matB.getUMat(), D = matD.getUMat();
bool isPropagatedC2D = false; // D content is updated with C / C.t()
if (!dev.intelSubgroupsSupport() || (depth == CV_64F) || cn != 1)
{
String opts;
if (atrans)
sizeA = Size(sizeA.height, sizeA.width);
if (btrans)
sizeB = Size(sizeB.height, sizeB.width);
if (haveC && ctrans)
sizeC = Size(sizeC.height, sizeC.width);
CV_Assert( sizeA.width == sizeB.height && (!haveC || sizeC == sizeD) );
int max_wg_size = (int)dev.maxWorkGroupSize();
int block_size = (max_wg_size / (32*cn) < 32) ? (max_wg_size / (16*cn) < 16) ? (max_wg_size / (8*cn) < 8) ? 1 : 8 : 16 : 32;
if (atrans)
A = A.t();
if (btrans)
B = B.t();
if (haveC)
ctrans ? transpose(matC, D) : matC.copyTo(D);
int vectorWidths[] = { 4, 4, 2, 2, 1, 4, cn, -1 };
int kercn = ocl::checkOptimalVectorWidth(vectorWidths, B, D);
opts += format(" -D T=%s -D T1=%s -D WT=%s -D cn=%d -D kercn=%d -D LOCAL_SIZE=%d%s%s%s",
ocl::typeToStr(type), ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)),
cn, kercn, block_size,
(sizeA.width % block_size !=0) ? " -D NO_MULT" : "",
haveC ? " -D HAVE_C" : "",
doubleSupport ? " -D DOUBLE_SUPPORT" : "");
ocl::Kernel k("gemm", cv::ocl::core::gemm_oclsrc, opts);
if (k.empty())
return false;
if (depth == CV_64F)
k.args(ocl::KernelArg::ReadOnlyNoSize(A),
ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn),
ocl::KernelArg::ReadWrite(D, cn, kercn),
sizeA.width, alpha, beta);
else
k.args(ocl::KernelArg::ReadOnlyNoSize(A),
ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn),
ocl::KernelArg::ReadWrite(D, cn, kercn),
sizeA.width, (float)alpha, (float)beta);
size_t globalsize[2] = { (size_t)sizeD.width * cn / kercn, (size_t)sizeD.height};
size_t localsize[2] = { (size_t)block_size, (size_t)block_size};
return k.run(2, globalsize, block_size!=1 ? localsize : NULL, false);
}
else
if (dev.intelSubgroupsSupport() && (depth == CV_32F) && cn == 1)
{
if (haveC && beta != 0.0)
{
ctrans ? transpose(matC, D) : matC.copyTo(D);
isPropagatedC2D = true;
}
else
{
beta = 0.0;
}
return intel_gpu_gemm(A, sizeA,
B, sizeB,
D, sizeD,
alpha,
beta,
atrans, btrans);
bool res = intel_gpu_gemm(A, matA.size(),
B, matB.size(),
D, sizeD,
alpha,
beta,
atrans, btrans,
isPropagatedC2D);
if (res)
return true;
// fallback on generic OpenCL code
}
if (sizeD.width < 8 || sizeD.height < 8)
return false;
String opts;
int wg_size = (int)dev.maxWorkGroupSize();
int sizeDmin = std::min(sizeD.width, sizeD.height);
wg_size = std::min(wg_size, sizeDmin * sizeDmin);
int block_size = (wg_size / (32*cn) < 32) ? (wg_size / (16*cn) < 16) ? (wg_size / (8*cn) < 8) ? 1 : 8 : 16 : 32;
if (atrans)
A = A.t();
if (btrans)
B = B.t();
if (haveC && !isPropagatedC2D)
ctrans ? transpose(matC, D) : matC.copyTo(D);
int vectorWidths[] = { 4, 4, 2, 2, 1, 4, cn, -1 };
int kercn = ocl::checkOptimalVectorWidth(vectorWidths, B, D);
opts += format(" -D T=%s -D T1=%s -D WT=%s -D cn=%d -D kercn=%d -D LOCAL_SIZE=%d%s%s%s",
ocl::typeToStr(type), ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)),
cn, kercn, block_size,
(sizeA.width % block_size !=0) ? " -D NO_MULT" : "",
haveC ? " -D HAVE_C" : "",
doubleSupport ? " -D DOUBLE_SUPPORT" : "");
ocl::Kernel k("gemm", cv::ocl::core::gemm_oclsrc, opts);
if (k.empty())
return false;
if (depth == CV_64F)
k.args(ocl::KernelArg::ReadOnlyNoSize(A),
ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn),
ocl::KernelArg::ReadWrite(D, cn, kercn),
sizeA.width, alpha, beta);
else
k.args(ocl::KernelArg::ReadOnlyNoSize(A),
ocl::KernelArg::ReadOnlyNoSize(B, cn, kercn),
ocl::KernelArg::ReadWrite(D, cn, kercn),
sizeA.width, (float)alpha, (float)beta);
size_t globalsize[2] = { (size_t)sizeD.width * cn / kercn, (size_t)sizeD.height};
size_t localsize[2] = { (size_t)block_size, (size_t)block_size};
return k.run(2, globalsize, block_size !=1 ? localsize : NULL, false);
}
#endif
+2 -3
View File
@@ -809,18 +809,17 @@ Mat::Mat(const Mat& m, const Rect& roi)
data += roi.x*esz;
CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
if( u )
CV_XADD(&u->refcount, 1);
if( roi.width < m.cols || roi.height < m.rows )
flags |= SUBMATRIX_FLAG;
step[0] = m.step[0]; step[1] = esz;
updateContinuityFlag();
addref();
if( rows <= 0 || cols <= 0 )
{
release();
rows = cols = 0;
release();
}
}
+4 -4
View File
@@ -229,14 +229,14 @@ void cv::setIdentity( InputOutputArray _m, const Scalar& s )
namespace cv {
UMat UMat::eye(int rows, int cols, int type)
UMat UMat::eye(int rows, int cols, int type, UMatUsageFlags usageFlags)
{
return UMat::eye(Size(cols, rows), type);
return UMat::eye(Size(cols, rows), type, usageFlags);
}
UMat UMat::eye(Size size, int type)
UMat UMat::eye(Size size, int type, UMatUsageFlags usageFlags)
{
UMat m(size, type);
UMat m(size, type, usageFlags);
setIdentity(m);
return m;
}
+1 -1
View File
@@ -1194,7 +1194,7 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask
// special case to handle "integer" overflow in accumulator
const size_t esz = src1.elemSize();
const int total = (int)it.size;
const int intSumBlockSize = normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15);
const int intSumBlockSize = (normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15))/cn;
const int blockSize = std::min(total, intSumBlockSize);
int isum = 0;
int count = 0;
+111 -25
View File
@@ -76,8 +76,11 @@
#undef CV__ALLOCATOR_STATS_LOG
#define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0
#define CV_OPENCL_SHOW_BUILD_OPTIONS 0
#define CV_OPENCL_SHOW_BUILD_KERNELS 0
#define CV_OPENCL_SHOW_RUN_KERNELS 0
#define CV_OPENCL_SYNC_RUN_KERNELS 0
#define CV_OPENCL_TRACE_CHECK 0
#define CV_OPENCL_VALIDATE_BINARY_PROGRAMS 1
@@ -1566,6 +1569,7 @@ struct Device::Impl
version_ = getStrProp(CL_DEVICE_VERSION);
extensions_ = getStrProp(CL_DEVICE_EXTENSIONS);
doubleFPConfig_ = getProp<cl_device_fp_config, int>(CL_DEVICE_DOUBLE_FP_CONFIG);
halfFPConfig_ = getProp<cl_device_fp_config, int>(CL_DEVICE_HALF_FP_CONFIG);
hostUnifiedMemory_ = getBoolProp(CL_DEVICE_HOST_UNIFIED_MEMORY);
maxComputeUnits_ = getProp<cl_uint, int>(CL_DEVICE_MAX_COMPUTE_UNITS);
maxWorkGroupSize_ = getProp<size_t, size_t>(CL_DEVICE_MAX_WORK_GROUP_SIZE);
@@ -1678,6 +1682,7 @@ struct Device::Impl
String version_;
std::string extensions_;
int doubleFPConfig_;
int halfFPConfig_;
bool hostUnifiedMemory_;
int maxComputeUnits_;
size_t maxWorkGroupSize_;
@@ -1827,11 +1832,7 @@ int Device::singleFPConfig() const
{ return p ? p->getProp<cl_device_fp_config, int>(CL_DEVICE_SINGLE_FP_CONFIG) : 0; }
int Device::halfFPConfig() const
#ifdef CL_VERSION_1_2
{ return p ? p->getProp<cl_device_fp_config, int>(CL_DEVICE_HALF_FP_CONFIG) : 0; }
#else
{ CV_REQUIRE_OPENCL_1_2_ERROR; }
#endif
{ return p ? p->halfFPConfig_ : 0; }
bool Device::endianLittle() const
{ return p ? p->getBoolProp(CL_DEVICE_ENDIAN_LITTLE) : false; }
@@ -2157,20 +2158,22 @@ static cl_device_id selectOpenCLDevice(const char* configuration = NULL)
platforms.resize(numPlatforms);
}
int selectedPlatform = -1;
if (platform.length() > 0)
{
for (size_t i = 0; i < platforms.size(); i++)
for (std::vector<cl_platform_id>::iterator currentPlatform = platforms.begin(); currentPlatform != platforms.end();)
{
std::string name;
CV_OCL_DBG_CHECK(getStringInfo(clGetPlatformInfo, platforms[i], CL_PLATFORM_NAME, name));
CV_OCL_DBG_CHECK(getStringInfo(clGetPlatformInfo, *currentPlatform, CL_PLATFORM_NAME, name));
if (name.find(platform) != std::string::npos)
{
selectedPlatform = (int)i;
break;
++currentPlatform;
}
else
{
currentPlatform = platforms.erase(currentPlatform);
}
}
if (selectedPlatform == -1)
if (platforms.size() == 0)
{
CV_LOG_ERROR(NULL, "OpenCL: Can't find OpenCL platform by name: " << platform);
goto not_found;
@@ -2207,13 +2210,11 @@ static cl_device_id selectOpenCLDevice(const char* configuration = NULL)
goto not_found;
}
std::vector<cl_device_id> devices; // TODO Use clReleaseDevice to cleanup
for (int i = selectedPlatform >= 0 ? selectedPlatform : 0;
(selectedPlatform >= 0 ? i == selectedPlatform : true) && (i < (int)platforms.size());
i++)
std::vector<cl_device_id> devices;
for (std::vector<cl_platform_id>::iterator currentPlatform = platforms.begin(); currentPlatform != platforms.end(); ++currentPlatform)
{
cl_uint count = 0;
cl_int status = clGetDeviceIDs(platforms[i], deviceType, 0, NULL, &count);
cl_int status = clGetDeviceIDs(*currentPlatform, deviceType, 0, NULL, &count);
if (!(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND))
{
CV_OCL_DBG_CHECK_RESULT(status, "clGetDeviceIDs get count");
@@ -2222,7 +2223,7 @@ static cl_device_id selectOpenCLDevice(const char* configuration = NULL)
continue;
size_t base = devices.size();
devices.resize(base + count);
status = clGetDeviceIDs(platforms[i], deviceType, count, &devices[base], &count);
status = clGetDeviceIDs(*currentPlatform, deviceType, count, &devices[base], &count);
if (!(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND))
{
CV_OCL_DBG_CHECK_RESULT(status, "clGetDeviceIDs get IDs");
@@ -3455,19 +3456,33 @@ struct Kernel::Impl
void cleanupUMats()
{
bool exceptionOccurred = false;
for( int i = 0; i < MAX_ARRS; i++ )
{
if( u[i] )
{
if( CV_XADD(&u[i]->urefcount, -1) == 1 )
{
u[i]->flags |= UMatData::ASYNC_CLEANUP;
u[i]->currAllocator->deallocate(u[i]);
try
{
u[i]->currAllocator->deallocate(u[i]);
}
catch(const std::exception& exc)
{
// limited by legacy before C++11, therefore log and
// remember some exception occurred to throw below
CV_LOG_ERROR(NULL, "OCL: Unexpected C++ exception in OpenCL Kernel::Impl::cleanupUMats(): " << exc.what());
exceptionOccurred = true;
}
}
u[i] = 0;
}
}
nu = 0;
haveTempDstUMats = false;
haveTempSrcUMats = false;
CV_Assert(!exceptionOccurred);
}
void addUMat(const UMat& m, bool dst)
@@ -3498,8 +3513,16 @@ struct Kernel::Impl
void finit(cl_event e)
{
CV_UNUSED(e);
cleanupUMats();
isInProgress = false;
try
{
cleanupUMats();
}
catch(...)
{
release();
throw;
}
release();
}
@@ -3657,6 +3680,10 @@ bool Kernel::empty() const
static cv::String dumpValue(size_t sz, const void* p)
{
if (!p)
return "NULL";
if (sz == 2)
return cv::format("%d / %uu / 0x%04x", *(short*)p, *(unsigned short*)p, *(short*)p);
if (sz == 4)
return cv::format("%d / %uu / 0x%08x / %g", *(int*)p, *(int*)p, *(int*)p, *(float*)p);
if (sz == 8)
@@ -3829,6 +3856,14 @@ bool Kernel::run(int dims, size_t _globalsize[], size_t _localsize[],
}
bool Kernel::run_(int dims, size_t _globalsize[], size_t _localsize[],
bool sync, const Queue& q)
{
CV_Assert(p);
return p->run(dims, _globalsize, _localsize, sync, NULL, q);
}
static bool isRaiseErrorOnReuseAsyncKernel()
{
static bool initialized = false;
@@ -3869,6 +3904,10 @@ bool Kernel::Impl::run(int dims, size_t globalsize[], size_t localsize[],
return false; // OpenCV 5.0: raise error
}
#if CV_OPENCL_SYNC_RUN_KERNELS
sync = true;
#endif
cl_command_queue qq = getQueue(q);
if (haveTempDstUMats)
sync = true;
@@ -4316,7 +4355,28 @@ struct Program::Impl
if (!param_buildExtraOptions.empty())
buildflags = joinBuildOptions(buildflags, param_buildExtraOptions);
}
#if CV_OPENCL_SHOW_BUILD_OPTIONS
CV_LOG_INFO(NULL, "OpenCL program '" << sourceModule_ << "/" << sourceName_ << "' options:" << buildflags);
#endif
compile(ctx, src_, errmsg);
#if CV_OPENCL_SHOW_BUILD_KERNELS
if (handle)
{
size_t retsz = 0;
char kernels_buffer[4096] = {0};
cl_int result = clGetProgramInfo(handle, CL_PROGRAM_KERNEL_NAMES, sizeof(kernels_buffer), &kernels_buffer[0], &retsz);
CV_OCL_DBG_CHECK_RESULT(result, cv::format("clGetProgramInfo(CL_PROGRAM_KERNEL_NAMES: %s/%s)", sourceModule_.c_str(), sourceName_.c_str()).c_str());
if (result == CL_SUCCESS && retsz < sizeof(kernels_buffer))
{
kernels_buffer[retsz] = 0;
CV_LOG_INFO(NULL, "OpenCL program '" << sourceModule_ << "/" << sourceName_ << "' kernels: '" << kernels_buffer << "'");
}
else
{
CV_LOG_ERROR(NULL, "OpenCL program '" << sourceModule_ << "/" << sourceName_ << "' can't retrieve kernel names!");
}
}
#endif
}
bool compile(const Context& ctx, const ProgramSource::Impl* src_, String& errmsg)
@@ -4548,7 +4608,6 @@ struct Program::Impl
CV_LOG_INFO(NULL, result << ": Kernels='" << kernels_buffer << "'");
}
#endif
}
return handle != NULL;
}
@@ -6668,6 +6727,10 @@ void convertFromImage(void* cl_mem_image, UMat& dst)
depth = CV_32F;
break;
case CL_HALF_FLOAT:
depth = CV_16F;
break;
default:
CV_Error(cv::Error::OpenCLApiCallError, "Not supported image_channel_data_type");
}
@@ -6676,9 +6739,23 @@ void convertFromImage(void* cl_mem_image, UMat& dst)
switch (fmt.image_channel_order)
{
case CL_R:
case CL_A:
case CL_INTENSITY:
case CL_LUMINANCE:
type = CV_MAKE_TYPE(depth, 1);
break;
case CL_RG:
case CL_RA:
type = CV_MAKE_TYPE(depth, 2);
break;
// CL_RGB has no mappings to OpenCV types because CL_RGB can only be used with
// CL_UNORM_SHORT_565, CL_UNORM_SHORT_555, or CL_UNORM_INT_101010.
/*case CL_RGB:
type = CV_MAKE_TYPE(depth, 3);
break;*/
case CL_RGBA:
case CL_BGRA:
case CL_ARGB:
@@ -7068,6 +7145,13 @@ static std::string kerToStr(const Mat & k)
stream << "DIG(" << data[i] << "f)";
stream << "DIG(" << data[width] << "f)";
}
else if (depth == CV_16F)
{
stream.setf(std::ios_base::showpoint);
for (int i = 0; i < width; ++i)
stream << "DIG(" << (float)data[i] << "h)";
stream << "DIG(" << (float)data[width] << "h)";
}
else
{
for (int i = 0; i < width; ++i)
@@ -7091,7 +7175,7 @@ String kernelToStr(InputArray _kernel, int ddepth, const char * name)
typedef std::string (* func_t)(const Mat &);
static const func_t funcs[] = { kerToStr<uchar>, kerToStr<char>, kerToStr<ushort>, kerToStr<short>,
kerToStr<int>, kerToStr<float>, kerToStr<double>, 0 };
kerToStr<int>, kerToStr<float>, kerToStr<double>, kerToStr<float16_t> };
const func_t func = funcs[ddepth];
CV_Assert(func != 0);
@@ -7130,14 +7214,14 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
int vectorWidths[] = { d.preferredVectorWidthChar(), d.preferredVectorWidthChar(),
d.preferredVectorWidthShort(), d.preferredVectorWidthShort(),
d.preferredVectorWidthInt(), d.preferredVectorWidthFloat(),
d.preferredVectorWidthDouble(), -1 };
d.preferredVectorWidthDouble(), d.preferredVectorWidthHalf() };
// if the device says don't use vectors
if (vectorWidths[0] == 1)
{
// it's heuristic
vectorWidths[CV_8U] = vectorWidths[CV_8S] = 4;
vectorWidths[CV_16U] = vectorWidths[CV_16S] = 2;
vectorWidths[CV_16U] = vectorWidths[CV_16S] = vectorWidths[CV_16F] = 2;
vectorWidths[CV_32S] = vectorWidths[CV_32F] = vectorWidths[CV_64F] = 1;
}
@@ -7225,10 +7309,12 @@ struct Image2D::Impl
{
cl_image_format format;
static const int channelTypes[] = { CL_UNSIGNED_INT8, CL_SIGNED_INT8, CL_UNSIGNED_INT16,
CL_SIGNED_INT16, CL_SIGNED_INT32, CL_FLOAT, -1, -1 };
CL_SIGNED_INT16, CL_SIGNED_INT32, CL_FLOAT, -1, CL_HALF_FLOAT };
static const int channelTypesNorm[] = { CL_UNORM_INT8, CL_SNORM_INT8, CL_UNORM_INT16,
CL_SNORM_INT16, -1, -1, -1, -1 };
static const int channelOrders[] = { -1, CL_R, CL_RG, -1, CL_RGBA };
// CL_RGB has no mappings to OpenCV types because CL_RGB can only be used with
// CL_UNORM_SHORT_565, CL_UNORM_SHORT_555, or CL_UNORM_INT_101010.
static const int channelOrders[] = { -1, CL_R, CL_RG, /*CL_RGB*/ -1, CL_RGBA };
int channelType = norm ? channelTypesNorm[depth] : channelTypes[depth];
int channelOrder = channelOrders[cn];
+82 -98
View File
@@ -392,6 +392,15 @@ __kernel void intelblas_gemm_buffer_NN(
#define TILE_N 8
#define SLM_BLOCK 512
/*
A K B.t() K D N
----------- ----------- -----------
| | | | | |
M | | x N | | => M | |
| | | | | |
----------- ----------- -----------
*/
__attribute__((reqd_work_group_size(8, LWG_HEIGHT, 1)))
__kernel void intelblas_gemm_buffer_NT(
const __global float *src0, int off0,
@@ -422,59 +431,79 @@ __kernel void intelblas_gemm_buffer_NT(
float8 dot06 = 0.f;
float8 dot07 = 0.f;
float4 brow0;
float4 brow1;
float4 brow2;
float4 brow3;
float4 brow4;
float4 brow5;
float4 brow6;
float4 brow7;
const int dst_row = (global_y * TILE_M);
__global float *dst_write0 = dst + global_x + dst_row * ldC + offd;
__global float *dst_write0 = dst + local_x * VEC_SIZE + ( group_x * TILE_N ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M) * ldC + offd;
const __global float *src0_read00 = src0 + off0;
const int a_row_base = global_y * TILE_M;
const int a_col_base = local_x * (TILE_K / 8); // <= TILE_K - 4
const __global float *src0_read = src0 + local_x * ( TILE_K / 8 ) + ( group_y * LWG_HEIGHT * TILE_M + local_y * TILE_M ) * ldA + off0;
const __global float *src1_read0 = src1 + ( group_x * TILE_N ) * ldB + off1;
const __global float *src1_read00 = src1 + off1;
const int b_row_base = (group_x * TILE_N);
//const int b_col_base = 0;
__local float slm_brow[8 * SLM_BLOCK];
__local float* slm_brow0;
int local_index = mad24(local_y, 8, local_x) * 4;
int w;
for(int b_tile = 0; b_tile < K; b_tile += SLM_BLOCK) {
int w = 0;
for (int b_tile = 0; b_tile < K; b_tile += SLM_BLOCK)
{
#define UPDATE_BROW(_row) \
{ \
float4 brow; \
int b_row = b_row_base + _row; \
int b_col = b_tile + local_index; \
if (b_row < N && b_col <= K - 4 /*vload4*/) \
brow = vload4(0, src1_read00 + mad24(b_row, ldB, b_col)); \
else \
brow = (float4)0; \
vstore4(brow, 0, slm_brow + mad24(_row, SLM_BLOCK, local_index)); \
}
barrier(CLK_LOCAL_MEM_FENCE);
vstore4(vload4(0, src1_read0 + mad24(0, ldB, local_index)), 0, slm_brow + mad24(0, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(1, ldB, local_index)), 0, slm_brow + mad24(1, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(2, ldB, local_index)), 0, slm_brow + mad24(2, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(3, ldB, local_index)), 0, slm_brow + mad24(3, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(4, ldB, local_index)), 0, slm_brow + mad24(4, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(5, ldB, local_index)), 0, slm_brow + mad24(5, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(6, ldB, local_index)), 0, slm_brow + mad24(6, SLM_BLOCK, local_index));
vstore4(vload4(0, src1_read0 + mad24(7, ldB, local_index)), 0, slm_brow + mad24(7, SLM_BLOCK, local_index));
UPDATE_BROW(0);
UPDATE_BROW(1);
UPDATE_BROW(2);
UPDATE_BROW(3);
UPDATE_BROW(4);
UPDATE_BROW(5);
UPDATE_BROW(6);
UPDATE_BROW(7);
barrier(CLK_LOCAL_MEM_FENCE);
#undef UPDATE_BROW
slm_brow0 = slm_brow + local_x * (TILE_K / 8);
w = b_tile;
int end_w = min(b_tile + SLM_BLOCK, K);
while( w + TILE_K <= end_w ) {
float4 arow;
for (int k_tile_offset = 0; k_tile_offset < SLM_BLOCK; k_tile_offset += TILE_K)
{
int a_col = a_col_base + b_tile + k_tile_offset;
brow0 = vload4(0, slm_brow0 + 0 * SLM_BLOCK);
brow1 = vload4(0, slm_brow0 + 1 * SLM_BLOCK);
brow2 = vload4(0, slm_brow0 + 2 * SLM_BLOCK);
brow3 = vload4(0, slm_brow0 + 3 * SLM_BLOCK);
brow4 = vload4(0, slm_brow0 + 4 * SLM_BLOCK);
brow5 = vload4(0, slm_brow0 + 5 * SLM_BLOCK);
brow6 = vload4(0, slm_brow0 + 6 * SLM_BLOCK);
brow7 = vload4(0, slm_brow0 + 7 * SLM_BLOCK);
if (a_col > K - 4 /*vload4*/)
break;
#define MM_DOT_PRODUCT(_row,_dot) \
arow = vload4(0, src0_read + _row * ldA); \
_dot = mad( (float8)(arow.x), (float8)(brow0.x, brow1.x, brow2.x, brow3.x, brow4.x, brow5.x, brow6.x, brow7.x), _dot ); \
_dot = mad( (float8)(arow.y), (float8)(brow0.y, brow1.y, brow2.y, brow3.y, brow4.y, brow5.y, brow6.y, brow7.y), _dot ); \
_dot = mad( (float8)(arow.z), (float8)(brow0.z, brow1.z, brow2.z, brow3.z, brow4.z, brow5.z, brow6.z, brow7.z), _dot ); \
_dot = mad( (float8)(arow.w), (float8)(brow0.w, brow1.w, brow2.w, brow3.w, brow4.w, brow5.w, brow6.w, brow7.w), _dot );
int slm_brow_col = a_col_base + k_tile_offset; // <= SLM_BLOCK - 4
#define READ_SLM_BROW(_row) \
float4 brow##_row = vload4(0, slm_brow + mad24(_row, SLM_BLOCK, slm_brow_col));
READ_SLM_BROW(0);
READ_SLM_BROW(1);
READ_SLM_BROW(2);
READ_SLM_BROW(3);
READ_SLM_BROW(4);
READ_SLM_BROW(5);
READ_SLM_BROW(6);
READ_SLM_BROW(7);
#undef READ_SLM_BROW
#define MM_DOT_PRODUCT(_row,_dot) \
{ \
int a_row = a_row_base + _row; \
if (a_row < M) { \
float4 arow = vload4(0, src0_read00 + mad24(a_row, ldA, a_col)); \
_dot = mad( (float8)(arow.x), (float8)(brow0.x, brow1.x, brow2.x, brow3.x, brow4.x, brow5.x, brow6.x, brow7.x), _dot ); \
_dot = mad( (float8)(arow.y), (float8)(brow0.y, brow1.y, brow2.y, brow3.y, brow4.y, brow5.y, brow6.y, brow7.y), _dot ); \
_dot = mad( (float8)(arow.z), (float8)(brow0.z, brow1.z, brow2.z, brow3.z, brow4.z, brow5.z, brow6.z, brow7.z), _dot ); \
_dot = mad( (float8)(arow.w), (float8)(brow0.w, brow1.w, brow2.w, brow3.w, brow4.w, brow5.w, brow6.w, brow7.w), _dot ); \
} \
}
MM_DOT_PRODUCT(0,dot00);
MM_DOT_PRODUCT(1,dot01);
@@ -485,53 +514,7 @@ __kernel void intelblas_gemm_buffer_NT(
MM_DOT_PRODUCT(6,dot06);
MM_DOT_PRODUCT(7,dot07);
#undef MM_DOT_PRODUCT
src0_read += TILE_K;
slm_brow0 += TILE_K;
w += TILE_K;
}
src1_read0 += SLM_BLOCK;
}
if(w < K) {
float4 arow;
#define READ_BROW(_brow,_row) \
_brow = vload4(0, slm_brow0 + _row * SLM_BLOCK); \
_brow.x = (mad24(local_x, 4, w) < K) ? _brow.x : 0.0f; \
_brow.y = (mad24(local_x, 4, w + 1) < K) ? _brow.y : 0.0f; \
_brow.z = (mad24(local_x, 4, w + 2) < K) ? _brow.z : 0.0f; \
_brow.w = (mad24(local_x, 4, w + 3) < K) ? _brow.w : 0.0f;
READ_BROW(brow0,0);
READ_BROW(brow1,1);
READ_BROW(brow2,2);
READ_BROW(brow3,3);
READ_BROW(brow4,4);
READ_BROW(brow5,5);
READ_BROW(brow6,6);
READ_BROW(brow7,7);
#define MM_DOT_PRODUCT(_row,_dot) \
arow = vload4(0, src0_read + _row * ldA); \
arow.x = (mad24(local_x, 4, w) < K) ? arow.x : 0.0f; \
arow.y = (mad24(local_x, 4, w + 1) < K) ? arow.y : 0.0f; \
arow.z = (mad24(local_x, 4, w + 2) < K) ? arow.z : 0.0f; \
arow.w = (mad24(local_x, 4, w + 3) < K) ? arow.w : 0.0f; \
_dot = mad( (float8)(arow.x), (float8)(brow0.x, brow1.x, brow2.x, brow3.x, brow4.x, brow5.x, brow6.x, brow7.x), _dot ); \
_dot = mad( (float8)(arow.y), (float8)(brow0.y, brow1.y, brow2.y, brow3.y, brow4.y, brow5.y, brow6.y, brow7.y), _dot ); \
_dot = mad( (float8)(arow.z), (float8)(brow0.z, brow1.z, brow2.z, brow3.z, brow4.z, brow5.z, brow6.z, brow7.z), _dot ); \
_dot = mad( (float8)(arow.w), (float8)(brow0.w, brow1.w, brow2.w, brow3.w, brow4.w, brow5.w, brow6.w, brow7.w), _dot );
MM_DOT_PRODUCT(0,dot00);
MM_DOT_PRODUCT(1,dot01);
MM_DOT_PRODUCT(2,dot02);
MM_DOT_PRODUCT(3,dot03);
MM_DOT_PRODUCT(4,dot04);
MM_DOT_PRODUCT(5,dot05);
MM_DOT_PRODUCT(6,dot06);
MM_DOT_PRODUCT(7,dot07);
#undef MM_DOT_PRODUCT
}
#define REDUCE(_dot) \
@@ -572,21 +555,22 @@ __kernel void intelblas_gemm_buffer_NT(
output = (local_x == 5) ? _dot.s5 : output; \
output = (local_x == 6) ? _dot.s6 : output; \
output = (local_x == 7) ? _dot.s7 : output; \
if (beta != 0.0) \
if (beta != 0.0f) \
dst_write0[0] = mad(output, (float)alpha, ((float)beta * dst_write0[0])); \
else \
dst_write0[0] = output * (float)alpha; \
dst_write0 += ldC;
if(global_x < N && global_y * 8 < M) {
OUTPUT(dot00);
if(mad24(global_y, 8, 1) < M) { OUTPUT(dot01); }
if(mad24(global_y, 8, 2) < M) { OUTPUT(dot02); }
if(mad24(global_y, 8, 3) < M) { OUTPUT(dot03); }
if(mad24(global_y, 8, 4) < M) { OUTPUT(dot04); }
if(mad24(global_y, 8, 5) < M) { OUTPUT(dot05); }
if(mad24(global_y, 8, 6) < M) { OUTPUT(dot06); }
if(mad24(global_y, 8, 7) < M) { OUTPUT(dot07); }
if (global_x < N && dst_row < M)
{
/*if (dst_row + 0 < M)*/ { OUTPUT(dot00); }
if (dst_row + 1 < M) { OUTPUT(dot01); }
if (dst_row + 2 < M) { OUTPUT(dot02); }
if (dst_row + 3 < M) { OUTPUT(dot03); }
if (dst_row + 4 < M) { OUTPUT(dot04); }
if (dst_row + 5 < M) { OUTPUT(dot05); }
if (dst_row + 6 < M) { OUTPUT(dot06); }
if (dst_row + 7 < M) { OUTPUT(dot07); }
}
#undef OUTPUT
}
+16 -4
View File
@@ -56,9 +56,9 @@
#undef abs
#endif
#if defined __linux__ || defined __APPLE__ || defined __GLIBC__ \
|| defined __HAIKU__ || defined __EMSCRIPTEN__ || defined __FreeBSD__ \
|| defined __OpenBSD__
#if defined __unix__ || defined __APPLE__ || defined __GLIBC__ \
|| defined __HAIKU__ || defined __EMSCRIPTEN__ \
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@@ -72,7 +72,7 @@
#endif
#endif
#if defined CV_CXX11
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <thread>
#endif
@@ -884,9 +884,11 @@ T minNonZero(const T& val_1, const T& val_2)
return (val_1 != 0) ? val_1 : val_2;
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
static
int getNumberOfCPUs_()
{
#ifndef OPENCV_SEMIHOSTING
/*
* Logic here is to try different methods of getting CPU counts and return
* the minimum most value as it has high probablity of being right and safe.
@@ -978,6 +980,9 @@ int getNumberOfCPUs_()
#endif
return ncpus != 0 ? ncpus : 1;
#else // OPENCV_SEMIHOSTING
return 1;
#endif //OPENCV_SEMIHOSTING
}
int getNumberOfCPUs()
@@ -986,6 +991,13 @@ int getNumberOfCPUs()
return nCPUs; // cached value
}
#else // OPENCV_DISABLE_THREAD_SUPPORT
int getNumberOfCPUs()
{
return 1;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
const char* currentParallelFramework()
{
std::shared_ptr<ParallelForAPI>& api = getCurrentParallelForAPI();
@@ -223,6 +223,9 @@ std::vector<FileSystemPath_t> getPluginCandidates(const std::string& baseName)
continue;
std::vector<std::string> candidates;
cv::glob(utils::fs::join(path, plugin_expr), candidates);
// Prefer candisates with higher versions
// TODO: implemented accurate versions-based comparator
std::sort(candidates.begin(), candidates.end(), std::greater<std::string>());
CV_LOG_DEBUG(NULL, " - " << path << ": " << candidates.size());
copy(candidates.begin(), candidates.end(), back_inserter(results));
}
+5
View File
@@ -580,6 +580,11 @@ void ThreadPool::run(const Range& range, const ParallelLoopBody& body, double ns
{
WorkerThread& thread = *(threads[i].get());
if (
#if defined(__clang__) && defined(__has_feature)
#if __has_feature(thread_sanitizer)
1 || // Robust workaround to avoid data race warning of `thread.job`
#endif
#endif
#if !defined(CV_USE_GLOBAL_WORKERS_COND_VAR)
thread.isActive ||
#endif
File diff suppressed because it is too large Load Diff
+18
View File
@@ -163,6 +163,24 @@ public:
CV_NORETURN
virtual void parseError(const char* funcname, const std::string& msg,
const char* filename, int lineno) = 0;
private:
enum Base64State{
Uncertain,
NotUse,
InUse,
};
friend class cv::FileStorage::Impl;
friend class cv::FileStorage;
friend class JSONEmitter;
friend class XMLEmitter;
friend class YAMLEmitter;
virtual void check_if_write_struct_is_delayed(bool change_type_to_base64 = false) = 0;
virtual void switch_to_Base64_state(Base64State state) = 0;
virtual Base64State get_state_of_writing_base64() = 0;
virtual int get_space() = 0;
};
class FileStorageEmitter
@@ -0,0 +1,370 @@
// 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
#include "precomp.hpp"
#include "persistence_impl.hpp"
#include "persistence_base64_encoding.hpp"
namespace cv
{
class base64::Base64ContextEmitter
{
public:
explicit Base64ContextEmitter(cv::FileStorage::Impl& fs, bool needs_indent_)
: file_storage(fs)
, needs_indent(needs_indent_)
, binary_buffer(BUFFER_LEN)
, base64_buffer(base64_encode_buffer_size(BUFFER_LEN))
, src_beg(0)
, src_cur(0)
, src_end(0)
{
src_beg = binary_buffer.data();
src_end = src_beg + BUFFER_LEN;
src_cur = src_beg;
CV_Assert(fs.write_mode);
if (needs_indent)
{
file_storage.flush();
}
}
~Base64ContextEmitter()
{
/* cleaning */
if (src_cur != src_beg)
flush(); /* encode the rest binary data to base64 buffer */
}
Base64ContextEmitter & write(const uchar * beg, const uchar * end)
{
if (beg >= end)
return *this;
while (beg < end) {
/* collect binary data and copy to binary buffer */
size_t len = std::min(end - beg, src_end - src_cur);
std::memcpy(src_cur, beg, len);
beg += len;
src_cur += len;
if (src_cur >= src_end) {
/* binary buffer is full. */
/* encode it to base64 and send result to fs */
flush();
}
}
return *this;
}
/*
* a convertor must provide :
* - `operator >> (uchar * & dst)` for writing current binary data to `dst` and moving to next data.
* - `operator bool` for checking if current loaction is valid and not the end.
*/
template<typename _to_binary_convertor_t> inline
Base64ContextEmitter & write(_to_binary_convertor_t & convertor)
{
static const size_t BUFFER_MAX_LEN = 1024U;
std::vector<uchar> buffer(BUFFER_MAX_LEN);
uchar * beg = buffer.data();
uchar * end = beg;
while (convertor) {
convertor >> end;
write(beg, end);
end = beg;
}
return *this;
}
bool flush()
{
/* control line width, so on. */
size_t len = base64_encode(src_beg, base64_buffer.data(), 0U, src_cur - src_beg);
if (len == 0U)
return false;
src_cur = src_beg;
if ( !needs_indent)
{
file_storage.puts((const char*)base64_buffer.data());
}
else
{
const char newline[] = "\n";
char space[80];
int ident = file_storage.write_stack.back().indent;
memset(space, ' ', static_cast<int>(ident));
space[ident] = '\0';
file_storage.puts(space);
file_storage.puts((const char*)base64_buffer.data());
file_storage.puts(newline);
file_storage.flush();
}
return true;
}
private:
/* because of Base64, we must keep its length a multiple of 3 */
static const size_t BUFFER_LEN = 48U;
// static_assert(BUFFER_LEN % 3 == 0, "BUFFER_LEN is invalid");
private:
cv::FileStorage::Impl& file_storage;
bool needs_indent;
std::vector<uchar> binary_buffer;
std::vector<uchar> base64_buffer;
uchar * src_beg;
uchar * src_cur;
uchar * src_end;
};
std::string base64::make_base64_header(const char *dt) {
std::ostringstream oss;
oss << dt << ' ';
std::string buffer(oss.str());
CV_Assert(buffer.size() < ::base64::HEADER_SIZE);
buffer.reserve(::base64::HEADER_SIZE);
while (buffer.size() < ::base64::HEADER_SIZE)
buffer += ' ';
return buffer;
}
size_t base64::base64_encode(const uint8_t *src, uint8_t *dst, size_t off, size_t cnt) {
if (!src || !dst || !cnt)
return 0;
/* initialize beginning and end */
uint8_t * dst_beg = dst;
uint8_t * dst_cur = dst_beg;
uint8_t const * src_beg = src + off;
uint8_t const * src_cur = src_beg;
uint8_t const * src_end = src_cur + cnt / 3U * 3U;
/* integer multiples part */
while (src_cur < src_end) {
uint8_t _2 = *src_cur++;
uint8_t _1 = *src_cur++;
uint8_t _0 = *src_cur++;
*dst_cur++ = base64_mapping[ _2 >> 2U];
*dst_cur++ = base64_mapping[(_1 & 0xF0U) >> 4U | (_2 & 0x03U) << 4U];
*dst_cur++ = base64_mapping[(_0 & 0xC0U) >> 6U | (_1 & 0x0FU) << 2U];
*dst_cur++ = base64_mapping[ _0 & 0x3FU];
}
/* remainder part */
size_t rst = src_beg + cnt - src_cur;
if (rst == 1U) {
uint8_t _2 = *src_cur++;
*dst_cur++ = base64_mapping[ _2 >> 2U];
*dst_cur++ = base64_mapping[(_2 & 0x03U) << 4U];
} else if (rst == 2U) {
uint8_t _2 = *src_cur++;
uint8_t _1 = *src_cur++;
*dst_cur++ = base64_mapping[ _2 >> 2U];
*dst_cur++ = base64_mapping[(_2 & 0x03U) << 4U | (_1 & 0xF0U) >> 4U];
*dst_cur++ = base64_mapping[(_1 & 0x0FU) << 2U];
}
/* padding */
switch (rst)
{
case 1U: *dst_cur++ = base64_padding;
/* fallthrough */
case 2U: *dst_cur++ = base64_padding;
/* fallthrough */
default: *dst_cur = 0;
break;
}
return static_cast<size_t>(dst_cur - dst_beg);
}
int base64::icvCalcStructSize(const char *dt, int initial_size) {
int size = cv::fs::calcElemSize( dt, initial_size );
size_t elem_max_size = 0;
for ( const char * type = dt; *type != '\0'; type++ ) {
switch ( *type )
{
case 'u': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; }
case 'c': { elem_max_size = std::max( elem_max_size, sizeof(schar ) ); break; }
case 'w': { elem_max_size = std::max( elem_max_size, sizeof(ushort) ); break; }
case 's': { elem_max_size = std::max( elem_max_size, sizeof(short ) ); break; }
case 'i': { elem_max_size = std::max( elem_max_size, sizeof(int ) ); break; }
case 'f': { elem_max_size = std::max( elem_max_size, sizeof(float ) ); break; }
case 'd': { elem_max_size = std::max( elem_max_size, sizeof(double) ); break; }
default: break;
}
}
size = cvAlign( size, static_cast<int>(elem_max_size) );
return size;
}
size_t base64::base64_encode_buffer_size(size_t cnt, bool is_end_with_zero) {
size_t additional = static_cast<size_t>(is_end_with_zero == true);
return (cnt + 2U) / 3U * 4U + additional;
}
base64::Base64Writer::Base64Writer(cv::FileStorage::Impl& fs, bool can_indent)
: emitter(new Base64ContextEmitter(fs, can_indent))
, data_type_string()
{
CV_Assert(fs.write_mode);
}
void base64::Base64Writer::write(const void* _data, size_t len, const char* dt)
{
check_dt(dt);
RawDataToBinaryConvertor convertor(_data, static_cast<int>(len), data_type_string);
emitter->write(convertor);
}
template<typename _to_binary_convertor_t> inline
void base64::Base64Writer::write(_to_binary_convertor_t & convertor, const char* dt)
{
check_dt(dt);
emitter->write(convertor);
}
base64::Base64Writer::~Base64Writer()
{
delete emitter;
}
void base64::Base64Writer::check_dt(const char* dt)
{
if ( dt == 0 )
CV_Error( cv::Error::StsBadArg, "Invalid \'dt\'." );
else if (data_type_string.empty()) {
data_type_string = dt;
/* output header */
std::string buffer = make_base64_header(dt);
const uchar * beg = reinterpret_cast<const uchar *>(buffer.data());
const uchar * end = beg + buffer.size();
emitter->write(beg, end);
} else if ( data_type_string != dt )
CV_Error( cv::Error::StsBadArg, "\'dt\' does not match." );
}
base64::RawDataToBinaryConvertor::RawDataToBinaryConvertor(const void* src, int len, const std::string & dt)
: beg(reinterpret_cast<const uchar *>(src))
, cur(0)
, end(0)
{
CV_Assert(src);
CV_Assert(!dt.empty());
CV_Assert(len > 0);
/* calc step and to_binary_funcs */
step_packed = make_to_binary_funcs(dt);
end = beg;
cur = beg;
step = icvCalcStructSize(dt.c_str(), 0);
end = beg + static_cast<size_t>(len);
}
inline base64::RawDataToBinaryConvertor& base64::RawDataToBinaryConvertor::operator >>(uchar * & dst)
{
CV_DbgAssert(*this);
for (size_t i = 0U, n = to_binary_funcs.size(); i < n; i++) {
elem_to_binary_t & pack = to_binary_funcs[i];
pack.func(cur + pack.offset, dst + pack.offset_packed);
}
cur += step;
dst += step_packed;
return *this;
}
inline base64::RawDataToBinaryConvertor::operator bool() const
{
return cur < end;
}
size_t base64::RawDataToBinaryConvertor::make_to_binary_funcs(const std::string &dt)
{
size_t cnt = 0;
size_t offset = 0;
size_t offset_packed = 0;
char type = '\0';
std::istringstream iss(dt);
while (!iss.eof()) {
if (!(iss >> cnt)) {
iss.clear();
cnt = 1;
}
CV_Assert(cnt > 0U);
if (!(iss >> type))
break;
while (cnt-- > 0)
{
elem_to_binary_t pack;
size_t size = 0;
switch (type)
{
case 'u':
case 'c':
size = sizeof(uchar);
pack.func = to_binary<uchar>;
break;
case 'w':
case 's':
size = sizeof(ushort);
pack.func = to_binary<ushort>;
break;
case 'i':
size = sizeof(uint);
pack.func = to_binary<uint>;
break;
case 'f':
size = sizeof(float);
pack.func = to_binary<float>;
break;
case 'd':
size = sizeof(double);
pack.func = to_binary<double>;
break;
case 'r':
default:
CV_Error(cv::Error::StsError, "type is not supported");
};
offset = static_cast<size_t>(cvAlign(static_cast<int>(offset), static_cast<int>(size)));
pack.offset = offset;
offset += size;
pack.offset_packed = offset_packed;
offset_packed += size;
to_binary_funcs.push_back(pack);
}
}
CV_Assert(iss.eof());
return offset_packed;
}
}
@@ -0,0 +1,127 @@
// 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
#ifndef OPENCV_CORE_BASE64_ENCODING_HPP
#define OPENCV_CORE_BASE64_ENCODING_HPP
namespace cv
{
namespace base64
{
/* A decorator for CvFileStorage
* - no copyable
* - not safe for now
* - move constructor may be needed if C++11
*/
uint8_t const base64_mapping[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
uint8_t const base64_padding = '=';
std::string make_base64_header(const char * dt);
size_t base64_encode(uint8_t const * src, uint8_t * dst, size_t off, size_t cnt);
int icvCalcStructSize( const char* dt, int initial_size );
class Base64ContextEmitter;
class Impl;
class Base64Writer
{
public:
Base64Writer(cv::FileStorage::Impl& fs, bool can_indent);
~Base64Writer();
void write(const void* _data, size_t len, const char* dt);
template<typename _to_binary_convertor_t> void write(_to_binary_convertor_t & convertor, const char* dt);
private:
void check_dt(const char* dt);
private:
// disable copy and assignment
Base64Writer(const Base64Writer &);
Base64Writer & operator=(const Base64Writer &);
private:
Base64ContextEmitter * emitter;
std::string data_type_string;
};
size_t base64_encode_buffer_size(size_t cnt, bool is_end_with_zero = true);
template<typename _uint_t> inline size_t
to_binary(_uint_t val, uchar * cur)
{
size_t delta = CHAR_BIT;
size_t cnt = sizeof(_uint_t);
while (cnt --> static_cast<size_t>(0U)) {
*cur++ = static_cast<uchar>(val);
val >>= delta;
}
return sizeof(_uint_t);
}
template<> inline size_t to_binary(double val, uchar * cur)
{
Cv64suf bit64;
bit64.f = val;
return to_binary(bit64.u, cur);
}
template<> inline size_t to_binary(float val, uchar * cur)
{
Cv32suf bit32;
bit32.f = val;
return to_binary(bit32.u, cur);
}
template<typename _primitive_t> inline size_t
to_binary(uchar const * val, uchar * cur)
{
return to_binary<_primitive_t>(*reinterpret_cast<_primitive_t const *>(val), cur);
}
class RawDataToBinaryConvertor
{
public:
// NOTE: len is already multiplied by element size here
RawDataToBinaryConvertor(const void* src, int len, const std::string & dt);
inline RawDataToBinaryConvertor & operator >>(uchar * & dst);
inline operator bool() const;
private:
typedef size_t(*to_binary_t)(const uchar *, uchar *);
struct elem_to_binary_t
{
size_t offset;
size_t offset_packed;
to_binary_t func;
};
private:
size_t make_to_binary_funcs(const std::string &dt);
private:
const uchar * beg;
const uchar * cur;
const uchar * end;
size_t step;
size_t step_packed;
std::vector<elem_to_binary_t> to_binary_funcs;
};
}
}
#endif
+231
View File
@@ -0,0 +1,231 @@
// 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
#ifndef OPENCV_CORE_PERSISTENCE_IMPL_HPP
#define OPENCV_CORE_PERSISTENCE_IMPL_HPP
#include "persistence.hpp"
#include "persistence_base64_encoding.hpp"
#include <unordered_map>
#include <iterator>
namespace cv
{
enum Base64State{
Uncertain,
NotUse,
InUse,
};
class cv::FileStorage::Impl : public FileStorage_API
{
public:
void init();
Impl(FileStorage* _fs);
virtual ~Impl();
void release(String* out=0);
void analyze_file_name( const std::string& file_name, std::vector<std::string>& params );
bool open( const char* filename_or_buf, int _flags, const char* encoding );
void puts( const char* str );
char* getsFromFile( char* buf, int count );
char* gets( size_t maxCount );
char* gets();
bool eof();
void setEof();
void closeFile();
void rewind();
char* resizeWriteBuffer( char* ptr, int len );
char* flush();
void endWriteStruct();
void startWriteStruct_helper( const char* key, int struct_flags,
const char* type_name );
void startWriteStruct( const char* key, int struct_flags,
const char* type_name );
void writeComment( const char* comment, bool eol_comment );
void startNextStream();
void write( const String& key, int value );
void write( const String& key, double value );
void write( const String& key, const String& value );
void writeRawData( const std::string& dt, const void* _data, size_t len );
void workaround();
void switch_to_Base64_state( FileStorage_API::Base64State new_state);
void make_write_struct_delayed( const char* key, int struct_flags, const char* type_name );
void check_if_write_struct_is_delayed( bool change_type_to_base64 );
void writeRawDataBase64(const void* _data, size_t len, const char* dt );
String releaseAndGetString();
FileNode getFirstTopLevelNode() const;
FileNode root(int streamIdx=0) const;
FileNode operator[](const String& nodename) const;
FileNode operator[](const char* /*nodename*/) const;
int getFormat() const;
char* bufferPtr() const;
char* bufferStart() const;
char* bufferEnd() const;
void setBufferPtr(char* ptr);
int wrapMargin() const;
FStructData& getCurrentStruct();
void setNonEmpty();
void processSpecialDouble( char* buf, double* value, char** endptr );
double strtod( char* ptr, char** endptr );
void convertToCollection(int type, FileNode& node);
// a) allocates new FileNode (for that just set blockIdx to the last block and ofs to freeSpaceOfs) or
// b) reallocates just created new node (blockIdx and ofs must be taken from FileNode).
// If there is no enough space in the current block (it should be the last block added so far),
// the last block is shrunk so that it ends immediately before the reallocated node. Then,
// a new block of sufficient size is allocated and the FileNode is placed in the beginning of it.
// The case (a) can be used to allocate the very first node by setting blockIdx == ofs == 0.
// In the case (b) the existing tag and the name are copied automatically.
uchar* reserveNodeSpace(FileNode& node, size_t sz);
unsigned getStringOfs( const std::string& key ) const;
FileNode addNode( FileNode& collection, const std::string& key,
int elem_type, const void* value, int len );
void finalizeCollection( FileNode& collection );
void normalizeNodeOfs(size_t& blockIdx, size_t& ofs) const;
Base64State get_state_of_writing_base64();
int get_space();
class Base64Decoder
{
public:
Base64Decoder();
void init(Ptr<FileStorageParser>& _parser, char* _ptr, int _indent);
bool readMore(int needed);
uchar getUInt8();
ushort getUInt16();
int getInt32();
double getFloat64();
bool endOfStream() const;
char* getPtr() const;
protected:
Ptr<FileStorageParser> parser;
char* ptr;
int indent;
std::vector<char> encoded;
std::vector<uchar> decoded;
size_t ofs;
size_t totalchars;
bool eos;
};
char* parseBase64(char* ptr, int indent, FileNode& collection);
void parseError( const char* func_name, const std::string& err_msg, const char* source_file, int source_line );
const uchar* getNodePtr(size_t blockIdx, size_t ofs) const;
std::string getName( size_t nameofs ) const;
FileStorage* getFS();
FileStorage* fs_ext;
std::string filename;
int flags;
bool empty_stream;
FILE* file;
gzFile gzfile;
bool is_opened;
bool dummy_eof;
bool write_mode;
bool mem_mode;
int fmt;
State state; //!< current state of the FileStorage (used only for writing)
bool is_using_base64;
bool is_write_struct_delayed;
char* delayed_struct_key;
int delayed_struct_flags;
char* delayed_type_name;
FileStorage_API::Base64State state_of_writing_base64;
int space, wrap_margin;
std::deque<FStructData> write_stack;
std::vector<char> buffer;
size_t bufofs;
std::deque<char> outbuf;
Ptr<FileStorageEmitter> emitter;
Ptr<FileStorageParser> parser;
Base64Decoder base64decoder;
base64::Base64Writer* base64_writer;
std::vector<FileNode> roots;
std::vector<Ptr<std::vector<uchar> > > fs_data;
std::vector<uchar*> fs_data_ptrs;
std::vector<size_t> fs_data_blksz;
size_t freeSpaceOfs;
typedef std::unordered_map<std::string, unsigned> str_hash_t;
str_hash_t str_hash;
std::vector<char> str_hash_data;
std::vector<char> strbufv;
char* strbuf;
size_t strbufsize;
size_t strbufpos;
int lineno;
};
}
#endif
+40 -29
View File
@@ -23,7 +23,7 @@ public:
struct_flags = (struct_flags & (FileNode::TYPE_MASK|FileNode::FLOW)) | FileNode::EMPTY;
if( !FileNode::isCollection(struct_flags))
CV_Error( CV_StsBadArg,
CV_Error( cv::Error::StsBadArg,
"Some collection type - FileNode::SEQ or FileNode::MAP, must be specified" );
if( type_name && *type_name == '\0' )
@@ -53,29 +53,26 @@ public:
void endWriteStruct(const FStructData& current_struct)
{
int struct_flags = current_struct.flags;
CV_Assert( FileNode::isCollection(struct_flags) );
if( !FileNode::isFlow(struct_flags) )
{
#if 0
if ( fs->bufferPtr() <= fs->bufferStart() + fs->space )
{
/* some bad code for base64_writer... */
ptr = fs->bufferPtr();
*ptr++ = '\n';
*ptr++ = '\0';
fs->puts( fs->bufferStart() );
fs->setBufferPtr(fs->bufferStart());
if (FileNode::isCollection(struct_flags)) {
if (!FileNode::isFlow(struct_flags)) {
if (fs->bufferPtr() <= fs->bufferStart() + fs->get_space()) {
/* some bad code for base64_writer... */
char *ptr = fs->bufferPtr();
*ptr++ = '\n';
*ptr++ = '\0';
fs->puts(fs->bufferStart());
fs->setBufferPtr(fs->bufferStart());
}
fs->flush();
}
#endif
fs->flush();
}
char* ptr = fs->bufferPtr();
if( ptr > fs->bufferStart() + current_struct.indent && !FileNode::isEmptyCollection(struct_flags) )
*ptr++ = ' ';
*ptr++ = FileNode::isMap(struct_flags) ? '}' : ']';
fs->setBufferPtr(ptr);
char *ptr = fs->bufferPtr();
if (ptr > fs->bufferStart() + current_struct.indent && !FileNode::isEmptyCollection(struct_flags))
*ptr++ = ' ';
*ptr++ = FileNode::isMap(struct_flags) ? '}' : ']';
fs->setBufferPtr(ptr);
}
}
void write(const char* key, int value)
@@ -97,11 +94,11 @@ public:
int i, len;
if( !str )
CV_Error( CV_StsNullPtr, "Null string pointer" );
CV_Error( cv::Error::StsNullPtr, "Null string pointer" );
len = (int)strlen(str);
if( len > CV_FS_MAX_LEN )
CV_Error( CV_StsBadArg, "The written string is too long" );
CV_Error( cv::Error::StsBadArg, "The written string is too long" );
if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
{
@@ -136,6 +133,20 @@ public:
void writeScalar(const char* key, const char* data)
{
/* check write_struct */
fs->check_if_write_struct_is_delayed(false);
if ( fs->get_state_of_writing_base64() == FileStorage_API::Uncertain )
{
fs->switch_to_Base64_state( FileStorage_API::NotUse );
}
else if ( fs->get_state_of_writing_base64() == FileStorage_API::InUse )
{
CV_Error( cv::Error::StsError, "At present, output Base64 data only." );
}
/* check parameters */
size_t key_len = 0u;
if( key && *key == '\0' )
key = 0;
@@ -143,9 +154,9 @@ public:
{
key_len = strlen(key);
if ( key_len == 0u )
CV_Error( CV_StsBadArg, "The key is an empty" );
CV_Error( cv::Error::StsBadArg, "The key is an empty" );
else if ( static_cast<int>(key_len) > CV_FS_MAX_LEN )
CV_Error( CV_StsBadArg, "The key is too long" );
CV_Error( cv::Error::StsBadArg, "The key is too long" );
}
size_t data_len = 0u;
@@ -157,7 +168,7 @@ public:
if( FileNode::isCollection(struct_flags) )
{
if ( (FileNode::isMap(struct_flags) ^ (key != 0)) )
CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
CV_Error( cv::Error::StsBadArg, "An attempt to add element without a key to a map, "
"or add element with key to sequence" );
} else {
fs->setNonEmpty();
@@ -199,7 +210,7 @@ public:
if( key )
{
if( !cv_isalpha(key[0]) && key[0] != '_' )
CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
CV_Error( cv::Error::StsBadArg, "Key must start with a letter or _" );
ptr = fs->resizeWriteBuffer( ptr, static_cast<int>(key_len) );
*ptr++ = '\"';
@@ -210,7 +221,7 @@ public:
ptr[i] = c;
if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
CV_Error( cv::Error::StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
}
ptr += key_len;
@@ -233,7 +244,7 @@ public:
void writeComment(const char* comment, bool eol_comment)
{
if( !comment )
CV_Error( CV_StsNullPtr, "Null comment" );
CV_Error( cv::Error::StsNullPtr, "Null comment" );
int len = static_cast<int>(strlen(comment));
char* ptr = fs->bufferPtr();
+20 -10
View File
@@ -45,7 +45,7 @@ public:
if( FileNode::isCollection(struct_flags) )
{
if( FileNode::isMap(struct_flags) ^ (key != 0) )
CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
CV_Error( cv::Error::StsBadArg, "An attempt to add element without a key to a map, "
"or add element with key to sequence" );
}
else
@@ -61,26 +61,26 @@ public:
if( !key )
key = "_";
else if( key[0] == '_' && key[1] == '\0' )
CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" );
CV_Error( cv::Error::StsBadArg, "A single _ is a reserved tag name" );
len = (int)strlen( key );
*ptr++ = '<';
if( tag_type == CV_XML_CLOSING_TAG )
{
if( !attrlist.empty() )
CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" );
CV_Error( cv::Error::StsBadArg, "Closing tag should not include any attributes" );
*ptr++ = '/';
}
if( !cv_isalpha(key[0]) && key[0] != '_' )
CV_Error( CV_StsBadArg, "Key should start with a letter or _" );
CV_Error( cv::Error::StsBadArg, "Key should start with a letter or _" );
ptr = fs->resizeWriteBuffer( ptr, len );
for( i = 0; i < len; i++ )
{
char c = key[i];
if( !cv_isalnum(c) && c != '_' && c != '-' )
CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" );
CV_Error( cv::Error::StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" );
ptr[i] = c;
}
ptr += len;
@@ -158,11 +158,11 @@ public:
int i, len;
if( !str )
CV_Error( CV_StsNullPtr, "Null string pointer" );
CV_Error( cv::Error::StsNullPtr, "Null string pointer" );
len = (int)strlen(str);
if( len > CV_FS_MAX_LEN )
CV_Error( CV_StsBadArg, "The written string is too long" );
CV_Error( cv::Error::StsBadArg, "The written string is too long" );
if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] )
{
@@ -233,6 +233,16 @@ public:
void writeScalar(const char* key, const char* data)
{
fs->check_if_write_struct_is_delayed(false);
if ( fs->get_state_of_writing_base64() == FileStorage_API::Uncertain )
{
fs->switch_to_Base64_state( FileStorage_API::NotUse );
}
else if ( fs->get_state_of_writing_base64() == FileStorage_API::InUse )
{
CV_Error( cv::Error::StsError, "At present, output Base64 data only." );
}
int len = (int)strlen(data);
if( key && *key == '\0' )
key = 0;
@@ -255,7 +265,7 @@ public:
int new_offset = (int)(ptr - fs->bufferStart()) + len;
if( key )
CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" );
CV_Error( cv::Error::StsBadArg, "elements with keys can not be written to sequence" );
current_struct.flags = FileNode::SEQ;
@@ -281,10 +291,10 @@ public:
char* ptr;
if( !comment )
CV_Error( CV_StsNullPtr, "Null comment" );
CV_Error( cv::Error::StsNullPtr, "Null comment" );
if( strstr(comment, "--") != 0 )
CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );
CV_Error( cv::Error::StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );
len = (int)strlen(comment);
eol = strchr(comment, '\n');
+19 -9
View File
@@ -33,7 +33,7 @@ public:
struct_flags = (struct_flags & (FileNode::TYPE_MASK|FileNode::FLOW)) | FileNode::EMPTY;
if( !FileNode::isCollection(struct_flags))
CV_Error( CV_StsBadArg,
CV_Error( cv::Error::StsBadArg,
"Some collection type - FileNode::SEQ or FileNode::MAP, must be specified" );
if (type_name && memcmp(type_name, "binary", 6) == 0)
@@ -120,11 +120,11 @@ public:
int i, len;
if( !str )
CV_Error( CV_StsNullPtr, "Null string pointer" );
CV_Error( cv::Error::StsNullPtr, "Null string pointer" );
len = (int)strlen(str);
if( len > CV_FS_MAX_LEN )
CV_Error( CV_StsBadArg, "The written string is too long" );
CV_Error( cv::Error::StsBadArg, "The written string is too long" );
if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
{
@@ -174,6 +174,16 @@ public:
void writeScalar(const char* key, const char* data)
{
fs->check_if_write_struct_is_delayed(false);
if ( fs->get_state_of_writing_base64() == FileStorage_API::Uncertain )
{
fs->switch_to_Base64_state( FileStorage_API::NotUse );
}
else if ( fs->get_state_of_writing_base64() == FileStorage_API::InUse )
{
CV_Error( cv::Error::StsError, "At present, output Base64 data only." );
}
int i, keylen = 0;
int datalen = 0;
char* ptr;
@@ -188,7 +198,7 @@ public:
if( FileNode::isCollection(struct_flags) )
{
if( (FileNode::isMap(struct_flags) ^ (key != 0)) )
CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
CV_Error( cv::Error::StsBadArg, "An attempt to add element without a key to a map, "
"or add element with key to sequence" );
}
else
@@ -201,10 +211,10 @@ public:
{
keylen = (int)strlen(key);
if( keylen == 0 )
CV_Error( CV_StsBadArg, "The key is an empty" );
CV_Error( cv::Error::StsBadArg, "The key is an empty" );
if( keylen > CV_FS_MAX_LEN )
CV_Error( CV_StsBadArg, "The key is too long" );
CV_Error( cv::Error::StsBadArg, "The key is too long" );
}
if( data )
@@ -238,7 +248,7 @@ public:
if( key )
{
if( !cv_isalpha(key[0]) && key[0] != '_' )
CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
CV_Error( cv::Error::StsBadArg, "Key must start with a letter or _" );
ptr = fs->resizeWriteBuffer( ptr, keylen );
@@ -248,7 +258,7 @@ public:
ptr[i] = c;
if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
CV_Error( cv::Error::StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
}
ptr += keylen;
@@ -271,7 +281,7 @@ public:
void writeComment(const char* comment, bool eol_comment)
{
if( !comment )
CV_Error( CV_StsNullPtr, "Null comment" );
CV_Error( cv::Error::StsNullPtr, "Null comment" );
int len = (int)strlen(comment);
const char* eol = strchr(comment, '\n');
+212 -58
View File
@@ -55,6 +55,18 @@
#include <opencv2/core/utils/filesystem.private.hpp>
#ifndef OPENCV_WITH_THREAD_SANITIZER
#if defined(__clang__) && defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define OPENCV_WITH_THREAD_SANITIZER 1
#include <atomic> // assume C++11
#endif
#endif
#endif
#ifndef OPENCV_WITH_THREAD_SANITIZER
#define OPENCV_WITH_THREAD_SANITIZER 0
#endif
namespace cv {
static void _initSystem()
@@ -116,10 +128,14 @@ void* allocSingletonNewBuffer(size_t size) { return malloc(size); }
#include <cstdlib> // std::abort
#endif
#if defined __ANDROID__ || defined __linux__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __HAIKU__ || defined __Fuchsia__
#if defined __ANDROID__ || defined __unix__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __HAIKU__ || defined __Fuchsia__
# include <unistd.h>
# include <fcntl.h>
#if defined __QNXNTO__
# include <sys/elf.h>
#else
# include <elf.h>
#endif
#if defined __ANDROID__ || defined __linux__
# include <linux/auxvec.h>
#endif
@@ -130,7 +146,7 @@ void* allocSingletonNewBuffer(size_t size) { return malloc(size); }
#endif
#if (defined __ppc64__ || defined __PPC64__) && defined __linux__
#if (defined __ppc64__ || defined __PPC64__) && defined __unix__
# include "sys/auxv.h"
# ifndef AT_HWCAP2
# define AT_HWCAP2 26
@@ -216,7 +232,9 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix)
#endif
#else
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <pthread.h>
#endif
#include <sys/time.h>
#include <time.h>
@@ -231,7 +249,7 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix)
#include "omp.h"
#endif
#if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__ || defined __FreeBSD__ || defined __GLIBC__ || defined __HAIKU__
#if defined __unix__ || defined __APPLE__ || defined __EMSCRIPTEN__ || defined __FreeBSD__ || defined __GLIBC__ || defined __HAIKU__
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@@ -533,7 +551,7 @@ struct HWFeatures
}
#endif // CV_CPUID_X86
#if defined __ANDROID__ || defined __linux__
#if defined __ANDROID__ || defined __linux__ || defined __FreeBSD__
#ifdef __aarch64__
have[CV_CPU_NEON] = true;
have[CV_CPU_FP16] = true;
@@ -559,7 +577,7 @@ struct HWFeatures
CV_LOG_INFO(NULL, "- FP16 instructions is NOT enabled via build flags");
#endif
#endif
#elif defined __arm__
#elif defined __arm__ && !defined __FreeBSD__
int cpufile = open("/proc/self/auxv", O_RDONLY);
if (cpufile >= 0)
@@ -598,7 +616,7 @@ struct HWFeatures
have[CV_CPU_MSA] = true;
#endif
#if (defined __ppc64__ || defined __PPC64__) && defined __linux__
#if (defined __ppc64__ || defined __PPC64__) && defined __unix__
unsigned int hwcap = getauxval(AT_HWCAP);
if (hwcap & PPC_FEATURE_HAS_VSX) {
hwcap = getauxval(AT_HWCAP2);
@@ -812,12 +830,12 @@ int64 getTickCount(void)
LARGE_INTEGER counter;
QueryPerformanceCounter( &counter );
return (int64)counter.QuadPart;
#elif defined __linux || defined __linux__
#elif defined __MACH__ && defined __APPLE__
return (int64)mach_absolute_time();
#elif defined __unix__
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return (int64)tp.tv_sec*1000000000 + tp.tv_nsec;
#elif defined __MACH__ && defined __APPLE__
return (int64)mach_absolute_time();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -831,8 +849,6 @@ double getTickFrequency(void)
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return (double)freq.QuadPart;
#elif defined __linux || defined __linux__
return 1e9;
#elif defined __MACH__ && defined __APPLE__
static double freq = 0;
if( freq == 0 )
@@ -842,6 +858,8 @@ double getTickFrequency(void)
freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer;
}
return freq;
#elif defined __unix__
return 1e9;
#else
return 1e6;
#endif
@@ -1314,6 +1332,8 @@ bool __termination = false;
namespace details {
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
@@ -1323,64 +1343,62 @@ namespace details {
#endif
#endif
template <class T>
class DisposedSingletonMark
{
private:
static bool mark;
protected:
DisposedSingletonMark() {}
~DisposedSingletonMark()
{
mark = true;
}
public:
static bool isDisposed() { return mark; }
};
// TLS platform abstraction layer
class TlsAbstraction : public DisposedSingletonMark<TlsAbstraction>
class TlsAbstraction
{
public:
TlsAbstraction();
~TlsAbstraction();
void* getData() const
~TlsAbstraction()
{
if (isDisposed()) // guard: static initialization order fiasco
return NULL;
return getData_();
}
void setData(void *pData)
{
if (isDisposed()) // guard: static initialization order fiasco
return;
return setData_(pData);
// TlsAbstraction singleton should not be released
// There is no reliable way to avoid problems caused by static initialization order fiasco
// NB: Do NOT use logging here
fprintf(stderr, "OpenCV FATAL: TlsAbstraction::~TlsAbstraction() call is not expected\n");
fflush(stderr);
}
void* getData() const;
void setData(void *pData);
void releaseSystemResources();
private:
void* getData_() const;
void setData_(void *pData);
#ifdef _WIN32
#ifndef WINRT
DWORD tlsKey;
bool disposed;
#endif
#else // _WIN32
pthread_key_t tlsKey;
#if OPENCV_WITH_THREAD_SANITIZER
std::atomic<bool> disposed;
#else
bool disposed;
#endif
#endif
};
template<> bool DisposedSingletonMark<TlsAbstraction>::mark = false;
static TlsAbstraction& getTlsAbstraction_()
class TlsAbstractionReleaseGuard
{
static TlsAbstraction g_tls; // disposed in atexit() handlers (required for unregistering our callbacks)
return g_tls;
}
TlsAbstraction& tls_;
public:
TlsAbstractionReleaseGuard(TlsAbstraction& tls) : tls_(tls)
{
/* nothing */
}
~TlsAbstractionReleaseGuard()
{
tls_.releaseSystemResources();
}
};
// TODO use reference
static TlsAbstraction* getTlsAbstraction()
{
static TlsAbstraction* instance = &getTlsAbstraction_();
return DisposedSingletonMark<TlsAbstraction>::isDisposed() ? NULL : instance;
static TlsAbstraction *g_tls = new TlsAbstraction(); // memory leak is intended here to avoid disposing of TLS container
static TlsAbstractionReleaseGuard g_tlsReleaseGuard(*g_tls);
return g_tls;
}
@@ -1388,15 +1406,15 @@ static TlsAbstraction* getTlsAbstraction()
#ifdef WINRT
static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data
TlsAbstraction::TlsAbstraction() {}
TlsAbstraction::~TlsAbstraction()
void TlsAbstraction::releaseSystemResources()
{
cv::__termination = true; // DllMain is missing in static builds
}
void* TlsAbstraction::getData_() const
void* TlsAbstraction::getData() const
{
return tlsData;
}
void TlsAbstraction::setData_(void *pData)
void TlsAbstraction::setData(void *pData)
{
tlsData = pData;
}
@@ -1405,6 +1423,7 @@ void TlsAbstraction::setData_(void *pData)
static void NTAPI opencv_fls_destructor(void* pData);
#endif // CV_USE_FLS
TlsAbstraction::TlsAbstraction()
: disposed(false)
{
#ifndef CV_USE_FLS
tlsKey = TlsAlloc();
@@ -1413,9 +1432,10 @@ TlsAbstraction::TlsAbstraction()
#endif // CV_USE_FLS
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
}
TlsAbstraction::~TlsAbstraction()
void TlsAbstraction::releaseSystemResources()
{
cv::__termination = true; // DllMain is missing in static builds
disposed = true;
#ifndef CV_USE_FLS
TlsFree(tlsKey);
#else // CV_USE_FLS
@@ -1423,16 +1443,20 @@ TlsAbstraction::~TlsAbstraction()
#endif // CV_USE_FLS
tlsKey = TLS_OUT_OF_INDEXES;
}
void* TlsAbstraction::getData_() const
void* TlsAbstraction::getData() const
{
if (disposed)
return NULL;
#ifndef CV_USE_FLS
return TlsGetValue(tlsKey);
#else // CV_USE_FLS
return FlsGetValue(tlsKey);
#endif // CV_USE_FLS
}
void TlsAbstraction::setData_(void *pData)
void TlsAbstraction::setData(void *pData)
{
if (disposed)
return; // no-op
#ifndef CV_USE_FLS
CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
#else // CV_USE_FLS
@@ -1443,12 +1467,14 @@ void TlsAbstraction::setData_(void *pData)
#else // _WIN32
static void opencv_tls_destructor(void* pData);
TlsAbstraction::TlsAbstraction()
: disposed(false)
{
CV_Assert(pthread_key_create(&tlsKey, opencv_tls_destructor) == 0);
}
TlsAbstraction::~TlsAbstraction()
void TlsAbstraction::releaseSystemResources()
{
cv::__termination = true; // DllMain is missing in static builds
disposed = true;
if (pthread_key_delete(tlsKey) != 0)
{
// Don't use logging here
@@ -1456,12 +1482,16 @@ TlsAbstraction::~TlsAbstraction()
fflush(stderr);
}
}
void* TlsAbstraction::getData_() const
void* TlsAbstraction::getData() const
{
if (disposed)
return NULL;
return pthread_getspecific(tlsKey);
}
void TlsAbstraction::setData_(void *pData)
void TlsAbstraction::setData(void *pData)
{
if (disposed)
return; // no-op
CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
}
#endif
@@ -1489,6 +1519,7 @@ public:
TlsStorage() :
tlsSlotsSize(0)
{
(void)getTlsAbstraction(); // ensure singeton initialization (for correct order of atexit calls)
tlsSlots.reserve(32);
threads.reserve(32);
g_isTlsStorageInitialized = true;
@@ -1726,14 +1757,129 @@ static void WINAPI opencv_fls_destructor(void* pData)
#endif // CV_USE_FLS
#endif // _WIN32
static TlsStorage* const g_force_initialization_of_TlsStorage
#if defined __GNUC__
__attribute__((unused))
#endif
= &getTlsStorage();
#else // OPENCV_DISABLE_THREAD_SUPPORT
// no threading (OPENCV_DISABLE_THREAD_SUPPORT=ON)
class TlsStorage
{
public:
TlsStorage()
{
slots.reserve(32);
}
~TlsStorage()
{
for (size_t slotIdx = 0; slotIdx < slots.size(); slotIdx++)
{
SlotInfo& s = slots[slotIdx];
TLSDataContainer* container = s.container;
if (container && s.data)
{
container->deleteDataInstance(s.data); // Can't use from SlotInfo destructor
s.data = nullptr;
}
}
}
// Reserve TLS storage index
size_t reserveSlot(TLSDataContainer* container)
{
size_t slotsSize = slots.size();
for (size_t slot = 0; slot < slotsSize; slot++)
{
SlotInfo& s = slots[slot];
if (s.container == NULL)
{
CV_Assert(!s.data);
s.container = container;
return slot;
}
}
// create new slot
slots.push_back(SlotInfo(container));
return slotsSize;
}
// Release TLS storage index and pass associated data to caller
void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec, bool keepSlot = false)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
{
dataVec.push_back(data);
s.data = nullptr;
}
if (!keepSlot)
{
s.container = NULL; // mark slot as free (see reserveSlot() implementation)
}
}
// Get data by TLS storage index
void* getData(size_t slotIdx) const
{
CV_Assert(slotIdx < slots.size());
const SlotInfo& s = slots[slotIdx];
return s.data;
}
// Gather data from threads by TLS storage index
void gather(size_t slotIdx, std::vector<void*> &dataVec)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
dataVec.push_back(data);
return;
}
// Set data to storage index
void setData(size_t slotIdx, void* pData)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
s.data = pData;
}
private:
struct SlotInfo
{
SlotInfo(TLSDataContainer* _container) : container(_container), data(nullptr) {}
TLSDataContainer* container; // attached container (to dispose data)
void* data;
};
std::vector<struct SlotInfo> slots;
};
static TlsStorage& getTlsStorage()
{
static TlsStorage g_storage; // no threading
return g_storage;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
} // namespace details
using namespace details;
void releaseTlsStorageThread()
{
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
if (!g_isTlsStorageInitialized)
return; // nothing to release, so prefer to avoid creation of new global structures
getTlsStorage().releaseThread();
#endif
}
TLSDataContainer::TLSDataContainer()
@@ -1783,7 +1929,15 @@ void* TLSDataContainer::getData() const
{
// Create new data instance and save it to TLS storage
pData = createDataInstance();
getTlsStorage().setData(key_, pData);
try
{
getTlsStorage().setData(key_, pData);
}
catch (...)
{
deleteDataInstance(pData);
throw;
}
}
return pData;
}
+89 -42
View File
@@ -56,10 +56,6 @@ void setSize(UMat& m, int _dims, const int* _sz, const size_t* _steps,
void updateContinuityFlag(UMat& m);
void finalizeHdr(UMat& m);
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
UMatData::UMatData(const MatAllocator* allocator)
{
prevAllocator = currAllocator = allocator;
@@ -131,6 +127,12 @@ UMatData::~UMatData()
}
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
static size_t getUMatDataLockIndex(const UMatData* u)
{
size_t idx = ((size_t)(void*)u) % UMAT_NLOCKS;
@@ -228,6 +230,33 @@ UMatDataAutoLock::~UMatDataAutoLock()
getUMatDataAutoLocker().release(u1, u2);
}
#else
void UMatData::lock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
void UMatData::unlock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u) : u1(u), u2(NULL)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u1_, UMatData* u2_) : u1(u1_), u2(u2_)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::~UMatDataAutoLock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
//////////////////////////////// UMat ////////////////////////////////
UMat::UMat(UMatUsageFlags _usageFlags) CV_NOEXCEPT
@@ -597,14 +626,28 @@ UMat Mat::getUMat(AccessFlag accessFlags, UMatUsageFlags usageFlags) const
CV_XADD(&(u->refcount), 1);
CV_XADD(&(u->urefcount), 1);
}
hdr.flags = flags;
hdr.usageFlags = usageFlags;
setSize(hdr, dims, size.p, step.p);
finalizeHdr(hdr);
hdr.u = new_u;
hdr.offset = 0; //data - datastart;
hdr.addref();
return hdr;
try
{
hdr.flags = flags;
hdr.usageFlags = usageFlags;
setSize(hdr, dims, size.p, step.p);
finalizeHdr(hdr);
hdr.u = new_u;
hdr.offset = 0; //data - datastart;
hdr.addref();
return hdr;
}
catch(...)
{
if (u != NULL)
{
CV_XADD(&(u->refcount), -1);
CV_XADD(&(u->urefcount), -1);
}
new_u->currAllocator->deallocate(new_u);
throw;
}
}
void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlags)
@@ -756,18 +799,17 @@ UMat::UMat(const UMat& m, const Rect& roi)
offset += roi.x*esz;
CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
if( u )
CV_XADD(&(u->urefcount), 1);
if( roi.width < m.cols || roi.height < m.rows )
flags |= SUBMATRIX_FLAG;
step[0] = m.step[0]; step[1] = esz;
updateContinuityFlag();
addref();
if( rows <= 0 || cols <= 0 )
{
release();
rows = cols = 0;
release();
}
}
@@ -951,11 +993,11 @@ UMat UMat::reshape(int new_cn, int new_rows) const
return hdr;
}
UMat UMat::diag(const UMat& d)
UMat UMat::diag(const UMat& d, UMatUsageFlags usageFlags)
{
CV_Assert( d.cols == 1 || d.rows == 1 );
int len = d.rows + d.cols - 1;
UMat m(len, len, d.type(), Scalar(0));
UMat m(len, len, d.type(), Scalar(0), usageFlags);
UMat md = m.diag();
if( d.cols == 1 )
d.copyTo(md);
@@ -1033,24 +1075,29 @@ Mat UMat::getMat(AccessFlag accessFlags) const
// TODO Support ACCESS_READ (ACCESS_WRITE) without unnecessary data transfers
accessFlags |= ACCESS_RW;
UMatDataAutoLock autolock(u);
if(CV_XADD(&u->refcount, 1) == 0)
u->currAllocator->map(u, accessFlags);
if (u->data != 0)
try
{
Mat hdr(dims, size.p, type(), u->data + offset, step.p);
hdr.flags = flags;
hdr.u = u;
hdr.datastart = u->data;
hdr.data = u->data + offset;
hdr.datalimit = hdr.dataend = u->data + u->size;
return hdr;
if(CV_XADD(&u->refcount, 1) == 0)
u->currAllocator->map(u, accessFlags);
if (u->data != 0)
{
Mat hdr(dims, size.p, type(), u->data + offset, step.p);
hdr.flags = flags;
hdr.u = u;
hdr.datastart = u->data;
hdr.data = u->data + offset;
hdr.datalimit = hdr.dataend = u->data + u->size;
return hdr;
}
}
else
catch(...)
{
CV_XADD(&u->refcount, -1);
CV_Assert(u->data != 0 && "Error mapping of UMat to host memory.");
return Mat();
throw;
}
CV_XADD(&u->refcount, -1);
CV_Assert(u->data != 0 && "Error mapping of UMat to host memory.");
return Mat();
}
void* UMat::handle(AccessFlag accessFlags) const
@@ -1323,34 +1370,34 @@ UMat UMat::t() const
return m;
}
UMat UMat::zeros(int rows, int cols, int type)
UMat UMat::zeros(int rows, int cols, int type, UMatUsageFlags usageFlags)
{
return UMat(rows, cols, type, Scalar::all(0));
return UMat(rows, cols, type, Scalar::all(0), usageFlags);
}
UMat UMat::zeros(Size size, int type)
UMat UMat::zeros(Size size, int type, UMatUsageFlags usageFlags)
{
return UMat(size, type, Scalar::all(0));
return UMat(size, type, Scalar::all(0), usageFlags);
}
UMat UMat::zeros(int ndims, const int* sz, int type)
UMat UMat::zeros(int ndims, const int* sz, int type, UMatUsageFlags usageFlags)
{
return UMat(ndims, sz, type, Scalar::all(0));
return UMat(ndims, sz, type, Scalar::all(0), usageFlags);
}
UMat UMat::ones(int rows, int cols, int type)
UMat UMat::ones(int rows, int cols, int type, UMatUsageFlags usageFlags)
{
return UMat::ones(Size(cols, rows), type);
return UMat(rows, cols, type, Scalar(1), usageFlags);
}
UMat UMat::ones(Size size, int type)
UMat UMat::ones(Size size, int type, UMatUsageFlags usageFlags)
{
return UMat(size, type, Scalar(1));
return UMat(size, type, Scalar(1), usageFlags);
}
UMat UMat::ones(int ndims, const int* sz, int type)
UMat UMat::ones(int ndims, const int* sz, int type, UMatUsageFlags usageFlags)
{
return UMat(ndims, sz, type, Scalar(1));
return UMat(ndims, sz, type, Scalar(1), usageFlags);
}
}
+2 -2
View File
@@ -37,8 +37,8 @@ private:
// also, extensible functions (accepting user-provided callback) are not allowed
// to call LogTagManger (to prevent iterator invalidation), which needs enforced
// with a non-recursive mutex.
using MutexType = std::mutex;
using LockType = std::lock_guard<MutexType>;
using MutexType = cv::Mutex;
using LockType = cv::AutoLock;
enum class MatchingScope
{