igneum/proto-opencl/cl_dynamic.h
igneum-labs 079ed76a2d OpenCL worker: generic --pack serve mode and OpenCL.dll loaded at run time (one-click AMD worker)
host.c --serve --pack <dir> serves a pack read at run time (packfile.h), whatever pack the exe was built against: the
first pair is built and self-tested like a prepared one (pairBuffers, pairSelfTest), prepared pairs are self-tested
too, the ready line says path prebuilt-generic. cl_dynamic.h (IGNEUM_CL_DYNAMIC) opens OpenCL.dll with LoadLibrary and
fills a function pointer per entry point, so the mingw build links no import library. test-generic.sh checks the mode
through Apple OpenCL with the packs of the CUDA emulation test: PASS (192 found, prepare and swap, 15 sampled hashes
equal igneum-pow hash-bound), built against a different placeholder pack than it served.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 09:55:05 +00:00

78 lines
3.7 KiB
C

/* cl_dynamic.h: OpenCL.dll loaded at run time (Windows). 4 October 2026.
*
* The one-click AMD worker (host.c cross-compiled with mingw, build-windows.sh) links no OpenCL import library:
* every cl* entry point host.c calls is a function pointer filled from OpenCL.dll with LoadLibrary/GetProcAddress.
* OpenCL.dll is the Khronos ICD loader that the AMD Adrenalin (and NVIDIA, Intel) driver installs in System32, so
* nothing but the driver is needed on the PC. Included by host.c after <CL/cl.h> when IGNEUM_CL_DYNAMIC is defined;
* the macros below then rename the calls in the rest of the file. The Mac and Linux builds link the library as before.
*/
#ifndef IGNEUM_CL_DYNAMIC_H
#define IGNEUM_CL_DYNAMIC_H
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <stdio.h>
#define IG_CL_FUNCS(X) \
X(clGetPlatformIDs) X(clGetPlatformInfo) X(clGetDeviceIDs) X(clGetDeviceInfo) X(clCreateContext) \
X(clCreateCommandQueue) X(clCreateProgramWithSource) X(clBuildProgram) X(clGetProgramBuildInfo) X(clCreateKernel) \
X(clSetKernelArg) X(clEnqueueNDRangeKernel) X(clEnqueueReadBuffer) X(clEnqueueWriteBuffer) X(clCreateBuffer) \
X(clReleaseMemObject) X(clReleaseKernel) X(clReleaseProgram) X(clReleaseCommandQueue) X(clReleaseContext) \
X(clFinish) X(clWaitForEvents) X(clReleaseEvent) X(clGetEventProfilingInfo) X(clGetKernelWorkGroupInfo) \
X(clGetExtensionFunctionAddressForPlatform)
/* One pointer per entry point, typed from the header's declaration (so a signature drift is a compile error). */
#define IG_CL_DECL(f) static __typeof__(f)* ig_##f = NULL;
IG_CL_FUNCS(IG_CL_DECL)
#undef IG_CL_DECL
static char ig_cl_error[512];
/* Returns 1 when OpenCL.dll and every entry point are there; else 0 with ig_cl_error set. */
static int ig_cl_load(void) {
#ifdef _WIN32
HMODULE h = LoadLibraryA("OpenCL.dll");
if (!h) {
snprintf(ig_cl_error, sizeof(ig_cl_error), "OpenCL.dll is not installed (the GPU driver provides it: AMD Adrenalin, or the NVIDIA or Intel driver); nothing else is needed");
return 0;
}
#define IG_CL_LOAD(f) ig_##f = (__typeof__(f)*)(void*)GetProcAddress(h, #f); if (!ig_##f) { snprintf(ig_cl_error, sizeof(ig_cl_error), "OpenCL.dll lacks %s", #f); return 0; }
IG_CL_FUNCS(IG_CL_LOAD)
#undef IG_CL_LOAD
return 1;
#else
snprintf(ig_cl_error, sizeof(ig_cl_error), "IGNEUM_CL_DYNAMIC is for the Windows build");
return 0;
#endif
}
/* From here on, host.c's calls go through the pointers. */
#define IG_CL_RENAME(f)
#define clGetPlatformIDs ig_clGetPlatformIDs
#define clGetPlatformInfo ig_clGetPlatformInfo
#define clGetDeviceIDs ig_clGetDeviceIDs
#define clGetDeviceInfo ig_clGetDeviceInfo
#define clCreateContext ig_clCreateContext
#define clCreateCommandQueue ig_clCreateCommandQueue
#define clCreateProgramWithSource ig_clCreateProgramWithSource
#define clBuildProgram ig_clBuildProgram
#define clGetProgramBuildInfo ig_clGetProgramBuildInfo
#define clCreateKernel ig_clCreateKernel
#define clSetKernelArg ig_clSetKernelArg
#define clEnqueueNDRangeKernel ig_clEnqueueNDRangeKernel
#define clEnqueueReadBuffer ig_clEnqueueReadBuffer
#define clEnqueueWriteBuffer ig_clEnqueueWriteBuffer
#define clCreateBuffer ig_clCreateBuffer
#define clReleaseMemObject ig_clReleaseMemObject
#define clReleaseKernel ig_clReleaseKernel
#define clReleaseProgram ig_clReleaseProgram
#define clReleaseCommandQueue ig_clReleaseCommandQueue
#define clReleaseContext ig_clReleaseContext
#define clFinish ig_clFinish
#define clWaitForEvents ig_clWaitForEvents
#define clReleaseEvent ig_clReleaseEvent
#define clGetEventProfilingInfo ig_clGetEventProfilingInfo
#define clGetKernelWorkGroupInfo ig_clGetKernelWorkGroupInfo
#define clGetExtensionFunctionAddressForPlatform ig_clGetExtensionFunctionAddressForPlatform
#endif