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:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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];
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+1360
-1316
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user