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}