Using ICD loader in open-source project

Hello,
I’m working on an open-source project that will use OpenCL. My goal would be that the user can just download the .exe and the opencl.dll will be supplied by the graphics driver. Or they can compile the application from source.
But that requires opencl.lib and CL header files. These files are atleast according to my understanding distributed by vendor SDKs.
Are those SDKs really needed? Because CL header files can be downloaded from Khronos and I have found a thing called ICD loader, also from Khronos, that generates both .lib and .dll files.

Can I use this library instead of a SDK? I mean I got it working, but should I do it this way? My project would link against the .lib library from ICD but runtime would use .dll supplied by graphics driver?
And what files can I distribute exactly, because licenses seem prety relaxed expect in ICD loader’s there is a following paragraph that I do not fully understand:

If the binary is used as part of an OpenCL™ implementation, whether binary
is distributed together with or separately to that implementation, then
recipient must become an OpenCL Adopter and follow the published OpenCL
conformance process for that implementation, details at:
url that I cannot post on this forum;

What does the term implementation mean? I do not mean to ‘implement’ OpenCL, merely use it. Is this relevant only for vendors that want to implement better versions of .lib/.dll library for their SDKs? Because I do not plan on to distributing .lib nor .dll files. My project would contain my source files, CL headers, ICD loader sources and CMake files to build it together into working application.
I do not plan on using any vendor-specific functions, just standard OpenCL 1.2, so is driver’s .dll superset/compatible with ICD .lib? I would also like that my project be multi-platform which is another reason I do not want any SDKs. And last question, is there version of ICD that targets OpenCL 1.2? Because I had to supply CL 2.2 headers for it to compile and I don’t plan on using those new functions. Or does it matter?

Could somebody please help me answer my questions?

OpenCL.lib is the same for every OpenCL vendor. It is a simple library that searches for actual OpenCL dlls. You don’t need to provide anything but your app binary. Also, OpenCL 2.2 is backwards compatible with older versions, so it’s fine.

Thank you. And about that license, that paragraph is targeted to vendors? So I can redistribute ICD source code?(With the licence file of course)

I’m not too keen on legal aspects, but probably yes. Is this code the same for Windows, Linux and MacOS though?

John.W

You can use:
LoadLibrary(“Opencl32.dll”)/GetProcAdress for Windows, dlopen/dlsym for Android/MacOSX/Linux/BSD Unix

Example code:


// load OpenCL dynamic library
#ifdef _WIN32
	openglDLL = ::LoadLibrary("OpenCL.dll");
#elif !defined(__MACOSX__)
	openglDLL = ::dlopen("libOpenCL.so", RTLD_LAZY);
#else
	openglDLL = ::dlopen("/System/Library/Frameworks/OpenCL.FrameWork/OpenCL", RTLD_NOW);
#endif

