master ohmu/fastfetch-openbsd / src / detection / opencl / opencl.c
ohmu  ·  2026-10-15
  1#include "detection/opencl/opencl.h"
  2#include "detection/gpu/gpu.h"
  3
  4#if !defined(FF_HAVE_OPENCL) && defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_15)
  5    #define FF_HAVE_OPENCL 1
  6#endif
  7
  8#ifdef FF_HAVE_OPENCL
  9
 10    #include "common/library.h"
 11    #include "common/parsing.h"
 12    #include "common/strutil.h"
 13    #include <string.h>
 14
 15    #define CL_TARGET_OPENCL_VERSION 110
 16    #ifndef __APPLE__
 17        #include <CL/cl.h>
 18        #include <CL/cl_ext.h>
 19    #else
 20        #include <OpenCL/cl.h>
 21        #include <OpenCL/cl_ext.h>
 22    #endif
 23
 24typedef struct OpenCLData {
 25    FF_LIBRARY_SYMBOL(clGetPlatformIDs)
 26    FF_LIBRARY_SYMBOL(clGetPlatformInfo)
 27    FF_LIBRARY_SYMBOL(clGetDeviceInfo)
 28    FF_LIBRARY_SYMBOL(clGetDeviceIDs)
 29} OpenCLData;
 30
 31static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result) {
 32    cl_platform_id platforms[32];
 33    cl_uint numPlatforms = 0;
 34    cl_int ret = data->ffclGetPlatformIDs(ARRAY_SIZE(platforms), platforms, &numPlatforms);
 35    if (ret != CL_SUCCESS) {
 36        switch (ret) {
 37    #ifdef CL_PLATFORM_NOT_FOUND_KHR // not available on macOS
 38            case CL_PLATFORM_NOT_FOUND_KHR:
 39                return "clGetPlatformIDs() failed: CL_PLATFORM_NOT_FOUND_KHR";
 40    #endif
 41            case CL_INVALID_VALUE:
 42                return "clGetPlatformIDs() failed: CL_INVALID_VALUE";
 43            case CL_OUT_OF_HOST_MEMORY:
 44                return "clGetPlatformIDs() failed: CL_OUT_OF_HOST_MEMORY";
 45            default:
 46                return "clGetPlatformIDs() failed: unknown error";
 47        }
 48    }
 49
 50    if (numPlatforms == 0) {
 51        return "clGetPlatformIDs returned 0 platforms";
 52    }
 53
 54    char buffer[1024];
 55    for (cl_uint iplat = 0; iplat < numPlatforms; ++iplat) {
 56        if (data->ffclGetPlatformInfo(platforms[iplat], CL_PLATFORM_VERSION, sizeof(buffer), buffer, nullptr) != CL_SUCCESS) {
 57            return "clGetPlatformInfo() failed";
 58        }
 59
 60        // Use the newest supported OpenCL version
 61        if (ffStrbufCompS(&result->version, buffer) < 0) {
 62            const char* versionPretty = buffer;
 63            if (ffStrStartsWithIgnCase(buffer, "OpenCL ")) {
 64                versionPretty = buffer + strlen("OpenCL ");
 65            }
 66            ffStrbufSetS(&result->version, versionPretty);
 67            ffStrbufTrim(&result->version, ' ');
 68
 69            if (data->ffclGetPlatformInfo(platforms[iplat], CL_PLATFORM_NAME, sizeof(buffer), buffer, nullptr) == CL_SUCCESS) {
 70                ffStrbufSetS(&result->name, buffer);
 71            }
 72
 73            if (data->ffclGetPlatformInfo(platforms[iplat], CL_PLATFORM_VENDOR, sizeof(buffer), buffer, nullptr) == CL_SUCCESS) {
 74                ffStrbufSetS(&result->vendor, buffer);
 75            }
 76        }
 77
 78        cl_device_id deviceIDs[32];
 79        cl_uint numDevices = (cl_uint) ARRAY_SIZE(deviceIDs);
 80        if (data->ffclGetDeviceIDs(platforms[iplat], CL_DEVICE_TYPE_GPU, numDevices, deviceIDs, &numDevices) != CL_SUCCESS) {
 81            continue;
 82        }
 83
 84        for (cl_uint idev = 0; idev < numDevices; ++idev) {
 85            cl_device_id deviceID = deviceIDs[idev];
 86            if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_NAME, sizeof(buffer), buffer, nullptr) != CL_SUCCESS) {
 87                continue;
 88            }
 89
 90            FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, result->gpus);
 91            ffStrbufInitS(&gpu->name, buffer);
 92            ffStrbufInit(&gpu->vendor);
 93            ffStrbufInit(&gpu->driver);
 94            ffStrbufInit(&gpu->platformApi);
 95            ffStrbufInit(&gpu->memoryType);
 96            gpu->index = FF_GPU_INDEX_UNSET;
 97            gpu->temperature = FF_GPU_TEMP_UNSET;
 98            gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
 99            gpu->type = FF_GPU_TYPE_UNKNOWN;
