Commit a82d2363 authored by Alexander Alekhin's avatar Alexander Alekhin Committed by Alexander Alekhin

ocl: refactor Program API

- don't store ProgramSource in compiled Programs (resolved problem with "source" buffers lifetime)
- completelly remove Program::read/write methods implementation:
  - replaced with method to query RAW OpenCL binary without any "custom" data
- deprecate Program::getPrefix() methods
parent 13c4a021
...@@ -606,19 +606,14 @@ public: ...@@ -606,19 +606,14 @@ public:
bool create(const ProgramSource& src, bool create(const ProgramSource& src,
const String& buildflags, String& errmsg); const String& buildflags, String& errmsg);
bool read(const String& buf, const String& buildflags); // deprecated
bool write(String& buf) const; // deprecated
const ProgramSource& source() const; // deprecated
void* ptr() const; void* ptr() const;
String getPrefix() const; // deprecated
static String getPrefix(const String& buildflags); // deprecated
/** /**
* @brief Query device-specific program binary. * @brief Query device-specific program binary.
* *
* Returns RAW OpenCL executable binary without additional attachments.
*
* @sa ProgramSource::fromBinary * @sa ProgramSource::fromBinary
* *
* @param[out] binary output buffer * @param[out] binary output buffer
...@@ -629,6 +624,15 @@ public: ...@@ -629,6 +624,15 @@ public:
inline Impl* getImpl() const { return (Impl*)p; } inline Impl* getImpl() const { return (Impl*)p; }
protected: protected:
Impl* p; Impl* p;
public:
#ifndef OPENCV_REMOVE_DEPRECATED_API
// TODO Remove this
CV_DEPRECATED bool read(const String& buf, const String& buildflags); // removed, use ProgramSource instead
CV_DEPRECATED bool write(String& buf) const; // removed, use getBinary() method instead (RAW OpenCL binary)
CV_DEPRECATED const ProgramSource& source() const; // implementation removed
CV_DEPRECATED String getPrefix() const; // deprecated, implementation replaced
CV_DEPRECATED static String getPrefix(const String& buildflags); // deprecated, implementation replaced
#endif
}; };
......
...@@ -2252,6 +2252,8 @@ struct Context::Impl ...@@ -2252,6 +2252,8 @@ struct Context::Impl
return; return;
} }
#endif #endif
friend class Program;
}; };
...@@ -3463,19 +3465,20 @@ struct Program::Impl ...@@ -3463,19 +3465,20 @@ struct Program::Impl
{ {
IMPLEMENT_REFCOUNTABLE(); IMPLEMENT_REFCOUNTABLE();
Impl(const ProgramSource& _src, Impl(const ProgramSource& src,
const String& _buildflags, String& errmsg) : const String& _buildflags, String& errmsg) :
src(_src), refcount(1),
buildflags(_buildflags), handle(NULL),
handle(NULL) buildflags(_buildflags)
{ {
refcount = 1; const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_);
sourceModule_ = src_->module_;
sourceName_ = src_->name_;
const Context ctx = Context::getDefault(); const Context ctx = Context::getDefault();
Device device = ctx.device(0); Device device = ctx.device(0);
if (ctx.ptr() == NULL || device.ptr() == NULL) if (ctx.ptr() == NULL || device.ptr() == NULL)
return; return;
const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_);
buildflags = joinBuildOptions(buildflags, src_->buildOptions_); buildflags = joinBuildOptions(buildflags, src_->buildOptions_);
if (src.getImpl()->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE) if (src.getImpl()->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE)
{ {
...@@ -3484,13 +3487,12 @@ struct Program::Impl ...@@ -3484,13 +3487,12 @@ struct Program::Impl
else if (device.isIntel()) else if (device.isIntel())
buildflags = joinBuildOptions(buildflags, " -D INTEL_DEVICE"); buildflags = joinBuildOptions(buildflags, " -D INTEL_DEVICE");
} }
compile(ctx, errmsg); compile(ctx, src_, errmsg);
} }
bool compile(const Context& ctx, String& errmsg) bool compile(const Context& ctx, const ProgramSource::Impl* src_, String& errmsg)
{ {
CV_Assert(ctx.getImpl()); CV_Assert(ctx.getImpl());
const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_); CV_Assert(src_);
// We don't cache OpenCL binaries // We don't cache OpenCL binaries
...@@ -3499,13 +3501,12 @@ struct Program::Impl ...@@ -3499,13 +3501,12 @@ struct Program::Impl
bool isLoaded = createFromBinary(ctx, src_->sourceAddr_, src_->sourceSize_, errmsg); bool isLoaded = createFromBinary(ctx, src_->sourceAddr_, src_->sourceSize_, errmsg);
return isLoaded; return isLoaded;
} }
return compileWithCache(ctx, errmsg); return compileWithCache(ctx, src_, errmsg);
} }
bool compileWithCache(const Context& ctx, String& errmsg) bool compileWithCache(const Context& ctx, const ProgramSource::Impl* src_, String& errmsg)
{ {
CV_Assert(ctx.getImpl()); CV_Assert(ctx.getImpl());
const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_); CV_Assert(src_);
CV_Assert(src_->kind_ != ProgramSource::Impl::PROGRAM_BINARIES); CV_Assert(src_->kind_ != ProgramSource::Impl::PROGRAM_BINARIES);
...@@ -3557,7 +3558,7 @@ struct Program::Impl ...@@ -3557,7 +3558,7 @@ struct Program::Impl
CV_Assert(handle == NULL); CV_Assert(handle == NULL);
if (src_->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE) if (src_->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE)
{ {
if (!buildFromSources(ctx, errmsg)) if (!buildFromSources(ctx, src_, errmsg))
{ {
return false; return false;
} }
...@@ -3648,23 +3649,22 @@ struct Program::Impl ...@@ -3648,23 +3649,22 @@ struct Program::Impl
errmsg = String(buffer); errmsg = String(buffer);
printf("OpenCL program build log: %s/%s\nStatus %d: %s\n%s\n%s\n", printf("OpenCL program build log: %s/%s\nStatus %d: %s\n%s\n%s\n",
src.getImpl()->module_.c_str(), src.getImpl()->name_.c_str(), sourceModule_.c_str(), sourceName_.c_str(),
result, getOpenCLErrorString(result), result, getOpenCLErrorString(result),
buildflags.c_str(), errmsg.c_str()); buildflags.c_str(), errmsg.c_str());
fflush(stdout); fflush(stdout);
} }
bool buildFromSources(const Context& ctx, String& errmsg) bool buildFromSources(const Context& ctx, const ProgramSource::Impl* src_, String& errmsg)
{ {
const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_); CV_Assert(src_);
CV_Assert(src_->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE); CV_Assert(src_->kind_ == ProgramSource::Impl::PROGRAM_SOURCE_CODE);
CV_Assert(handle == NULL); CV_Assert(handle == NULL);
CV_INSTRUMENT_REGION_OPENCL_COMPILE(cv::format("Build OpenCL program: %s/%s %" PRIx64 " options: %s", CV_INSTRUMENT_REGION_OPENCL_COMPILE(cv::format("Build OpenCL program: %s/%s %" PRIx64 " options: %s",
src_->module_.c_str(), src_->name_.c_str(), sourceModule_.c_str(), sourceName_.c_str(),
src.hash(), buildflags.c_str()).c_str()); src.hash(), buildflags.c_str()).c_str());
CV_LOG_VERBOSE(NULL, 0, "Compile... " << src_->module_.c_str() << "/" << src_->name_.c_str()); CV_LOG_VERBOSE(NULL, 0, "Compile... " << sourceModule_.c_str() << "/" << sourceName_.c_str());
const char* srcptr = src_->sourceAddr_ ? ((const char*)src_->sourceAddr_) : src_->codeStr_.c_str(); const char* srcptr = src_->sourceAddr_ ? ((const char*)src_->sourceAddr_) : src_->codeStr_.c_str();
size_t srclen = src_->sourceAddr_ ? src_->sourceSize_ : src_->codeStr_.size(); size_t srclen = src_->sourceAddr_ ? src_->sourceSize_ : src_->codeStr_.size();
...@@ -3721,58 +3721,6 @@ struct Program::Impl ...@@ -3721,58 +3721,6 @@ struct Program::Impl
return handle != NULL; return handle != NULL;
} }
Impl(const String& _buf, const String& _buildflags)
{
refcount = 1;
handle = 0;
buildflags = _buildflags;
if(_buf.empty())
return;
String prefix0 = Program::getPrefix(buildflags);
const Context& ctx = Context::getDefault();
const Device& dev = Device::getDefault();
const char* pos0 = _buf.c_str();
const char* pos1 = strchr(pos0, '\n');
if(!pos1)
return;
const char* pos2 = strchr(pos1+1, '\n');
if(!pos2)
return;
const char* pos3 = strchr(pos2+1, '\n');
if(!pos3)
return;
size_t prefixlen = (pos3 - pos0)+1;
String prefix(pos0, prefixlen);
if( prefix != prefix0 )
return;
const uchar* bin = (uchar*)(pos3+1);
void* devid = dev.ptr();
size_t codelen = _buf.length() - prefixlen;
cl_int binstatus = 0, retval = 0;
handle = clCreateProgramWithBinary((cl_context)ctx.ptr(), 1, (cl_device_id*)&devid,
&codelen, &bin, &binstatus, &retval);
CV_OCL_DBG_CHECK_RESULT(retval, "clCreateProgramWithBinary");
}
String store()
{
if(!handle)
return String();
size_t progsz = 0, retsz = 0;
String prefix = Program::getPrefix(buildflags);
size_t prefixlen = prefix.length();
if(clGetProgramInfo(handle, CL_PROGRAM_BINARY_SIZES, sizeof(progsz), &progsz, &retsz) != CL_SUCCESS)
return String();
AutoBuffer<uchar> bufbuf(prefixlen + progsz + 16);
uchar* buf = bufbuf;
memcpy(buf, prefix.c_str(), prefixlen);
buf += prefixlen;
if(clGetProgramInfo(handle, CL_PROGRAM_BINARIES, sizeof(buf), &buf, &retsz) != CL_SUCCESS)
return String();
buf[progsz] = (uchar)'\0';
return String((const char*)(uchar*)bufbuf, prefixlen + progsz);
}
void getProgramBinary(std::vector<char>& buf) void getProgramBinary(std::vector<char>& buf)
{ {
CV_Assert(handle); CV_Assert(handle);
...@@ -3836,7 +3784,7 @@ struct Program::Impl ...@@ -3836,7 +3784,7 @@ struct Program::Impl
else else
{ {
result = clBuildProgram(handle, (cl_uint)ndevices, (cl_device_id*)devices_, buildflags.c_str(), 0, 0); result = clBuildProgram(handle, (cl_uint)ndevices, (cl_device_id*)devices_, buildflags.c_str(), 0, 0);
CV_OCL_DBG_CHECK_RESULT(result, cv::format("clBuildProgram(binary: %s/%s)", src.getImpl()->module_.c_str(), src.getImpl()->name_.c_str()).c_str()); CV_OCL_DBG_CHECK_RESULT(result, cv::format("clBuildProgram(binary: %s/%s)", sourceModule_.c_str(), sourceName_.c_str()).c_str());
if (result != CL_SUCCESS) if (result != CL_SUCCESS)
{ {
dumpBuildLog_(result, devices, errmsg); dumpBuildLog_(result, devices, errmsg);
...@@ -3905,9 +3853,11 @@ struct Program::Impl ...@@ -3905,9 +3853,11 @@ struct Program::Impl
} }
} }
ProgramSource src;
String buildflags;
cl_program handle; cl_program handle;
String buildflags;
String sourceModule_;
String sourceName_;
}; };
#else // HAVE_OPENCL #else // HAVE_OPENCL
...@@ -3969,47 +3919,31 @@ bool Program::create(const ProgramSource& src, ...@@ -3969,47 +3919,31 @@ bool Program::create(const ProgramSource& src,
#endif #endif
} }
const ProgramSource& Program::source() const void* Program::ptr() const
{ {
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
static ProgramSource dummy; return p ? p->handle : 0;
return p ? p->src : dummy;
#else #else
CV_OPENCL_NO_SUPPORT(); CV_OPENCL_NO_SUPPORT();
#endif #endif
} }
void* Program::ptr() const #ifndef OPENCV_REMOVE_DEPRECATED_API
const ProgramSource& Program::source() const
{ {
#ifdef HAVE_OPENCL CV_ErrorNoReturn(Error::StsNotImplemented, "Removed API");
return p ? p->handle : 0;
#else
CV_OPENCL_NO_SUPPORT();
#endif
} }
bool Program::read(const String& bin, const String& buildflags) bool Program::read(const String& bin, const String& buildflags)
{ {
#ifdef HAVE_OPENCL CV_UNUSED(bin); CV_UNUSED(buildflags);
if(p) CV_ErrorNoReturn(Error::StsNotImplemented, "Removed API");
p->release();
p = new Impl(bin, buildflags);
return p->handle != 0;
#else
CV_OPENCL_NO_SUPPORT();
#endif
} }
bool Program::write(String& bin) const bool Program::write(String& bin) const
{ {
#ifdef HAVE_OPENCL CV_UNUSED(bin);
if(!p) CV_ErrorNoReturn(Error::StsNotImplemented, "Removed API");
return false;
bin = p->store();
return !bin.empty();
#else
CV_OPENCL_NO_SUPPORT();
#endif
} }
String Program::getPrefix() const String Program::getPrefix() const
...@@ -4017,7 +3951,9 @@ String Program::getPrefix() const ...@@ -4017,7 +3951,9 @@ String Program::getPrefix() const
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
if(!p) if(!p)
return String(); return String();
return getPrefix(p->buildflags); Context::Impl* ctx_ = Context::getDefault().getImpl();
CV_Assert(ctx_);
return cv::format("opencl=%s\nbuildflags=%s", ctx_->getPrefixString().c_str(), p->buildflags.c_str());
#else #else
CV_OPENCL_NO_SUPPORT(); CV_OPENCL_NO_SUPPORT();
#endif #endif
...@@ -4026,20 +3962,19 @@ String Program::getPrefix() const ...@@ -4026,20 +3962,19 @@ String Program::getPrefix() const
String Program::getPrefix(const String& buildflags) String Program::getPrefix(const String& buildflags)
{ {
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
const Context& ctx = Context::getDefault(); Context::Impl* ctx_ = Context::getDefault().getImpl();
const Device& dev = ctx.device(0); CV_Assert(ctx_);
return format("name=%s\ndriver=%s\nbuildflags=%s\n", return cv::format("opencl=%s\nbuildflags=%s", ctx_->getPrefixString().c_str(), buildflags.c_str());
dev.name().c_str(), dev.driverVersion().c_str(), buildflags.c_str());
#else #else
CV_UNUSED(buildflags);
CV_OPENCL_NO_SUPPORT(); CV_OPENCL_NO_SUPPORT();
#endif #endif
} }
#endif
void Program::getBinary(std::vector<char>& binary) const void Program::getBinary(std::vector<char>& binary) const
{ {
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
CV_Assert(p); CV_Assert(p && "Empty program");
p->getProgramBinary(binary); p->getProgramBinary(binary);
#else #else
binary.clear(); binary.clear();
...@@ -4054,7 +3989,10 @@ Program Context::Impl::getProg(const ProgramSource& src, ...@@ -4054,7 +3989,10 @@ Program Context::Impl::getProg(const ProgramSource& src,
size_t limit = getProgramCountLimit(); size_t limit = getProgramCountLimit();
const ProgramSource::Impl* src_ = src.getImpl(); const ProgramSource::Impl* src_ = src.getImpl();
CV_Assert(src_); CV_Assert(src_);
String key = cv::format("module=%s name=%s codehash=%s ", src_->module_.c_str(), src_->name_.c_str(), src_->sourceHash_.c_str()) + Program::getPrefix(buildflags); String key = cv::format("module=%s name=%s codehash=%s\nopencl=%s\nbuildflags=%s",
src_->module_.c_str(), src_->name_.c_str(), src_->sourceHash_.c_str(),
getPrefixString().c_str(),
buildflags.c_str());
{ {
cv::AutoLock lock(program_cache_mutex); cv::AutoLock lock(program_cache_mutex);
phash_t::iterator it = phash.find(key); phash_t::iterator it = phash.find(key);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment