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&);
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -806,24 +806,6 @@ cvGetModuleInfo( const char* name, const char **version, const char **plugin_lis
|
||||
*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
|
||||
{
|
||||
|
||||
@ -941,6 +923,223 @@ void Mutex::lock() { impl->lock(); }
|
||||
void Mutex::unlock() { impl->unlock(); }
|
||||
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. */
|
||||
|
@ -57,6 +57,10 @@
|
||||
namespace cv {
|
||||
namespace ocl {
|
||||
|
||||
#if defined(WIN32)
|
||||
static bool __termination = false;
|
||||
#endif
|
||||
|
||||
struct __Module
|
||||
{
|
||||
__Module();
|
||||
@ -494,6 +498,38 @@ PlatformInfo::PlatformInfo()
|
||||
// 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 ////////////////////////
|
||||
//This is a global singleton class used to represent a OpenCL context.
|
||||
class ContextImpl : public Context
|
||||
@ -501,12 +537,11 @@ class ContextImpl : public Context
|
||||
public:
|
||||
const cl_device_id clDeviceID;
|
||||
cl_context clContext;
|
||||
cl_command_queue clCmdQueue;
|
||||
const DeviceInfo& deviceInfo;
|
||||
|
||||
protected:
|
||||
ContextImpl(const DeviceInfo& deviceInfo, cl_device_id clDeviceID)
|
||||
: clDeviceID(clDeviceID), clContext(NULL), clCmdQueue(NULL), deviceInfo(deviceInfo)
|
||||
: clDeviceID(clDeviceID), clContext(NULL), deviceInfo(deviceInfo)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
@ -581,7 +616,13 @@ const void* Context::getOpenCLContextPtr() 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
|
||||
@ -607,10 +648,6 @@ bool ContextImpl::supportsFeature(FEATURE_TYPE featureType) const
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
static bool __termination = false;
|
||||
#endif
|
||||
|
||||
ContextImpl::~ContextImpl()
|
||||
{
|
||||
#ifdef WIN32
|
||||
@ -619,17 +656,11 @@ ContextImpl::~ContextImpl()
|
||||
if (!__termination)
|
||||
#endif
|
||||
{
|
||||
if(clCmdQueue)
|
||||
{
|
||||
openCLSafeCall(clReleaseCommandQueue(clCmdQueue)); // some cleanup problems are here
|
||||
}
|
||||
|
||||
if(clContext)
|
||||
{
|
||||
openCLSafeCall(clReleaseContext(clContext));
|
||||
}
|
||||
}
|
||||
clCmdQueue = 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 clContext = clCreateContext(cps, 1, &infoImpl.device_id, NULL, NULL, &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);
|
||||
ctx->clCmdQueue = clCmdQueue;
|
||||
ctx->clContext = clContext;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!__initialized)
|
||||
|
Loading…
Reference in New Issue
Block a user