Skip to content

Commit 2129c72

Browse files
committed
core(OpenCL): thread-local OpenCL execution context
1 parent 0428dce commit 2129c72

File tree

12 files changed

+1709
-242
lines changed

12 files changed

+1709
-242
lines changed

modules/core/include/opencv2/core/mat.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ struct CV_EXPORTS UMatData
565565
int allocatorFlags_;
566566
int mapcount;
567567
UMatData* originalUMatData;
568+
std::shared_ptr<void> allocatorContext;
568569
};
569570
CV_ENUM_FLAGS(UMatData::MemoryFlag)
570571

modules/core/include/opencv2/core/ocl.hpp

Lines changed: 148 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,15 @@ class CV_EXPORTS_W_SIMPLE Device
229229

230230
CV_WRAP static const Device& getDefault();
231231

232-
protected:
232+
/**
233+
* @param d OpenCL handle (cl_device_id). clRetainDevice() is called on success.
234+
*/
235+
static Device fromHandle(void* d);
236+
233237
struct Impl;
238+
inline Impl* getImpl() const { return (Impl*)p; }
239+
inline bool empty() const { return !p; }
240+
protected:
234241
Impl* p;
235242
};
236243

@@ -239,33 +246,55 @@ class CV_EXPORTS Context
239246
{
240247
public:
241248
Context();
242-
explicit Context(int dtype);
249+
explicit Context(int dtype); //!< @deprecated
243250
~Context();
244251
Context(const Context& c);
245-
Context& operator = (const Context& c);
252+
Context& operator= (const Context& c);
246253

254+
/** @deprecated */
247255
bool create();
256+
/** @deprecated */
248257
bool create(int dtype);
258+
249259
size_t ndevices() const;
250-
const Device& device(size_t idx) const;
260+
Device& device(size_t idx) const;
251261
Program getProg(const ProgramSource& prog,
252262
const String& buildopt, String& errmsg);
253263
void unloadProg(Program& prog);
254264

265+
266+
/** Get thread-local OpenCL context (initialize if necessary) */
267+
#if 0 // OpenCV 5.0
268+
static Context& getDefault();
269+
#else
255270
static Context& getDefault(bool initialize = true);
271+
#endif
272+
273+
/** @returns cl_context value */
256274
void* ptr() const;
257275

258-
friend void initializeContextFromHandle(Context& ctx, void* platform, void* context, void* device);
259276

260277
bool useSVM() const;
261278
void setUseSVM(bool enabled);
262279

280+
/**
281+
* @param context OpenCL handle (cl_context). clRetainContext() is called on success
282+
*/
283+
static Context fromHandle(void* context);
284+
static Context fromDevice(const ocl::Device& device);
285+
static Context create(const std::string& configuration);
286+
287+
void release();
288+
263289
struct Impl;
264290
inline Impl* getImpl() const { return (Impl*)p; }
291+
inline bool empty() const { return !p; }
292+
// TODO OpenCV 5.0
265293
//protected:
266294
Impl* p;
267295
};
268296

297+
/** @deprecated */
269298
class CV_EXPORTS Platform
270299
{
271300
public:
@@ -275,11 +304,14 @@ class CV_EXPORTS Platform
275304
Platform& operator = (const Platform& p);
276305

277306
void* ptr() const;
307+
308+
/** @deprecated */
278309
static Platform& getDefault();
279310

280-
friend void initializeContextFromHandle(Context& ctx, void* platform, void* context, void* device);
281-
protected:
282311
struct Impl;
312+
inline Impl* getImpl() const { return (Impl*)p; }
313+
inline bool empty() const { return !p; }
314+
protected:
283315
Impl* p;
284316
};
285317

@@ -319,6 +351,7 @@ CV_EXPORTS void convertFromBuffer(void* cl_mem_buffer, size_t step, int rows, in
319351
CV_EXPORTS void convertFromImage(void* cl_mem_image, UMat& dst);
320352

321353
// TODO Move to internal header
354+
/// @deprecated
322355
void initializeContextFromHandle(Context& ctx, void* platform, void* context, void* device);
323356

324357
class CV_EXPORTS Queue
@@ -340,6 +373,7 @@ class CV_EXPORTS Queue
340373

341374
struct Impl; friend struct Impl;
342375
inline Impl* getImpl() const { return p; }
376+
inline bool empty() const { return !p; }
343377
protected:
344378
Impl* p;
345379
};
@@ -490,6 +524,7 @@ class CV_EXPORTS Program
490524