100            gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
101            gpu->deviceId = (size_t) deviceID;
102            gpu->frequency = FF_GPU_FREQUENCY_UNSET;
103            gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
104            gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
105
106            if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VERSION, sizeof(buffer), buffer, nullptr) == CL_SUCCESS) {
107                ffStrbufSetS(&gpu->platformApi, buffer);
108                ffStrbufTrimRight(&gpu->platformApi, ' ');
109            } else {
110                ffStrbufSetStatic(&gpu->platformApi, "OpenCL");
111            }
112
113            {
114                cl_uint vendorId;
115                if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VENDOR_ID, sizeof(vendorId), &vendorId, nullptr) == CL_SUCCESS) {
116                    ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
117                }
118                if (gpu->vendor.length == 0 && data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VENDOR, sizeof(buffer), buffer, nullptr) == CL_SUCCESS) {
119                    ffStrbufSetS(&gpu->vendor, buffer);
120                }
121            }
122
123            if (data->ffclGetDeviceInfo(deviceID, CL_DRIVER_VERSION, sizeof(buffer), buffer, nullptr) == CL_SUCCESS) {
124                const char* versionPretty = strchr(buffer, ' ');
125                if (versionPretty && *versionPretty) {
126                    ffStrbufSetS(&gpu->driver, versionPretty + 1);
127                } else {
128                    ffStrbufSetS(&gpu->driver, buffer);
129                }
130            }
131
132            {
133                cl_uint value;
134                if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(value), &value, nullptr) == CL_SUCCESS) {
135                    gpu->coreCount = (int32_t) value;
136                }
137            }
138
139            {
140                cl_uint value;
141                if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(value), &value, nullptr) == CL_SUCCESS) {
142                    gpu->frequency = value;
143                }
144            }
145
146            {
147                cl_bool value;
148                if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_HOST_UNIFIED_MEMORY, sizeof(value), &value, nullptr) == CL_SUCCESS) {
149                    gpu->type = value ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
150
151                    cl_ulong memSize;
152                    if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(memSize), &memSize, nullptr) == CL_SUCCESS) {
153                        if (gpu->type == FF_GPU_TYPE_INTEGRATED) {
154                            gpu->shared.total = memSize;
155                        } else {
156                            gpu->dedicated.total = memSize;
157                        }
158                    }
159                }
160            }
161        }
162    }
163
164    return nullptr;
165}
166
167static const char* detectOpenCL(FFOpenCLResult* result) {
168    OpenCLData data;
169
170    #ifndef __APPLE__
171
172    FF_LIBRARY_LOAD_MESSAGE(opencl,
173        #ifdef _WIN32
174        "OpenCL" FF_LIBRARY_EXTENSION,
175        -1,
176        #endif
177        "libOpenCL" FF_LIBRARY_EXTENSION,
178        1);
179    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetPlatformIDs);
180    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetPlatformInfo);
181    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetDeviceIDs);
182    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetDeviceInfo);
183
184    return openCLHandleData(&data, result);
185
186    #else
187
188    data.ffclGetPlatformIDs = clGetPlatformIDs;
189    data.ffclGetPlatformInfo = clGetPlatformInfo;
190    data.ffclGetDeviceIDs = clGetDeviceIDs;
191    data.ffclGetDeviceInfo = clGetDeviceInfo;
192
193    return openCLHandleData(&data, result);
194
195    #endif
196}
197
198#endif // defined(FF_HAVE_OPENCL)
199
200FFOpenCLResult* ffDetectOpenCL(void) {
201    static FFOpenCLResult result;
202    static bool initialized;
203
204    if (!initialized) {
205        initialized = true;
206        ffStrbufInit(&result.version);
207        ffStrbufInit(&result.name);
208        ffStrbufInit(&result.vendor);
209        ffListInit(&result.gpus);
210
211#ifdef FF_HAVE_OPENCL
212        result.error = detectOpenCL(&result);
213#else
214        result.error = "fastfetch was compiled without OpenCL support";
215#endif
216    }
217
218    return &result;
219}