Merge pull request #1976 from alalek:ocl_multiple_command_queues
This commit is contained in:
commit
658282fcbe
@ -4821,6 +4821,32 @@ private:
|
|||||||
AutoLock& operator = (const AutoLock&);
|
AutoLock& operator = (const AutoLock&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TLSDataContainer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int key_;
|
||||||
|
protected:
|
||||||
|
CV_EXPORTS TLSDataContainer();
|
||||||
|
CV_EXPORTS ~TLSDataContainer(); // virtual is not required
|
||||||
|
public:
|
||||||
|
virtual void* createDataInstance() const = 0;
|
||||||
|
virtual void deleteDataInstance(void* data) const = 0;
|
||||||
|
|
||||||
|
CV_EXPORTS void* getData() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TLSData : protected TLSDataContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline TLSData() {}
|
||||||
|
inline ~TLSData() {}
|
||||||
|
inline T* get() const { return (T*)getData(); }
|
||||||
|
private:
|
||||||
|
virtual void* createDataInstance() const { return new T; }
|
||||||
|
virtual void deleteDataInstance(void* data) const { delete (T*)data; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
@ -806,24 +806,6 @@ cvGetModuleInfo( const char* name, const char **version, const char **plugin_lis
|
|||||||
*plugin_list = plugin_list_buf;
|
*plugin_list = plugin_list_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
|
|
||||||
#ifdef HAVE_WINRT
|
|
||||||
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID );
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID )
|
|
||||||
{
|
|
||||||
if( fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH )
|
|
||||||
{
|
|
||||||
cv::deleteThreadAllocData();
|
|
||||||
cv::deleteThreadRNGData();
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -941,6 +923,223 @@ void Mutex::lock() { impl->lock(); }
|
|||||||
void Mutex::unlock() { impl->unlock(); }
|
void Mutex::unlock() { impl->unlock(); }
|
||||||
bool Mutex::trylock() { return impl->trylock(); }
|
bool Mutex::trylock() { return impl->trylock(); }
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////// thread-local storage ////////////////////////////////
|
||||||
|
|
||||||
|
class TLSStorage
|
||||||
|
{
|
||||||
|
std::vector<void*> tlsData_;
|
||||||
|
public:
|
||||||
|
TLSStorage() { tlsData_.reserve(16); }
|
||||||
|
~TLSStorage();
|
||||||
|
inline void* getData(int key) const
|
||||||
|
{
|
||||||
|
CV_DbgAssert(key >= 0);
|
||||||
|
return (key < (int)tlsData_.size()) ? tlsData_[key] : NULL;
|
||||||
|
}
|
||||||
|
inline void setData(int key, void* data)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(key >= 0);
|
||||||
|
if (key >= (int)tlsData_.size())
|
||||||
|
{
|
||||||
|
tlsData_.resize(key + 1, NULL);
|
||||||
|
}
|
||||||
|
tlsData_[key] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static TLSStorage* get();
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#pragma warning(disable:4505) // unreferenced local function has been removed
|
||||||
|
|
||||||
|
#ifdef HAVE_WINRT
|
||||||
|
// using C++11 thread attribute for local thread data
|
||||||
|
static __declspec( thread ) TLSStorage* g_tlsdata = NULL;
|
||||||
|
|
||||||
|
static void deleteThreadData()
|
||||||
|
{
|
||||||
|
if (g_tlsdata)
|
||||||
|
{
|
||||||
|
delete g_tlsdata;
|
||||||
|
g_tlsdata = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
if (!g_tlsdata)
|
||||||
|
{
|
||||||
|
g_tlsdata = new TLSStorage;
|
||||||
|
}
|
||||||
|
return g_tlsdata;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef WINCE
|
||||||
|
# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
|
||||||
|
#endif
|
||||||
|
static DWORD tlsKey = TLS_OUT_OF_INDEXES;
|
||||||
|
|
||||||
|
static void deleteThreadData()
|
||||||
|
{
|
||||||
|
if(tlsKey != TLS_OUT_OF_INDEXES)
|
||||||
|
{
|
||||||
|
delete (TLSStorage*)TlsGetValue(tlsKey);
|
||||||
|
TlsSetValue(tlsKey, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
if (tlsKey == TLS_OUT_OF_INDEXES)
|
||||||
|
{
|
||||||
|
tlsKey = TlsAlloc();
|
||||||
|
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
|
||||||
|
}
|
||||||
|
TLSStorage* d = (TLSStorage*)TlsGetValue(tlsKey);
|
||||||
|
if (!d)
|
||||||
|
{
|
||||||
|
d = new TLSStorage;
|
||||||
|
TlsSetValue(tlsKey, d);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif //HAVE_WINRT
|
||||||
|
|
||||||
|
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
|
||||||
|
#ifdef HAVE_WINRT
|
||||||
|
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID);
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID)
|
||||||
|
{
|
||||||
|
if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
|
cv::deleteThreadAllocData();
|
||||||
|
cv::deleteThreadRNGData();
|
||||||
|
cv::deleteThreadData();
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
static pthread_key_t tlsKey = 0;
|
||||||
|
static pthread_once_t tlsKeyOnce = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
static void deleteTLSStorage(void* data)
|
||||||
|
{
|
||||||
|
delete (TLSStorage*)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeKey()
|
||||||
|
{
|
||||||
|
int errcode = pthread_key_create(&tlsKey, deleteTLSStorage);
|
||||||
|
CV_Assert(errcode == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
pthread_once(&tlsKeyOnce, makeKey);
|
||||||
|
TLSStorage* d = (TLSStorage*)pthread_getspecific(tlsKey);
|
||||||
|
if( !d )
|
||||||
|
{
|
||||||
|
d = new TLSStorage;
|
||||||
|
pthread_setspecific(tlsKey, d);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TLSContainerStorage
|
||||||
|
{
|
||||||
|
cv::Mutex mutex_;
|
||||||
|
std::vector<TLSDataContainer*> tlsContainers_;
|
||||||
|
public:
|
||||||
|
TLSContainerStorage() { }
|
||||||
|
~TLSContainerStorage()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < tlsContainers_.size(); i++)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(tlsContainers_[i] == NULL); // not all keys released
|
||||||
|
tlsContainers_[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int allocateKey(TLSDataContainer* pContainer)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
tlsContainers_.push_back(pContainer);
|
||||||
|
return (int)tlsContainers_.size() - 1;
|
||||||
|
}
|
||||||
|
void releaseKey(int id, TLSDataContainer* pContainer)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
CV_Assert(tlsContainers_[id] == pContainer);
|
||||||
|
tlsContainers_[id] = NULL;
|
||||||
|
// currently, we don't go into thread's TLSData and release data for this key
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyData(int key, void* data)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
TLSDataContainer* k = tlsContainers_[key];
|
||||||
|
if (!k)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
k->deleteDataInstance(data);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(k == NULL); // Debug this!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static TLSContainerStorage tlsContainerStorage;
|
||||||
|
|
||||||
|
TLSDataContainer::TLSDataContainer()
|
||||||
|
: key_(-1)
|
||||||
|
{
|
||||||
|
key_ = tlsContainerStorage.allocateKey(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TLSDataContainer::~TLSDataContainer()
|
||||||
|
{
|
||||||
|
tlsContainerStorage.releaseKey(key_, this);
|
||||||
|
key_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TLSDataContainer::getData() const
|
||||||
|
{
|
||||||
|
CV_Assert(key_ >= 0);
|
||||||
|
TLSStorage* tlsData = TLSStorage::get();
|
||||||
|
void* data = tlsData->getData(key_);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
data = this->createDataInstance();
|
||||||
|
CV_DbgAssert(data != NULL);
|
||||||
|
tlsData->setData(key_, data);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLSStorage::~TLSStorage()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)tlsData_.size(); i++)
|
||||||
|
{
|
||||||
|
void*& data = tlsData_[i];
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
tlsContainerStorage.destroyData(i, data);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlsData_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cv
|
||||||
|
|
||||||
/* End of file. */
|
/* End of file. */
|
||||||
|
@ -57,6 +57,10 @@
|
|||||||
namespace cv {
|
namespace cv {
|
||||||
namespace ocl {
|
namespace ocl {
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
static bool __termination = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct __Module
|
struct __Module
|
||||||
{
|
{
|
||||||
__Module();
|
__Module();
|
||||||
@ -494,6 +498,38 @@ PlatformInfo::PlatformInfo()
|
|||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ContextImpl;
|
||||||
|
|
||||||
|
struct CommandQueue
|
||||||
|
{
|
||||||
|
ContextImpl* context_;
|
||||||
|
cl_command_queue clQueue_;
|
||||||
|
|
||||||
|
CommandQueue() : context_(NULL), clQueue_(NULL) { }
|
||||||
|
~CommandQueue() { release(); }
|
||||||
|
|
||||||
|
void create(ContextImpl* context_);
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
// if process is on termination stage (ExitProcess was called and other threads were terminated)
|
||||||
|
// then disable command queue release because it may cause program hang
|
||||||
|
if (!__termination)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(clQueue_)
|
||||||
|
{
|
||||||
|
openCLSafeCall(clReleaseCommandQueue(clQueue_)); // some cleanup problems are here
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
clQueue_ = NULL;
|
||||||
|
context_ = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cv::TLSData<CommandQueue> commandQueueTLSData;
|
||||||
|
|
||||||
//////////////////////////////// OpenCL context ////////////////////////
|
//////////////////////////////// OpenCL context ////////////////////////
|
||||||
//This is a global singleton class used to represent a OpenCL context.
|
//This is a global singleton class used to represent a OpenCL context.
|
||||||
class ContextImpl : public Context
|
class ContextImpl : public Context
|
||||||
@ -501,12 +537,11 @@ class ContextImpl : public Context
|
|||||||
public:
|
public:
|
||||||
const cl_device_id clDeviceID;
|
const cl_device_id clDeviceID;
|
||||||
cl_context clContext;
|
cl_context clContext;
|
||||||
cl_command_queue clCmdQueue;
|
|
||||||
const DeviceInfo& deviceInfo;
|
const DeviceInfo& deviceInfo;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ContextImpl(const DeviceInfo& deviceInfo, cl_device_id clDeviceID)
|
ContextImpl(const DeviceInfo& deviceInfo, cl_device_id clDeviceID)
|
||||||
: clDeviceID(clDeviceID), clContext(NULL), clCmdQueue(NULL), deviceInfo(deviceInfo)
|
: clDeviceID(clDeviceID), clContext(NULL), deviceInfo(deviceInfo)
|
||||||
{
|
{
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
@ -581,7 +616,13 @@ const void* Context::getOpenCLContextPtr() const
|
|||||||
|
|
||||||
const void* Context::getOpenCLCommandQueuePtr() const
|
const void* Context::getOpenCLCommandQueuePtr() const
|
||||||
{
|
{
|
||||||
return &(((ContextImpl*)this)->clCmdQueue);
|
ContextImpl* pThis = (ContextImpl*)this;
|
||||||
|
CommandQueue* commandQueue = commandQueueTLSData.get();
|
||||||
|
if (commandQueue->context_ != pThis)
|
||||||
|
{
|
||||||
|
commandQueue->create(pThis);
|
||||||
|
}
|
||||||
|
return &commandQueue->clQueue_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* Context::getOpenCLDeviceIDPtr() const
|
const void* Context::getOpenCLDeviceIDPtr() const
|
||||||
@ -607,10 +648,6 @@ bool ContextImpl::supportsFeature(FEATURE_TYPE featureType) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
static bool __termination = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ContextImpl::~ContextImpl()
|
ContextImpl::~ContextImpl()
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -619,17 +656,11 @@ ContextImpl::~ContextImpl()
|
|||||||
if (!__termination)
|
if (!__termination)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if(clCmdQueue)
|
|
||||||
{
|
|
||||||
openCLSafeCall(clReleaseCommandQueue(clCmdQueue)); // some cleanup problems are here
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clContext)
|
if(clContext)
|
||||||
{
|
{
|
||||||
openCLSafeCall(clReleaseContext(clContext));
|
openCLSafeCall(clReleaseContext(clContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clCmdQueue = NULL;
|
|
||||||
clContext = NULL;
|
clContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,12 +698,8 @@ void ContextImpl::setContext(const DeviceInfo* deviceInfo)
|
|||||||
cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(infoImpl.platform_id), 0 };
|
cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(infoImpl.platform_id), 0 };
|
||||||
cl_context clContext = clCreateContext(cps, 1, &infoImpl.device_id, NULL, NULL, &status);
|
cl_context clContext = clCreateContext(cps, 1, &infoImpl.device_id, NULL, NULL, &status);
|
||||||
openCLVerifyCall(status);
|
openCLVerifyCall(status);
|
||||||
// TODO add CL_QUEUE_PROFILING_ENABLE
|
|
||||||
cl_command_queue clCmdQueue = clCreateCommandQueue(clContext, infoImpl.device_id, 0, &status);
|
|
||||||
openCLVerifyCall(status);
|
|
||||||
|
|
||||||
ContextImpl* ctx = new ContextImpl(infoImpl.info, infoImpl.device_id);
|
ContextImpl* ctx = new ContextImpl(infoImpl.info, infoImpl.device_id);
|
||||||
ctx->clCmdQueue = clCmdQueue;
|
|
||||||
ctx->clContext = clContext;
|
ctx->clContext = clContext;
|
||||||
|
|
||||||
ContextImpl* old = NULL;
|
ContextImpl* old = NULL;
|
||||||
@ -687,6 +714,17 @@ void ContextImpl::setContext(const DeviceInfo* deviceInfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandQueue::create(ContextImpl* context)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
cl_int status = 0;
|
||||||
|
// TODO add CL_QUEUE_PROFILING_ENABLE
|
||||||
|
cl_command_queue clCmdQueue = clCreateCommandQueue(context->clContext, context->clDeviceID, 0, &status);
|
||||||
|
openCLVerifyCall(status);
|
||||||
|
context_ = context;
|
||||||
|
clQueue_ = clCmdQueue;
|
||||||
|
}
|
||||||
|
|
||||||
int getOpenCLPlatforms(PlatformsInfo& platforms)
|
int getOpenCLPlatforms(PlatformsInfo& platforms)
|
||||||
{
|
{
|
||||||
if (!__initialized)
|
if (!__initialized)
|
||||||
|
Loading…
Reference in New Issue
Block a user