491525
struct Impl; friend struct Impl;
492526
inline Impl* getImpl() const { return (Impl*)p; }
527+
inline bool empty() const { return !p; }
493528
protected:
494529
Impl* p;
495530
public:
@@ -571,6 +606,7 @@ class CV_EXPORTS ProgramSource
571606

572607
struct Impl; friend struct Impl;
573608
inline Impl* getImpl() const { return (Impl*)p; }
609+
inline bool empty() const { return !p; }
574610
protected:
575611
Impl* p;
576612
};
@@ -579,6 +615,9 @@ class CV_EXPORTS PlatformInfo
579615
{
580616
public:
581617
PlatformInfo();
618+
/**
619+
* @param id pointer cl_platform_id (cl_platform_id*)
620+
*/
582621
explicit PlatformInfo(void* id);
583622
~PlatformInfo();
584623

@@ -591,8 +630,9 @@ class CV_EXPORTS PlatformInfo
591630
int deviceNumber() const;
592631
void getDevice(Device& device, int d) const;
593632

594-
protected:
595633
struct Impl;
634+
bool empty() const { return !p; }
635+
protected:
596636
Impl* p;
597637
};
598638

@@ -689,6 +729,106 @@ class CV_EXPORTS Timer
689729
CV_EXPORTS MatAllocator* getOpenCLAllocator();
690730

691731

732+
class CV_EXPORTS_W OpenCLExecutionContext
733+
{
734+
public:
735+
OpenCLExecutionContext() = default;
736+
~OpenCLExecutionContext() = default;
737+
738+
OpenCLExecutionContext(const OpenCLExecutionContext& other) = default;
739+
OpenCLExecutionContext(OpenCLExecutionContext&& other) = default;
740+
741+
OpenCLExecutionContext& operator=(const OpenCLExecutionContext& other) = default;
742+
OpenCLExecutionContext& operator=(OpenCLExecutionContext&& other) = default;
743+
744+
/** Get associated ocl::Context */
745+
Context& getContext() const;
746+
/** Get associated ocl::Device */
747+
Device& getDevice() const;
748+
/** Get associated ocl::Queue */
749+
Queue& getQueue() const;
750+
751+
bool useOpenCL() const;
752+
void setUseOpenCL(bool flag);
753+
754+
/** Get OpenCL execution context of current thread.
755+
*
756+
* Initialize OpenCL execution context if it is empty
757+
* - create new
758+
* - reuse context of the main thread (threadID = 0)
759+
*/
760+
static OpenCLExecutionContext& getCurrent();
761+
762+
/** Get OpenCL execution context of current thread (can be empty) */
763+
static OpenCLExecutionContext& getCurrentRef();
764+
765+
/** Bind this OpenCL execution context to current thread.
766+
*
767+
* Context can't be empty.
768+
*
769+
* @note clFinish is not called for queue of previous execution context
770+
*/
771+
void bind() const;
772+
773+
/** Creates new execution context with same OpenCV context and device
774+
*
775+
* @param q OpenCL queue
776+
*/
777+
OpenCLExecutionContext cloneWithNewQueue(const ocl::Queue& q) const;
778+
/** @overload */
779+
OpenCLExecutionContext cloneWithNewQueue() const;
780+
781+
/** @brief Creates OpenCL execution context
782+
* OpenCV will check if available OpenCL platform has platformName name, then assign context to
783+
* OpenCV and call `clRetainContext` function. The deviceID device will be used as target device and
784+
* new command queue will be created.
785+
*
786+
* @note Lifetime of passed handles is transferred to OpenCV wrappers on success
787+
*
788+
* @param platformName name of OpenCL platform to attach, this string is used to check if platform is available to OpenCV at runtime
789+
* @param platformID ID of platform attached context was created for (cl_platform_id)
790+
* @param context OpenCL context to be attached to OpenCV (cl_context)
791+
* @param deviceID OpenCL device (cl_device_id)
792+
*/
793+
static OpenCLExecutionContext create(const std::string& platformName, void* platformID, void* context, void* deviceID);
794+
795+
/** @brief Creates OpenCL execution context
796+
*
797+
* @param context non-empty OpenCL context
798+
* @param device non-empty OpenCL device (must be a part of context)
799+
* @param queue non-empty OpenCL queue for provided context and device
800+
*/
801+
static OpenCLExecutionContext create(const Context& context, const Device& device, const ocl::Queue& queue);
802+
/** @overload */
803+
static OpenCLExecutionContext create(const Context& context, const Device& device);
804+
805+
struct Impl;
806+
inline bool empty() const { return !p; }
807+
void release();
808+
protected:
809+
std::shared_ptr<Impl> p;
810+
};
811+
812+
class OpenCLExecutionContextScope
813+
{
814+
OpenCLExecutionContext ctx_;
815+
public:
816+
inline OpenCLExecutionContextScope(const OpenCLExecutionContext& ctx)
817+
{
818+
CV_Assert(!ctx.empty());
819+
ctx_ = OpenCLExecutionContext::getCurrentRef();
820+
ctx.bind();
821+
}
822+
823+
inline ~OpenCLExecutionContextScope()
824+
{
825+
if (!ctx_.empty())
826+
{
827+
ctx_.bind();
828+
}
829+
}
830+
};
831+
692832
#ifdef __OPENCV_BUILD
693833
namespace internal {
694834

modules/core/src/directx.cpp

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,22 @@ Context& initializeContextFromD3D11Device(ID3D11Device* pD3D11Device)
458458
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop");
459459
}
460460