// get OpenCL function pointer directly
void* GetOpenCLProcAdress(const char* funcName)
{
#ifdef _WIN32
	void* ptr = ::GetProcAddress(reinterpret_cast<::HMODULE>(openglDLL), funcName);
#else
	void* ptr = ::dlsym(openglDLL, funcName);
#endif
	if (!ptr) {
		Console::GetSinglenton().AddMessage(Console::INFO_MESSAGE, "OpenCL: can't find %s 
", funcName);
	}
	return ptr;
}

// get OpenCL extension function pointer
void* GetCLProcAdress(const char* funcName, cl_platform_id platform)
{
	assert(openglDLL && "NULL Ponter");
#ifndef __ANDROID__
	void* ptr = NULL;
	if (clGetExtensionFunctionAddressForPlatform) {
		ptr = clGetExtensionFunctionAddressForPlatform(platform, funcName);
	}
	if (!ptr) {
		ptr = clGetExtensionFunctionAddress ? clGetExtensionFunctionAddress(funcName) : NULL;
	}
	if (!ptr) {
		ptr = GetOpenCLProcAdress(funcName);
	}
#else
	void* ptr = GetOpenCLProcAdress(funcName);
#endif
	return ptr;
}

void InitFunctionPointers()
{
	clGetPlatformIDs = GetOpenCLProcAdress<clGetPlatformIDs_fn>("clGetPlatformIDs");
	clGetDeviceIDs = GetOpenCLProcAdress<clGetDeviceIDs_fn>("clGetDeviceIDs");
	clGetDeviceInfo = GetOpenCLProcAdress<clGetDeviceInfo_fn>("clGetDeviceInfo");
	clGetPlatformInfo = GetOpenCLProcAdress<clGetPlatformInfo_fn>("clGetPlatformInfo");
	clCreateContext = GetOpenCLProcAdress<clCreateContext_fn>("clCreateContext");
	clCreateBuffer = GetOpenCLProcAdress<clCreateBuffer_fn>("clCreateBuffer");
	clCreateCommandQueue = GetOpenCLProcAdress<clCreateCommandQueue_fn>("clCreateCommandQueue");
	clCreateCommandQueueWithProperties = GetOpenCLProcAdress<clCreateCommandQueueWithProperties_fn>("clCreateCommandQueueWithProperties");
	clCreateProgramWithSource = GetOpenCLProcAdress<clCreateProgramWithSource_fn>("clCreateProgramWithSource");
	clBuildProgram = GetOpenCLProcAdress<clBuildProgram_fn>("clBuildProgram");
	clGetProgramBuildInfo = GetOpenCLProcAdress<clGetProgramBuildInfo_fn>("clGetProgramBuildInfo");
	clGetProgramInfo = GetOpenCLProcAdress<clGetProgramInfo_fn>("clGetProgramInfo");
	clGetExtensionFunctionAddressForPlatform = GetOpenCLProcAdress<clGetExtensionFunctionAddressForPlatform_fn>("clGetExtensionFunctionAddressForPlatform");
	clGetExtensionFunctionAddress = GetOpenCLProcAdress<clGetExtensionFunctionAddress_fn>("clGetExtensionFunctionAddress");
	// deprecated since OpenCL 1.2
	clCreateProgramWithBinary = GetOpenCLProcAdress<clCreateProgramWithBinary_fn>("clCreateProgramWithBinary");
	clCreateKernel = GetOpenCLProcAdress<clCreateKernel_fn>("clCreateKernel");
	clSetKernelArg = GetOpenCLProcAdress<clSetKernelArg_fn>("clSetKernelArg");
	clGetKernelWorkGroupInfo = GetOpenCLProcAdress<clGetKernelWorkGroupInfo_fn>("clGetKernelWorkGroupInfo");
	clFinish = GetOpenCLProcAdress<clFinish_fn>("clFinish");
	clFlush = GetOpenCLProcAdress<clFlush_fn>("clFlush");
	clReleaseCommandQueue = GetOpenCLProcAdress<clReleaseCommandQueue_fn>("clReleaseCommandQueue");
	clWaitForEvents = GetOpenCLProcAdress<clWaitForEvents_fn>("clWaitForEvents");
	clReleaseEvent = GetOpenCLProcAdress<clReleaseEvent_fn>("clReleaseEvent");
	clEnqueueNDRangeKernel = GetOpenCLProcAdress<clEnqueueNDRangeKernel_fn>("clEnqueueNDRangeKernel");
	clEnqueueReadBuffer = GetOpenCLProcAdress<clEnqueueReadBuffer_fn>("clEnqueueReadBuffer");
	clEnqueueWriteBuffer = GetOpenCLProcAdress<clEnqueueWriteBuffer_fn>("clEnqueueWriteBuffer");
	clReleaseMemObject = GetOpenCLProcAdress<clReleaseMemObject_fn>("clReleaseMemObject");
	clReleaseProgram = GetOpenCLProcAdress<clReleaseProgram_fn>("clReleaseProgram");
	clReleaseKernel = GetOpenCLProcAdress<clReleaseKernel_fn>("clReleaseKernel");
	clReleaseContext = GetOpenCLProcAdress<clReleaseContext_fn>("clReleaseContext");
	clReleaseDevice = GetOpenCLProcAdress<clReleaseDevice_fn>("clReleaseDevice");
}

It is working very well on Mac OS X/Android/Windows :slight_smile:

I think no, because for Windows use Win32 API, for Linux/MacOSX - POSIX