461-
Context& ctx = Context::getDefault(false);
462-
initializeContextFromHandle(ctx, platforms[found], context, device);
463-
return ctx;
461+
cl_platform_id platform = platforms[found];
462+
std::string platformName = PlatformInfo(platform).name();
463+
464+
OpenCLExecutionContext clExecCtx;
465+
try
466+
{
467+
clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device);
468+
}
469+
catch (...)
470+
{
471+
clReleaseDevice(device);
472+
clReleaseContext(context);
473+
throw;
474+
}
475+
clExecCtx.bind();
476+
return const_cast<Context&>(clExecCtx.getContext());
464477
#endif
465478
}
466479

@@ -565,10 +578,22 @@ Context& initializeContextFromD3D10Device(ID3D10Device* pD3D10Device)
565578
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop");
566579
}
567580

581+
cl_platform_id platform = platforms[found];
582+
std::string platformName = PlatformInfo(platform).name();
568583

569-
Context& ctx = Context::getDefault(false);
570-
initializeContextFromHandle(ctx, platforms[found], context, device);
571-
return ctx;
584+
OpenCLExecutionContext clExecCtx;
585+
try
586+
{
587+
clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device);
588+
}
589+
catch (...)
590+
{
591+
clReleaseDevice(device);
592+
clReleaseContext(context);
593+
throw;
594+
}
595+
clExecCtx.bind();
596+
return const_cast<Context&>(clExecCtx.getContext());
572597
#endif
573598
}
574599

@@ -675,10 +700,23 @@ Context& initializeContextFromDirect3DDevice9Ex(IDirect3DDevice9Ex* pDirect3DDev
675700
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop");
676701
}
677702

678-
Context& ctx = Context::getDefault(false);
679-
initializeContextFromHandle(ctx, platforms[found], context, device);
703+
cl_platform_id platform = platforms[found];
704+
std::string platformName = PlatformInfo(platform).name();
705+
706+
OpenCLExecutionContext clExecCtx;
707+
try
708+
{
709+
clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device);
710+
}
711+
catch (...)
712+
{
713+
clReleaseDevice(device);
714+
clReleaseContext(context);
715+
throw;
716+
}
717+
clExecCtx.bind();
680718
g_isDirect3DDevice9Ex = true;
681-
return ctx;
719+
return const_cast<Context&>(clExecCtx.getContext());
682720
#endif
683721
}
684722

@@ -785,10 +823,23 @@ Context& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDirect3DDevice9
785823
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop");
786824
}
787825

788-
Context& ctx = Context::getDefault(false);
789-
initializeContextFromHandle(ctx, platforms[found], context, device);
826+
cl_platform_id platform = platforms[found];
827+
std::string platformName = PlatformInfo(platform).name();
828+
829+
OpenCLExecutionContext clExecCtx;
830+
try
831+
{
832+
clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device);
833+
}
834+
catch (...)
835+
{
836+
clReleaseDevice(device);
837+
clReleaseContext(context);
838+
throw;
839+
}
840+
clExecCtx.bind();
790841
g_isDirect3DDevice9Ex = false;
791-
return ctx;
842+
return const_cast<Context&>(clExecCtx.getContext());
792843
#endif
793844
}
794845

0 commit comments

Comments
 (0)